From: kennytm Date: Fri, 26 Oct 2018 10:25:10 +0000 (+0800) Subject: Rollup merge of #55343 - Keruspe:remap-debuginfo-release, r=alexcrichton X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=2e1e8d29130fe5db2e8beceb7981a0197aaff772;hp=bbc3cd43784b69beda25dc0f002514d656d853a2;p=rust.git Rollup merge of #55343 - Keruspe:remap-debuginfo-release, r=alexcrichton rustbuild: fix remap-debuginfo when building a release Fallback to the release number as we can't get the git commit sha as we're not in a git repository. Fixes #55341 --- diff --git a/RELEASES.md b/RELEASES.md index 7ae7dc9935b..15ab97e26fc 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -4,34 +4,31 @@ Version 1.30.0 (2018-10-25) Language -------- - [Procedural macros are now available.][52081] These kinds of macros allow for - more powerful code generation, there is a [new chapter available][proc-macros] - in Rust Programming Language book that goes further in depth. + more powerful code generation. There is a [new chapter available][proc-macros] + in the Rust Programming Language book that goes further in depth. - [You can now use keywords as identifiers using the raw identifiers - syntax (`r#`).][53236] e.g. `let r#for = true;` + syntax (`r#`),][53236] e.g. `let r#for = true;` - [Using anonymous parameters in traits is now deprecated with a warning and will be a hard error in the 2018 edition.][53272] - [You can now use `crate` in paths.][54404] This allows you to refer to the - crate root in the path. e.g. `use crate::foo;` refers to `foo` in `src/lib.rs`. -- [Using a external crate now no longer requires being prefixed with `::`.][54404] - e.g. previously using a external crate in a module without a use statement - required `let json = ::serde_json::from_str(foo);` can now be written + crate root in the path, e.g. `use crate::foo;` refers to `foo` in `src/lib.rs`. +- [Using a external crate no longer requires being prefixed with `::`.][54404] + Previously, using a external crate in a module without a use statement + required `let json = ::serde_json::from_str(foo);` but can now be written as `let json = serde_json::from_str(foo);`. - [You can now apply the `#[used]` attribute to static items to prevent the - compiler from optimising them away even if they appear to be unused.][51363] + compiler from optimising them away, even if they appear to be unused,][51363] e.g. `#[used] static FOO: u32 = 1;` - [You can now import and reexport macros from other crates with the `use` syntax.][50911] Macros exported with `#[macro_export]` are now placed into the root module of the crate. If your macro relies on calling other local - macros it is recommended to export with the - `#[macro_export(local_inner_macros)]` attribute so that users won't have to - import those macros. -- [`mod.rs` files are now optional.][54146] Previously if you had a `foo` module - with a `bar` submodule, you would have `src/foo/mod.rs` and `src/foo/bar.rs`. - Now you can have `src/foo.rs` and `src/foo/bar.rs` to achieve the same effect. + macros, it is recommended to export with the + `#[macro_export(local_inner_macros)]` attribute so users won't have to import + those macros. - [You can now catch visibility keywords (e.g. `pub`, `pub(crate)`) in macros using the `vis` specifier.][53370] -- [Non-macro attributes now allow all forms of literals not just - strings.][53044] e.g. Previously you would write `#[attr("true")]` you can now +- [Non-macro attributes now allow all forms of literals, not just + strings.][53044] Previously, you would write `#[attr("true")]`, and you can now write `#[attr(true)]`. - [You can now specify a function to handle a panic in the Rust runtime with the `#[panic_handler]` attribute.][51366] @@ -54,9 +51,9 @@ Stabilized APIs - [`Ipv6Addr::UNSPECIFIED`] - [`Iterator::find_map`] - The following methods are a replacement methods for `trim_left`, `trim_right`, - `trim_left_matches`, and `trim_right_matches`. Which will be deprecated - in 1.33.0. + The following methods are replacement methods for `trim_left`, `trim_right`, + `trim_left_matches`, and `trim_right_matches`, which will be deprecated + in 1.33.0: - [`str::trim_end_matches`] - [`str::trim_end`] - [`str::trim_start_matches`] @@ -67,21 +64,18 @@ Cargo - [`cargo run` doesn't require specifying a package in workspaces.][cargo/5877] - [`cargo doc` now supports `--message-format=json`.][cargo/5878] This is equivalent to calling `rustdoc --error-format=json`. -- [You can specify which edition to create a project in cargo - with `cargo new --edition`.][cargo/5984] Currently only `2015` is a - valid option. - [Cargo will now provide a progress bar for builds.][cargo/5995] Misc ---- - [`rustdoc` allows you to specify what edition to treat your code as with the `--edition` option.][54057] -- [`rustdoc` now has the `--color` (Specify whether to output color) and - `--error-format` (Specify error format e.g. `json`) options.][53003] +- [`rustdoc` now has the `--color` (specify whether to output color) and + `--error-format` (specify error format, e.g. `json`) options.][53003] - [We now distribute a `rust-gdbgui` script that invokes `gdbgui` with Rust debug symbols.][53774] - [Attributes from Rust tools such as `rustfmt` or `clippy` are now - available.][53459] e.g. `#[rustfmt::skip]` will skip formatting the next item. + available,][53459] e.g. `#[rustfmt::skip]` will skip formatting the next item. [50911]: https://github.com/rust-lang/rust/pull/50911/ [51363]: https://github.com/rust-lang/rust/pull/51363/ @@ -103,9 +97,8 @@ Misc [54404]: https://github.com/rust-lang/rust/pull/54404/ [cargo/5877]: https://github.com/rust-lang/cargo/pull/5877/ [cargo/5878]: https://github.com/rust-lang/cargo/pull/5878/ -[cargo/5984]: https://github.com/rust-lang/cargo/pull/5984/ [cargo/5995]: https://github.com/rust-lang/cargo/pull/5995/ -[proc-macros]: https://doc.rust-lang.org/book/2018-edition/ch19-06-macros.html +[proc-macros]: https://doc.rust-lang.org/nightly/book/2018-edition/ch19-06-macros.html [`Ipv4Addr::BROADCAST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.BROADCAST [`Ipv4Addr::LOCALHOST`]: https://doc.rust-lang.org/nightly/std/net/struct.Ipv4Addr.html#associatedconstant.LOCALHOST @@ -153,7 +146,7 @@ Compiler Libraries --------- -- [`Once::call_once` now no longer requires `Once` to be `'static`.][52239] +- [`Once::call_once` no longer requires `Once` to be `'static`.][52239] - [`BuildHasherDefault` now implements `PartialEq` and `Eq`.][52402] - [`Box`, `Box`, and `Box` now implement `Clone`.][51912] - [Implemented `PartialEq<&str>` for `OsString` and `PartialEq` @@ -169,10 +162,10 @@ Stabilized APIs Cargo ----- -- [Cargo can silently fix some bad lockfiles ][cargo/5831] You can use - `--locked` to disable this behaviour. +- [Cargo can silently fix some bad lockfiles.][cargo/5831] You can use + `--locked` to disable this behavior. - [`cargo-install` will now allow you to cross compile an install - using `--target`][cargo/5614] + using `--target`.][cargo/5614] - [Added the `cargo-fix` subcommand to automatically move project code from 2015 edition to 2018.][cargo/5723] - [`cargo doc` can now optionally document private types using the @@ -184,15 +177,15 @@ Misc the specified level to that level.][52354] For example `--cap-lints warn` will demote `deny` and `forbid` lints to `warn`. - [`rustc` and `rustdoc` will now have the exit code of `1` if compilation - fails, and `101` if there is a panic.][52197] + fails and `101` if there is a panic.][52197] - [A preview of clippy has been made available through rustup.][51122] - You can install the preview with `rustup component add clippy-preview` + You can install the preview with `rustup component add clippy-preview`. Compatibility Notes ------------------- - [`str::{slice_unchecked, slice_unchecked_mut}` are now deprecated.][51807] Use `str::get_unchecked(begin..end)` instead. -- [`std::env::home_dir` is now deprecated for its unintuitive behaviour.][51656] +- [`std::env::home_dir` is now deprecated for its unintuitive behavior.][51656] Consider using the `home_dir` function from https://crates.io/crates/dirs instead. - [`rustc` will no longer silently ignore invalid data in target spec.][52330] @@ -432,7 +425,7 @@ Language be used as an identifier. - [The dyn syntax is now available.][49968] This syntax is equivalent to the bare `Trait` syntax, and should make it clearer when being used in tandem with - `impl Trait`. Since it is equivalent to the following syntax: + `impl Trait` because it is equivalent to the following syntax: `&Trait == &dyn Trait`, `&mut Trait == &mut dyn Trait`, and `Box == Box`. - [Attributes on generic parameters such as types and lifetimes are @@ -495,10 +488,10 @@ Cargo a different directory than `target` for placing compilation artifacts. - [Cargo will be adding automatic target inference for binaries, benchmarks, examples, and tests in the Rust 2018 edition.][cargo/5335] If your project specifies - specific targets e.g. using `[[bin]]` and have other binaries in locations + specific targets, e.g. using `[[bin]]`, and have other binaries in locations where cargo would infer a binary, Cargo will produce a warning. You can - disable this feature ahead of time by setting any of the following `autobins`, - `autobenches`, `autoexamples`, `autotests` to false. + disable this feature ahead of time by setting any of the following to false: + `autobins`, `autobenches`, `autoexamples`, `autotests`. - [Cargo will now cache compiler information.][cargo/5359] This can be disabled by setting `CARGO_CACHE_RUSTC_INFO=0` in your environment. @@ -514,8 +507,8 @@ Compatibility Notes work.][49896] e.g. `::core::prelude::v1::StrExt::is_empty("")` will not compile, `"".is_empty()` will still compile. - [`Debug` output on `atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize}` - will only print the inner type.][48553] e.g. - `print!("{:?}", AtomicBool::new(true))` will print `true` + will only print the inner type.][48553] E.g. + `print!("{:?}", AtomicBool::new(true))` will print `true`, not `AtomicBool(true)`. - [The maximum number for `repr(align(N))` is now 2²⁹.][50378] Previously you could enter higher numbers but they were not supported by LLVM. Up to 512MB @@ -578,7 +571,7 @@ Version 1.26.2 (2018-06-05) Compatibility Notes ------------------- -- [The borrow checker was fixed to avoid unsoundness when using match ergonomics][51117] +- [The borrow checker was fixed to avoid unsoundness when using match ergonomics.][51117] [51117]: https://github.com/rust-lang/rust/issues/51117 @@ -589,18 +582,18 @@ Version 1.26.1 (2018-05-29) Tools ----- -- [RLS now works on Windows][50646] -- [Rustfmt stopped badly formatting text in some cases][rustfmt/2695] +- [RLS now works on Windows.][50646] +- [Rustfmt stopped badly formatting text in some cases.][rustfmt/2695] Compatibility Notes -------- - [`fn main() -> impl Trait` no longer works for non-Termination - trait][50656] + trait.][50656] This reverts an accidental stabilization. -- [`NaN > NaN` no longer returns true in const-fn contexts][50812] -- [Prohibit using turbofish for `impl Trait` in method arguments][50950] +- [`NaN > NaN` no longer returns true in const-fn contexts.][50812] +- [Prohibit using turbofish for `impl Trait` in method arguments.][50950] [50646]: https://github.com/rust-lang/rust/issues/50646 [50656]: https://github.com/rust-lang/rust/pull/50656 @@ -616,18 +609,18 @@ Language - [Closures now implement `Copy` and/or `Clone` if all captured variables implement either or both traits.][49299] - [The inclusive range syntax e.g. `for x in 0..=10` is now stable.][47813] -- [The `'_` lifetime is now stable. The underscore lifetime can be used anywhere where a +- [The `'_` lifetime is now stable. The underscore lifetime can be used anywhere a lifetime can be elided.][49458] - [`impl Trait` is now stable allowing you to have abstract types in returns - or in function parameters.][49255] e.g. `fn foo() -> impl Iterator` or + or in function parameters.][49255] E.g. `fn foo() -> impl Iterator` or `fn open(path: impl AsRef)`. - [Pattern matching will now automatically apply dereferences.][49394] - [128-bit integers in the form of `u128` and `i128` are now stable.][49101] - [`main` can now return `Result<(), E: Debug>`][49162] in addition to `()`. - [A lot of operations are now available in a const context.][46882] E.g. You can now index into constant arrays, reference and dereference into constants, - and use Tuple struct constructors. -- [Fixed entry slice patterns are now stable.][48516] e.g. + and use tuple struct constructors. +- [Fixed entry slice patterns are now stable.][48516] E.g. ```rust let points = [1, 2, 3, 4]; match points { @@ -1052,7 +1045,7 @@ Language Compiler -------- - [Enabled `TrapUnreachable` in LLVM which should mitigate the impact of - undefined behaviour.][45920] + undefined behavior.][45920] - [rustc now suggests renaming import if names clash.][45660] - [Display errors/warnings correctly when there are zero-width or wide characters.][45711] diff --git a/src/Cargo.lock b/src/Cargo.lock index 3361e81ecfe..dd211083527 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -349,6 +349,7 @@ dependencies = [ "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c27f4f056d7..ffc5adbebb3 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -594,7 +594,7 @@ class RustBuild(object): return '' def bootstrap_binary(self): - """Return the path of the boostrap binary + """Return the path of the bootstrap binary >>> rb = RustBuild() >>> rb.build_dir = "build" diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py index 4427313f9e5..2bbd4372721 100644 --- a/src/etc/lldb_rust_formatters.py +++ b/src/etc/lldb_rust_formatters.py @@ -277,7 +277,7 @@ def print_std_string_val(val, internal_dict): #=-------------------------------------------------------------------------------------------------- def print_array_of_values(array_name, data_ptr_val, length, internal_dict): - """Prints a contigous memory range, interpreting it as values of the + """Prints a contiguous memory range, interpreting it as values of the pointee-type of data_ptr_val.""" data_ptr_type = data_ptr_val.type diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 8c950cd06d9..24c8fd3a969 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -77,7 +77,7 @@ /// movie_reviews.insert("Office Space", "Deals with real issues in the workplace."); /// movie_reviews.insert("Pulp Fiction", "Masterpiece."); /// movie_reviews.insert("The Godfather", "Very enjoyable."); -/// movie_reviews.insert("The Blues Brothers", "Eye lyked it alot."); +/// movie_reviews.insert("The Blues Brothers", "Eye lyked it a lot."); /// /// // check for a specific one. /// if !movie_reviews.contains_key("Les Misérables") { diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 35e4eea756d..4efcaae59b0 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -518,7 +518,7 @@ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { /// The block is described by the given `ptr` pointer and `layout`. /// /// If this returns a non-null pointer, then ownership of the memory block - /// referenced by `ptr` has been transferred to this alloctor. + /// referenced by `ptr` has been transferred to this allocator. /// The memory may or may not have been deallocated, /// and should be considered unusable (unless of course it was /// transferred back to the caller again via the return value of diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 56a24168e28..cceae9249e4 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1025,7 +1025,7 @@ /// // to avoid problems in case something further down panics. /// src.set_len(0); /// - /// // The two regions cannot overlap becuase mutable references do + /// // The two regions cannot overlap because mutable references do /// // not alias, and two different vectors cannot own the same /// // memory. /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 07ba285ea5c..fd3e50998fe 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -304,7 +304,7 @@ pub fn contains(&self, item: &U) -> bool } } -/// An range bounded inclusively below and above (`start..=end`). +/// A range bounded inclusively below and above (`start..=end`). /// /// The `RangeInclusive` `start..=end` contains all values with `x >= start` /// and `x <= end`. It is empty unless `start <= end`. diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 0224560af4c..a03c080fb3f 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -102,7 +102,7 @@ /// value in place, preventing the value referenced by that pointer from being moved /// unless it implements [`Unpin`]. /// -/// See the [`pin` module] documentation for furthur explanation on pinning. +/// See the [`pin` module] documentation for further explanation on pinning. /// /// [`Unpin`]: ../../std/marker/trait.Unpin.html /// [`pin` module]: ../../std/pin/index.html diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 1c761ba21b3..b699cb02884 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -38,7 +38,7 @@ //! underlying object is live and no reference (just raw pointers) is used to //! access the same memory. //! -//! These axioms, along with careful use of [`offset`] for pointer arithmentic, +//! These axioms, along with careful use of [`offset`] for pointer arithmetic, //! are enough to correctly implement many useful things in unsafe code. Stronger guarantees //! will be provided eventually, as the [aliasing] rules are being determined. For more //! information, see the [book] as well as the section in the reference devoted diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index ab4ae50c443..c9fb22e0080 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -188,6 +188,11 @@ pub fn will_wake_nonlocal(&self, other: &Waker) -> bool { } impl From for Waker { + /// Converts a `LocalWaker` into a `Waker`. + /// + /// This conversion turns a `!Sync` `LocalWaker` into a `Sync` `Waker`, allowing a wakeup + /// object to be sent to another thread, but giving up its ability to do specialized + /// thread-local wakeup behavior. #[inline] fn from(local_waker: LocalWaker) -> Self { local_waker.0 diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index de03892b994..4d6d3bd56f2 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -72,8 +72,9 @@ use syntax_pos::symbol::InternedString; use traits; use traits::query::{ - CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, - CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, + CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, + CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, }; use ty::{TyCtxt, FnSig, Instance, InstanceDef, ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty}; @@ -654,6 +655,7 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool { [] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>), [] DropckOutlives(CanonicalTyGoal<'tcx>), [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), + [] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>), [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>), [] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>), [] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>), diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index a09fd5df557..e378e1b8be0 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -40,7 +40,7 @@ fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match self { CrateNum::Index(id) => write!(fmt, "crate{}", id.private), CrateNum::Invalid => write!(fmt, "invalid crate"), - CrateNum::BuiltinMacros => write!(fmt, "bultin macros crate"), + CrateNum::BuiltinMacros => write!(fmt, "builtin macros crate"), CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"), } } @@ -101,7 +101,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { CrateNum::Index(id) => fmt::Display::fmt(&id.private, f), CrateNum::Invalid => write!(f, "invalid crate"), - CrateNum::BuiltinMacros => write!(f, "bultin macros crate"), + CrateNum::BuiltinMacros => write!(f, "builtin macros crate"), CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"), } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 95b73d5f87b..dcc0f8545e5 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -298,6 +298,9 @@ fn visit_fn_decl(&mut self, fd: &'v FnDecl) { fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) { walk_fn(self, fk, fd, b, s, id) } + fn visit_use(&mut self, path: &'v Path, id: NodeId, hir_id: HirId) { + walk_use(self, path, id, hir_id) + } fn visit_trait_item(&mut self, ti: &'v TraitItem) { walk_trait_item(self, ti) } @@ -471,8 +474,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } } ItemKind::Use(ref path, _) => { - visitor.visit_id(item.id); - visitor.visit_path(path, item.hir_id); + visitor.visit_use(path, item.id, item.hir_id); } ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => { @@ -554,6 +556,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { walk_list!(visitor, visit_attribute, &item.attrs); } +pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, + path: &'v Path, + item_id: NodeId, + hir_id: HirId) { + visitor.visit_id(item_id); + visitor.visit_path(path, hir_id); +} + pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, enum_definition: &'v EnumDef, generics: &'v Generics, @@ -652,6 +662,9 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, path_span: Span, segment: &'v PathSegment) { visitor.visit_ident(segment.ident); + if let Some(id) = segment.id { + visitor.visit_id(id); + } if let Some(ref args) = segment.args { visitor.visit_generic_args(path_span, args); } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a1363168f01..6370a520183 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -143,8 +143,12 @@ pub struct LoweringContext<'a> { } pub trait Resolver { - /// Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc. - fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool); + /// Resolve a path generated by the lowerer when expanding `for`, `if let`, etc. + fn resolve_hir_path( + &mut self, + path: &ast::Path, + is_value: bool, + ) -> hir::Path; /// Obtain the resolution for a node id fn get_resolution(&mut self, id: NodeId) -> Option; @@ -163,7 +167,6 @@ fn resolve_str_path( span: Span, crate_root: Option<&str>, components: &[&str], - params: Option>, is_value: bool, ) -> hir::Path; } @@ -1064,6 +1067,9 @@ fn lower_attrs(&mut self, attrs: &[Attribute]) -> hir::HirVec { } fn lower_attr(&mut self, attr: &Attribute) -> Attribute { + // Note that we explicitly do not walk the path. Since we don't really + // lower attributes (we use the AST version) there is nowhere to keep + // the HirIds. We don't actually need HIR version of attributes anyway. Attribute { id: attr.id, style: attr.style, @@ -1147,7 +1153,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::T TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Rptr(ref region, ref mt) => { - let span = t.span.shrink_to_lo(); + let span = self.sess.source_map().next_point(t.span.shrink_to_lo()); let lifetime = match *region { Some(ref lt) => self.lower_lifetime(lt), None => self.elided_ref_lifetime(span), @@ -1677,6 +1683,7 @@ fn lower_qpath( num_lifetimes, parenthesized_generic_args, itctx.reborrow(), + None, ) }) .collect(), @@ -1720,6 +1727,7 @@ fn lower_qpath( 0, ParenthesizedGenericArgs::Warn, itctx.reborrow(), + None, )); let qpath = hir::QPath::TypeRelative(ty, segment); @@ -1748,6 +1756,7 @@ fn lower_path_extra( p: &Path, ident: Option, param_mode: ParamMode, + explicit_owner: Option, ) -> hir::Path { hir::Path { def, @@ -1761,6 +1770,7 @@ fn lower_path_extra( 0, ParenthesizedGenericArgs::Err, ImplTraitContext::disallowed(), + explicit_owner, ) }) .chain(ident.map(|ident| hir::PathSegment::from_ident(ident))) @@ -1771,7 +1781,7 @@ fn lower_path_extra( fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> hir::Path { let def = self.expect_full_def(id); - self.lower_path_extra(def, p, None, param_mode) + self.lower_path_extra(def, p, None, param_mode, None) } fn lower_path_segment( @@ -1782,6 +1792,7 @@ fn lower_path_segment( expected_lifetimes: usize, parenthesized_generic_args: ParenthesizedGenericArgs, itctx: ImplTraitContext<'_>, + explicit_owner: Option, ) -> hir::PathSegment { let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args { let msg = "parenthesized parameters may only be used with a trait"; @@ -1852,8 +1863,17 @@ fn lower_path_segment( } } + let def = self.expect_full_def(segment.id); + let id = if let Some(owner) = explicit_owner { + self.lower_node_id_with_owner(segment.id, owner) + } else { + self.lower_node_id(segment.id) + }; + hir::PathSegment::new( segment.ident, + Some(id.node_id), + Some(def), generic_args, infer_types, ) @@ -2936,6 +2956,12 @@ fn lower_use_tree( attrs: &hir::HirVec, ) -> hir::ItemKind { let path = &tree.prefix; + let segments = prefix + .segments + .iter() + .chain(path.segments.iter()) + .cloned() + .collect(); match tree.kind { UseTreeKind::Simple(rename, id1, id2) => { @@ -2943,12 +2969,7 @@ fn lower_use_tree( // First apply the prefix to the path let mut path = Path { - segments: prefix - .segments - .iter() - .chain(path.segments.iter()) - .cloned() - .collect(), + segments, span: path.span, }; @@ -2968,9 +2989,18 @@ fn lower_use_tree( // for later let ret_def = defs.next().unwrap_or(Def::Err); + // Here, we are looping over namespaces, if they exist for the definition + // being imported. We only handle type and value namespaces because we + // won't be dealing with macros in the rest of the compiler. + // Essentially a single `use` which imports two names is desugared into + // two imports. for (def, &new_node_id) in defs.zip([id1, id2].iter()) { let vis = vis.clone(); let name = name.clone(); + let mut path = path.clone(); + for seg in &mut path.segments { + seg.id = self.sess.next_node_id(); + } let span = path.span; self.resolver.definitions().create_def_with_parent( parent_def_index, @@ -2983,7 +3013,8 @@ fn lower_use_tree( self.with_hir_id_owner(new_node_id, |this| { let new_id = this.lower_node_id(new_node_id); - let path = this.lower_path_extra(def, &path, None, ParamMode::Explicit); + let path = + this.lower_path_extra(def, &path, None, ParamMode::Explicit, None); let item = hir::ItemKind::Use(P(path), hir::UseKind::Single); let vis_kind = match vis.node { hir::VisibilityKind::Public => hir::VisibilityKind::Public, @@ -2993,7 +3024,6 @@ fn lower_use_tree( let id = this.next_id(); hir::VisibilityKind::Restricted { path: path.clone(), - // We are allocating a new NodeId here id: id.node_id, hir_id: id.hir_id, } @@ -3016,19 +3046,15 @@ fn lower_use_tree( }); } - let path = P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit)); + let path = + P(self.lower_path_extra(ret_def, &path, None, ParamMode::Explicit, None)); hir::ItemKind::Use(path, hir::UseKind::Single) } UseTreeKind::Glob => { let path = P(self.lower_path( id, &Path { - segments: prefix - .segments - .iter() - .chain(path.segments.iter()) - .cloned() - .collect(), + segments, span: path.span, }, ParamMode::Explicit, @@ -3036,19 +3062,17 @@ fn lower_use_tree( hir::ItemKind::Use(path, hir::UseKind::Glob) } UseTreeKind::Nested(ref trees) => { + // Nested imports are desugared into simple imports. + let prefix = Path { - segments: prefix - .segments - .iter() - .chain(path.segments.iter()) - .cloned() - .collect(), + segments, span: prefix.span.to(path.span), }; - // Add all the nested PathListItems in the HIR + // Add all the nested PathListItems to the HIR. for &(ref use_tree, id) in trees { self.allocate_hir_id_counter(id, &use_tree); + let LoweredNodeId { node_id: new_id, hir_id: new_hir_id, @@ -3056,10 +3080,26 @@ fn lower_use_tree( let mut vis = vis.clone(); let mut name = name.clone(); - let item = - self.lower_use_tree(use_tree, &prefix, new_id, &mut vis, &mut name, &attrs); + let mut prefix = prefix.clone(); + // Give the segments new ids since they are being cloned. + for seg in &mut prefix.segments { + seg.id = self.sess.next_node_id(); + } + + // Each `use` import is an item and thus are owners of the + // names in the path. Up to this point the nested import is + // the current owner, since we want each desugared import to + // own its own names, we have to adjust the owner before + // lowering the rest of the import. self.with_hir_id_owner(new_id, |this| { + let item = this.lower_use_tree(use_tree, + &prefix, + new_id, + &mut vis, + &mut name, + attrs); + let vis_kind = match vis.node { hir::VisibilityKind::Public => hir::VisibilityKind::Public, hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar), @@ -3068,7 +3108,6 @@ fn lower_use_tree( let id = this.next_id(); hir::VisibilityKind::Restricted { path: path.clone(), - // We are allocating a new NodeId here id: id.node_id, hir_id: id.hir_id, } @@ -3081,7 +3120,7 @@ fn lower_use_tree( hir::Item { id: new_id, hir_id: new_hir_id, - name: name, + name, attrs: attrs.clone(), node: item, vis, @@ -3645,6 +3684,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { 0, ParenthesizedGenericArgs::Err, ImplTraitContext::disallowed(), + None, ); let args = args.iter().map(|x| self.lower_expr(x)).collect(); hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) @@ -4498,8 +4538,15 @@ fn lower_visibility( } else { self.lower_node_id(id) }; + let def = self.expect_full_def(id); hir::VisibilityKind::Restricted { - path: P(self.lower_path(id, path, ParamMode::Explicit)), + path: P(self.lower_path_extra( + def, + path, + None, + ParamMode::Explicit, + explicit_owner, + )), id: lowered_id.node_id, hir_id: lowered_id.hir_id, } @@ -4806,8 +4853,17 @@ fn std_path( params: Option>, is_value: bool ) -> hir::Path { - self.resolver - .resolve_str_path(span, self.crate_root, components, params, is_value) + let mut path = self.resolver + .resolve_str_path(span, self.crate_root, components, is_value); + path.segments.last_mut().unwrap().args = params; + + + for seg in path.segments.iter_mut() { + if let Some(id) = seg.id { + seg.id = Some(self.lower_node_id(id).node_id); + } + } + path } fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> hir::Ty { diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index bd12a5e0cb4..8c701d9e418 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -210,17 +210,22 @@ fn insert(&mut self, id: NodeId, node: Node<'hir>) { None => format!("{:?}", node) }; - if hir_id == ::hir::DUMMY_HIR_ID { - debug!("Maybe you forgot to lower the node id {:?}?", id); - } + let forgot_str = if hir_id == ::hir::DUMMY_HIR_ID { + format!("\nMaybe you forgot to lower the node id {:?}?", id) + } else { + String::new() + }; bug!("inconsistent DepNode for `{}`: \ - current_dep_node_owner={}, hir_id.owner={}", + current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?}) {}", node_str, self.definitions .def_path(self.current_dep_node_owner) .to_string_no_crate(), - self.definitions.def_path(hir_id.owner).to_string_no_crate()) + self.current_dep_node_owner, + self.definitions.def_path(hir_id.owner).to_string_no_crate(), + hir_id.owner, + forgot_str) } } @@ -392,6 +397,13 @@ fn visit_stmt(&mut self, stmt: &'hir Stmt) { }); } + fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment) { + if let Some(id) = path_segment.id { + self.insert(id, Node::PathSegment(path_segment)); + } + intravisit::walk_path_segment(self, path_span, path_segment); + } + fn visit_ty(&mut self, ty: &'hir Ty) { self.insert(ty.id, Node::Ty(ty)); diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs index 087efbd4a22..896a6163eba 100644 --- a/src/librustc/hir/map/hir_id_validator.rs +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -88,7 +88,7 @@ fn check)>(&mut self, walk(self); if owner_def_index == CRATE_DEF_INDEX { - return + return; } // There's always at least one entry for the owning item itself @@ -129,13 +129,16 @@ fn check)>(&mut self, local_id, self.hir_map.node_to_string(node_id))); } - self.errors.push(format!( "ItemLocalIds not assigned densely in {}. \ - Max ItemLocalId = {}, missing IDs = {:?}", + Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}", self.hir_map.def_path(DefId::local(owner_def_index)).to_string_no_crate(), max, - missing_items)); + missing_items, + self.hir_ids_seen + .values() + .map(|n| format!("({:?} {})", n, self.hir_map.node_to_string(*n))) + .collect::>())); } } } @@ -155,6 +158,7 @@ fn visit_id(&mut self, node_id: NodeId) { self.errors.push(format!("HirIdValidator: No HirId assigned for NodeId {}: {:?}", node_id, self.hir_map.node_to_string(node_id))); + return; } if owner != stable_id.owner { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index f5f9bcd3b5e..7a20146130d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -204,7 +204,7 @@ pub fn read(&self, id: NodeId) { if let Some(entry) = self.map[id.as_usize()] { self.dep_graph.read_index(entry.dep_node); } else { - bug!("called `HirMap::read()` with invalid `NodeId`") + bug!("called `HirMap::read()` with invalid `NodeId`: {:?}", id) } } @@ -344,6 +344,7 @@ pub fn describe_def(&self, node_id: NodeId) -> Option { Node::AnonConst(_) | Node::Expr(_) | Node::Stmt(_) | + Node::PathSegment(_) | Node::Ty(_) | Node::TraitRef(_) | Node::Pat(_) | @@ -884,6 +885,7 @@ pub fn span(&self, id: NodeId) -> Span { Some(Node::AnonConst(constant)) => self.body(constant.body).value.span, Some(Node::Expr(expr)) => expr.span, Some(Node::Stmt(stmt)) => stmt.span, + Some(Node::PathSegment(seg)) => seg.ident.span, Some(Node::Ty(ty)) => ty.span, Some(Node::TraitRef(tr)) => tr.path.span, Some(Node::Binding(pat)) => pat.span, @@ -1098,6 +1100,7 @@ pub fn print_node(&mut self, node: Node<'_>) -> io::Result<()> { Node::AnonConst(a) => self.print_anon_const(&a), Node::Expr(a) => self.print_expr(&a), Node::Stmt(a) => self.print_stmt(&a), + Node::PathSegment(a) => self.print_path_segment(&a), Node::Ty(a) => self.print_type(&a), Node::TraitRef(a) => self.print_trait_ref(&a), Node::Binding(a) | @@ -1215,6 +1218,9 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { Some(Node::Stmt(_)) => { format!("stmt {}{}", map.node_to_pretty_string(id), id_str) } + Some(Node::PathSegment(_)) => { + format!("path segment {}{}", map.node_to_pretty_string(id), id_str) + } Some(Node::Ty(_)) => { format!("type {}{}", map.node_to_pretty_string(id), id_str) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d5de6197a2e..a2095ff40c0 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -347,6 +347,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { pub struct PathSegment { /// The identifier portion of this path segment. pub ident: Ident, + // `id` and `def` are optional. We currently only use these in save-analysis, + // any path segments without these will not have save-analysis info and + // therefore will not have 'jump to def' in IDEs, but otherwise will not be + // affected. (In general, we don't bother to get the defs for synthesized + // segments, only for segments which have come from the AST). + pub id: Option, + pub def: Option, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that @@ -367,14 +374,24 @@ impl PathSegment { pub fn from_ident(ident: Ident) -> PathSegment { PathSegment { ident, + id: None, + def: None, infer_types: true, args: None, } } - pub fn new(ident: Ident, args: GenericArgs, infer_types: bool) -> Self { + pub fn new( + ident: Ident, + id: Option, + def: Option, + args: GenericArgs, + infer_types: bool, + ) -> Self { PathSegment { ident, + id, + def, infer_types, args: if args.is_empty() { None @@ -2511,6 +2528,7 @@ pub enum Node<'hir> { AnonConst(&'hir AnonConst), Expr(&'hir Expr), Stmt(&'hir Stmt), + PathSegment(&'hir PathSegment), Ty(&'hir Ty), TraitRef(&'hir TraitRef), Binding(&'hir Pat), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 08d46793d97..e69d32ad1de 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -180,7 +180,7 @@ pub fn new(cm: &'a SourceMap, State { s: pp::mk_printer(out, default_columns), cm: Some(cm), - comments: comments.clone(), + comments, literals: literals.unwrap_or_default().into_iter().peekable(), cur_cmnt: 0, boxes: Vec::new(), @@ -1633,6 +1633,17 @@ pub fn print_path(&mut self, Ok(()) } + pub fn print_path_segment(&mut self, segment: &hir::PathSegment) -> io::Result<()> { + if segment.ident.name != keywords::CrateRoot.name() && + segment.ident.name != keywords::DollarCrate.name() { + self.print_ident(segment.ident)?; + segment.with_generic_args(|generic_args| { + self.print_generic_args(generic_args, segment.infer_types, false) + })?; + } + Ok(()) + } + pub fn print_qpath(&mut self, qpath: &hir::QPath, colons_before_params: bool) diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index 97114779042..fbf4297222f 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -44,7 +44,7 @@ pub fn new(source_map: &'cm SourceMap) -> CachingSourceMapView<'cm> { CachingSourceMapView { source_map, - line_cache: [entry.clone(), entry.clone(), entry.clone()], + line_cache: [entry.clone(), entry.clone(), entry], time_stamp: 0, } } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index a48bd4eeb09..b220634d0d9 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -174,6 +174,8 @@ fn hash_stable(&self, impl_stable_hash_for!(struct hir::PathSegment { ident -> (ident.name), + id, + def, infer_types, args }); diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs index 89dbc76c8a6..0e4c94aaaf3 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc/infer/at.rs @@ -142,6 +142,28 @@ pub fn eq(self, self.trace(expected, actual).eq(&expected, &actual) } + pub fn relate( + self, + expected: T, + variance: ty::Variance, + actual: T, + ) -> InferResult<'tcx, ()> + where T: ToTrace<'tcx> + { + match variance { + ty::Variance::Covariant => self.sub(expected, actual), + ty::Variance::Invariant => self.eq(expected, actual), + ty::Variance::Contravariant => self.sup(expected, actual), + + // We could make this make sense but it's not readily + // exposed and I don't feel like dealing with it. Note + // that bivariance in general does a bit more than just + // *nothing*, it checks that the types are the same + // "modulo variance" basically. + ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"), + } + } + /// Compute the least-upper-bound, or mutual supertype, of two /// values. The order of the arguments doesn't matter, but since /// this can result in an error (e.g., if asked to compute LUB of diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index de8f57ee796..0ee03bc4c6e 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -251,6 +251,7 @@ fn generalize(&self, dir: RelationDir) -> RelateResult<'tcx, Generalization<'tcx>> { + debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir); // Determine the ambient variance within which `ty` appears. // The surrounding equation is: // @@ -273,8 +274,15 @@ fn generalize(&self, root_ty: ty, }; - let ty = generalize.relate(&ty, &ty)?; + let ty = match generalize.relate(&ty, &ty) { + Ok(ty) => ty, + Err(e) => { + debug!("generalize: failure {:?}", e); + return Err(e); + } + }; let needs_wf = generalize.needs_wf; + debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf); Ok(Generalization { ty, needs_wf }) } } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 854960492c9..c7b5ddb8341 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -74,6 +74,9 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let infcx = self.fields.infcx; let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); + + debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); + match (&a.sty, &b.sty) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { infcx.type_variables.borrow_mut().equate(a_id, b_id); diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 202a4284f4c..266b1c4d4a0 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -233,6 +233,12 @@ "detect mut variables which don't need to be mutable" } +declare_lint! { + pub UNCONDITIONAL_RECURSION, + Warn, + "functions that cannot return without calling themselves" +} + declare_lint! { pub SINGLE_USE_LIFETIMES, Allow, @@ -402,6 +408,7 @@ fn get_lints(&self) -> LintArray { DEPRECATED, UNUSED_UNSAFE, UNUSED_MUT, + UNCONDITIONAL_RECURSION, SINGLE_USE_LIFETIMES, UNUSED_LIFETIMES, UNUSED_LABELS, diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 897e9cc2a38..f21f949c9f5 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -83,7 +83,14 @@ macro_rules! __impl_stable_hash_field { macro_rules! impl_stable_hash_for { // FIXME(mark-i-m): Some of these should be `?` rather than `*`. See the git blame and change // them back when `?` is supported again. - (enum $enum_name:path { $( $variant:ident $( ( $($field:ident $(-> $delegate:tt)*),* ) )* ),* $(,)* }) => { + (enum $enum_name:path { + $( $variant:ident + // this incorrectly allows specifying both tuple-like and struct-like fields, as in `Variant(a,b){c,d}`, + // when it should be only one or the other + $( ( $($field:ident $(-> $delegate:tt)*),* ) )* + $( { $($named_field:ident $(-> $named_delegate:tt)*),* } )* + ),* $(,)* + }) => { impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $enum_name { #[inline] fn hash_stable(&self, @@ -94,8 +101,9 @@ fn hash_stable(&s match *self { $( - $variant $( ( $(ref $field),* ) )* => { + $variant $( ( $(ref $field),* ) )* $( { $(ref $named_field),* } )* => { $($( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );*)* + $($( __impl_stable_hash_field!($named_field, __ctx, __hasher $(, $named_delegate)*) );*)* } )* } @@ -133,10 +141,11 @@ fn hash_stable(&s } }; - (impl<$tcx:lifetime $(, $T:ident)*> for struct $struct_name:path { - $($field:ident),* $(,)* + (impl<$tcx:lifetime $(, $lt:lifetime $(: $lt_bound:lifetime)*)* $(, $T:ident)*> for struct $struct_name:path { + $($field:ident $(-> $delegate:tt)*),* $(,)* }) => { - impl<'a, $tcx, $($T,)*> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name + impl<'a, $tcx, $($lt $(: $lt_bound)*,)* $($T,)*> + ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name where $($T: ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>>),* { #[inline] @@ -147,7 +156,7 @@ fn hash_stable(&s $(ref $field),* } = *self; - $( $field.hash_stable(__ctx, __hasher));* + $( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );* } } }; diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 98e80d333c1..361abb16896 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2235,21 +2235,46 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) }; let mut err = report_missing_lifetime_specifiers(self.tcx.sess, span, lifetime_refs.len()); + let mut add_label = true; if let Some(params) = error { if lifetime_refs.len() == 1 { - self.report_elision_failure(&mut err, params); + add_label = add_label && self.report_elision_failure(&mut err, params, span); } } + if add_label { + add_missing_lifetime_specifiers_label(&mut err, span, lifetime_refs.len()); + } err.emit(); } + fn suggest_lifetime(&self, db: &mut DiagnosticBuilder<'_>, span: Span, msg: &str) -> bool { + match self.tcx.sess.source_map().span_to_snippet(span) { + Ok(ref snippet) => { + let (sugg, applicability) = if snippet == "&" { + ("&'static ".to_owned(), Applicability::MachineApplicable) + } else if snippet == "'_" { + ("'static".to_owned(), Applicability::MachineApplicable) + } else { + (format!("{} + 'static", snippet), Applicability::MaybeIncorrect) + }; + db.span_suggestion_with_applicability(span, msg, sugg, applicability); + false + } + Err(_) => { + db.help(msg); + true + } + } + } + fn report_elision_failure( &mut self, db: &mut DiagnosticBuilder<'_>, params: &[ElisionFailureInfo], - ) { + span: Span, + ) -> bool { let mut m = String::new(); let len = params.len(); @@ -2304,7 +2329,7 @@ fn report_elision_failure( "this function's return type contains a borrowed value, but \ there is no value for it to be borrowed from" ); - help!(db, "consider giving it a 'static lifetime"); + self.suggest_lifetime(db, span, "consider giving it a 'static lifetime") } else if elided_len == 0 { help!( db, @@ -2312,11 +2337,8 @@ fn report_elision_failure( an elided lifetime, but the lifetime cannot be derived from \ the arguments" ); - help!( - db, - "consider giving it an explicit bounded or 'static \ - lifetime" - ); + let msg = "consider giving it an explicit bounded or 'static lifetime"; + self.suggest_lifetime(db, span, msg) } else if elided_len == 1 { help!( db, @@ -2324,6 +2346,7 @@ fn report_elision_failure( the signature does not say which {} it is borrowed from", m ); + true } else { help!( db, @@ -2331,6 +2354,7 @@ fn report_elision_failure( the signature does not say whether it is borrowed from {}", m ); + true } } @@ -2744,26 +2768,28 @@ fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { } } -pub fn report_missing_lifetime_specifiers( +fn report_missing_lifetime_specifiers( sess: &Session, span: Span, count: usize, ) -> DiagnosticBuilder<'_> { - let mut err = struct_span_err!( + struct_span_err!( sess, span, E0106, "missing lifetime specifier{}", if count > 1 { "s" } else { "" } - ); + ) +} - let msg: Cow<'static, str> = if count > 1 { - format!("expected {} lifetime parameters", count).into() +fn add_missing_lifetime_specifiers_label( + err: &mut DiagnosticBuilder<'_>, + span: Span, + count: usize, +) { + if count > 1 { + err.span_label(span, format!("expected {} lifetime parameters", count)); } else { - "expected lifetime parameter".into() + err.span_label(span, "expected lifetime parameter"); }; - - err.span_label(span, msg); - - err } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 4c2b2b2d41d..5054f522778 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -632,7 +632,7 @@ pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result } //////////////////////////////////////////////////////////////////////////////// -// Methods to faciliate working with signed integers stored in a u128 +// Methods to facilitate working with signed integers stored in a u128 //////////////////////////////////////////////////////////////////////////////// pub fn sign_extend(value: u128, size: Size) -> u128 { diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 9e54b146fd0..4304f08a78f 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -181,7 +181,7 @@ pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self #[inline] pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool { match self { - Scalar::Bits { bits, size } => { + Scalar::Bits { bits, size } => { assert_eq!(size as u64, cx.data_layout().pointer_size.bytes()); bits == 0 }, @@ -189,14 +189,6 @@ pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool { } } - #[inline] - pub fn is_null(self) -> bool { - match self { - Scalar::Bits { bits, .. } => bits == 0, - Scalar::Ptr(_) => false - } - } - #[inline] pub fn from_bool(b: bool) -> Self { Scalar::Bits { bits: b as u128, size: 1 } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 62b5327ae46..9d296e67da1 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -469,7 +469,7 @@ pub enum BorrowKind { /// } /// /// This can't be a shared borrow because mutably borrowing (*x as Some).0 - /// should not prevent `if let None = x { ... }`, for example, becase the + /// should not prevent `if let None = x { ... }`, for example, because the /// mutating `(*x as Some).0` can't affect the discriminant of `x`. /// We can also report errors with this kind of borrow differently. Shallow, @@ -2065,9 +2065,8 @@ pub struct SourceScopeLocalData { /////////////////////////////////////////////////////////////////////////// // Operands -/// These are values that can appear inside an rvalue (or an index -/// place). They are intentionally limited to prevent rvalues from -/// being nested in one another. +/// These are values that can appear inside an rvalue. They are intentionally +/// limited to prevent rvalues from being nested in one another. #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] pub enum Operand<'tcx> { /// Copy: The value must be available for use afterwards. @@ -2438,6 +2437,14 @@ impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { } } +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> { + type Lifted = UserTypeAnnotation<'tcx>; + (UserTypeAnnotation::Ty)(ty), + (UserTypeAnnotation::TypeOf)(def, substs), + } +} + newtype_index! { pub struct Promoted { DEBUG_FORMAT = "promoted[{}]" diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index db1bc3e7519..a1e2b7a0646 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -34,6 +34,7 @@ pub struct Preorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, visited: BitSet, worklist: Vec, + root_is_start_block: bool, } impl<'a, 'tcx> Preorder<'a, 'tcx> { @@ -44,6 +45,7 @@ pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> { mir, visited: BitSet::new_empty(mir.basic_blocks().len()), worklist, + root_is_start_block: root == START_BLOCK, } } } @@ -75,15 +77,19 @@ fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { fn size_hint(&self) -> (usize, Option) { // All the blocks, minus the number of blocks we've visited. - let remaining = self.mir.basic_blocks().len() - self.visited.count(); + let upper = self.mir.basic_blocks().len() - self.visited.count(); - // We will visit all remaining blocks exactly once. - (remaining, Some(remaining)) + let lower = if self.root_is_start_block { + // We will visit all remaining blocks exactly once. + upper + } else { + self.worklist.len() + }; + + (lower, Some(upper)) } } -impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {} - /// Postorder traversal of a graph. /// /// Postorder traversal is when each node is visited after all of it's @@ -105,7 +111,8 @@ impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {} pub struct Postorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, visited: BitSet, - visit_stack: Vec<(BasicBlock, Successors<'a>)> + visit_stack: Vec<(BasicBlock, Successors<'a>)>, + root_is_start_block: bool, } impl<'a, 'tcx> Postorder<'a, 'tcx> { @@ -113,7 +120,8 @@ pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> { let mut po = Postorder { mir, visited: BitSet::new_empty(mir.basic_blocks().len()), - visit_stack: Vec::new() + visit_stack: Vec::new(), + root_is_start_block: root == START_BLOCK, }; @@ -214,15 +222,19 @@ fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { fn size_hint(&self) -> (usize, Option) { // All the blocks, minus the number of blocks we've visited. - let remaining = self.mir.basic_blocks().len() - self.visited.count(); + let upper = self.mir.basic_blocks().len() - self.visited.count(); - // We will visit all remaining blocks exactly once. - (remaining, Some(remaining)) + let lower = if self.root_is_start_block { + // We will visit all remaining blocks exactly once. + upper + } else { + self.visit_stack.len() + }; + + (lower, Some(upper)) } } -impl<'a, 'tcx> ExactSizeIterator for Postorder<'a, 'tcx> {} - /// Reverse postorder traversal of a graph /// /// Reverse postorder is the reverse order of a postorder traversal. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index dc003992644..ea30752a820 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -412,7 +412,7 @@ fn on_unimplemented_note( flags.push(("crate_local".to_owned(), None)); } - // Allow targetting all integers using `{integral}`, even if the exact type was resolved + // Allow targeting all integers using `{integral}`, even if the exact type was resolved if self_ty.is_integral() { flags.push(("_Self".to_owned(), Some("{integral}".to_owned()))); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b29ee8f7cdc..b266fbe0d11 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -340,7 +340,7 @@ fn fold>(&mut self, value: &T) -> T { let value = self.selcx.infcx().resolve_type_vars_if_possible(value); if !value.has_projections() { - value.clone() + value } else { value.fold_with(self) } diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 35f17aebc04..13683d85444 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -34,6 +34,9 @@ pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; +pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>; + pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>; diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs new file mode 100644 index 00000000000..b3955b8f864 --- /dev/null +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -0,0 +1,77 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use traits::query::Fallible; +use hir::def_id::DefId; +use ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use ty::subst::UserSubsts; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct AscribeUserType<'tcx> { + pub mir_ty: Ty<'tcx>, + pub variance: ty::Variance, + pub def_id: DefId, + pub user_substs: UserSubsts<'tcx>, +} + +impl<'tcx> AscribeUserType<'tcx> { + pub fn new( + mir_ty: Ty<'tcx>, + variance: ty::Variance, + def_id: DefId, + user_substs: UserSubsts<'tcx>, + ) -> Self { + AscribeUserType { mir_ty, variance, def_id, user_substs } + } +} + +impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx> { + type QueryResponse = (); + + fn try_fast_path( + _tcx: TyCtxt<'_, 'gcx, 'tcx>, + _key: &ParamEnvAnd<'tcx, Self>, + ) -> Option { + None + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + tcx.type_op_ascribe_user_type(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResponse<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { + v + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> { + mir_ty, variance, def_id, user_substs + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> { + type Lifted = AscribeUserType<'tcx>; + mir_ty, variance, def_id, user_substs + } +} + +impl_stable_hash_for! { + struct AscribeUserType<'tcx> { + mir_ty, variance, def_id, user_substs + } +} diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs index b292df758ee..d20d43cf757 100644 --- a/src/librustc/traits/query/type_op/mod.rs +++ b/src/librustc/traits/query/type_op/mod.rs @@ -20,6 +20,7 @@ use ty::fold::TypeFoldable; use ty::{Lift, ParamEnvAnd, TyCtxt}; +pub mod ascribe_user_type; pub mod custom; pub mod eq; pub mod implied_outlives_bounds; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 49f37179354..2ea16823cc6 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1522,6 +1522,33 @@ fn check_candidate_cache( .map(|v| v.get(tcx)) } + /// Determines whether can we safely cache the result + /// of selecting an obligation. This is almost always 'true', + /// except when dealing with certain ParamCandidates. + /// + /// Ordinarily, a ParamCandidate will contain no inference variables, + /// since it was usually produced directly from a DefId. However, + /// certain cases (currently only librustdoc's blanket impl finder), + /// a ParamEnv may be explicitly constructed with inference types. + /// When this is the case, we do *not* want to cache the resulting selection + /// candidate. This is due to the fact that it might not always be possible + /// to equate the obligation's trait ref and the candidate's trait ref, + /// if more constraints end up getting added to an inference variable. + /// + /// Because of this, we always want to re-run the full selection + /// process for our obligation the next time we see it, since + /// we might end up picking a different SelectionCandidate (or none at all) + fn can_cache_candidate(&self, + result: &SelectionResult<'tcx, SelectionCandidate<'tcx>> + ) -> bool { + match result { + Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => { + !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer())) + }, + _ => true + } + } + fn insert_candidate_cache( &mut self, param_env: ty::ParamEnv<'tcx>, @@ -1531,6 +1558,14 @@ fn insert_candidate_cache( ) { let tcx = self.tcx(); let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; + + if !self.can_cache_candidate(&candidate) { + debug!("insert_candidate_cache(trait_ref={:?}, candidate={:?} -\ + candidate is not cacheable", trait_ref, candidate); + return; + + } + if self.can_use_global_caches(param_env) { if let Err(Overflow) = candidate { // Don't cache overflow globally; we only produce this diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index c60471c285d..1a9f8630632 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -931,7 +931,9 @@ pub struct GlobalCtxt<'tcx> { maybe_unused_trait_imports: FxHashSet, maybe_unused_extern_crates: Vec<(DefId, Span)>, - pub extern_prelude: FxHashSet, + /// Extern prelude entries. The value is `true` if the entry was introduced + /// via `extern crate` item and not `--extern` option or compiler built-in. + pub extern_prelude: FxHashMap, // Internal cache for metadata decoding. No need to track deps on this. pub rcache: Lock>>, diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 46669f1f943..7153c729d15 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -343,7 +343,7 @@ pub fn push_item_path(self, buffer: &mut T, def_id: DefId, pushed_prelude_cra // printing the `CrateRoot` so we don't prepend a `crate::` to paths. let mut is_prelude_crate = false; if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data { - if self.extern_prelude.contains(&data.as_interned_str().as_symbol()) { + if self.extern_prelude.contains_key(&data.as_interned_str().as_symbol()) { is_prelude_crate = true; } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index bb9346f2f46..5a2f062f233 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -36,7 +36,7 @@ use ty::util::{IntTypeExt, Discr}; use ty::walk::TypeWalker; use util::captures::Captures; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use arena::SyncDroplessArena; use session::DataTypeKind; @@ -141,7 +141,9 @@ pub struct Resolutions { pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, pub export_map: ExportMap, - pub extern_prelude: FxHashSet, + /// Extern prelude entries. The value is `true` if the entry was introduced + /// via `extern crate` item and not `--extern` option or compiler built-in. + pub extern_prelude: FxHashMap, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -328,7 +330,7 @@ pub fn is_visible_locally(self) -> bool { } } -#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] +#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Hash)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type Invariant, // T <: T iff B == A -- e.g., type of mutable cell diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index d0c3109da52..0f6ff93c523 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -14,8 +14,9 @@ use mir::interpret::GlobalId; use traits; use traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, - CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; @@ -115,6 +116,15 @@ fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalPredicateGoal<'tcx>) -> Cow } } +impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> { + fn describe( + _tcx: TyCtxt<'_, '_, '_>, + goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>, + ) -> Cow<'static, str> { + format!("evaluating `type_op_ascribe_user_type` `{:?}`", goal).into() + } +} + impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> { fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpEqGoal<'tcx>) -> Cow<'static, str> { format!("evaluating `type_op_eq` `{:?}`", goal).into() diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index e4fc45f3798..a59a15da08d 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -34,9 +34,12 @@ use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; use traits::{self, Vtable}; -use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, - CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution}; +use traits::query::{ + CanonicalPredicateGoal, CanonicalProjectionGoal, + CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, + CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, + CanonicalTypeOpNormalizeGoal, NoSolution, +}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::query::outlives_bounds::OutlivesBound; @@ -589,6 +592,14 @@ CanonicalPredicateGoal<'tcx> ) -> Result, + /// Do not call this query directly: part of the `Eq` type-op + [] fn type_op_ascribe_user_type: TypeOpAscribeUserType( + CanonicalTypeOpAscribeUserTypeGoal<'tcx> + ) -> Result< + Lrc>>, + NoSolution, + >, + /// Do not call this query directly: part of the `Eq` type-op [] fn type_op_eq: TypeOpEq( CanonicalTypeOpEqGoal<'tcx> diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 71e435fea77..789658dcf72 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1079,6 +1079,7 @@ macro_rules! force { DepKind::ImpliedOutlivesBounds | DepKind::DropckOutlives | DepKind::EvaluateObligation | + DepKind::TypeOpAscribeUserType | DepKind::TypeOpEq | DepKind::TypeOpSubtype | DepKind::TypeOpProvePredicate | diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index cd9679c8763..62e38ad9bfa 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -967,7 +967,7 @@ pub fn inputs_and_output(&self) -> ty::Binder<&'tcx List>> { self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output) } pub fn output(&self) -> ty::Binder> { - self.map_bound_ref(|fn_sig| fn_sig.output().clone()) + self.map_bound_ref(|fn_sig| fn_sig.output()) } pub fn variadic(&self) -> bool { self.skip_binder().variadic diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index 169bd9a8466..2fe6a0377f8 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -761,7 +761,7 @@ pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char, fty, asm, cons, volatile, alignstack, dia); Some(self.call(v, inputs, None)) } else { - // LLVM has detected an issue with our constaints, bail out + // LLVM has detected an issue with our constraints, bail out None } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8020d596afd..7ad012409b5 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -790,7 +790,9 @@ pub fn phase_2_configure_and_expand( trait_map: resolver.trait_map, maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, maybe_unused_extern_crates: resolver.maybe_unused_extern_crates, - extern_prelude: resolver.extern_prelude, + extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { + (ident.name, entry.introduced_by_item) + }).collect(), }, analysis: ty::CrateAnalysis { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index bc5f688729c..19f9168cf0a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -30,10 +30,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; -use rustc::cfg; -use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; -use rustc::traits; use hir::Node; use util::nodemap::NodeSet; use lint::{LateContext, LintContext, LintArray}; @@ -844,279 +841,6 @@ fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) { } } -declare_lint! { - pub UNCONDITIONAL_RECURSION, - Warn, - "functions that cannot return without calling themselves" -} - -#[derive(Copy, Clone)] -pub struct UnconditionalRecursion; - - -impl LintPass for UnconditionalRecursion { - fn get_lints(&self) -> LintArray { - lint_array![UNCONDITIONAL_RECURSION] - } -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { - fn check_fn(&mut self, - cx: &LateContext, - fn_kind: FnKind, - _: &hir::FnDecl, - body: &hir::Body, - sp: Span, - id: ast::NodeId) { - let method = match fn_kind { - FnKind::ItemFn(..) => None, - FnKind::Method(..) => { - Some(cx.tcx.associated_item(cx.tcx.hir.local_def_id(id))) - } - // closures can't recur, so they don't matter. - FnKind::Closure(_) => return, - }; - - // Walk through this function (say `f`) looking to see if - // every possible path references itself, i.e. the function is - // called recursively unconditionally. This is done by trying - // to find a path from the entry node to the exit node that - // *doesn't* call `f` by traversing from the entry while - // pretending that calls of `f` are sinks (i.e. ignoring any - // exit edges from them). - // - // NB. this has an edge case with non-returning statements, - // like `loop {}` or `panic!()`: control flow never reaches - // the exit node through these, so one can have a function - // that never actually calls itself but is still picked up by - // this lint: - // - // fn f(cond: bool) { - // if !cond { panic!() } // could come from `assert!(cond)` - // f(false) - // } - // - // In general, functions of that form may be able to call - // itself a finite number of times and then diverge. The lint - // considers this to be an error for two reasons, (a) it is - // easier to implement, and (b) it seems rare to actually want - // to have behaviour like the above, rather than - // e.g. accidentally recursing after an assert. - - let cfg = cfg::CFG::new(cx.tcx, &body); - - let mut work_queue = vec![cfg.entry]; - let mut reached_exit_without_self_call = false; - let mut self_call_spans = vec![]; - let mut visited = FxHashSet::default(); - - while let Some(idx) = work_queue.pop() { - if idx == cfg.exit { - // found a path! - reached_exit_without_self_call = true; - break; - } - - let cfg_id = idx.node_id(); - if visited.contains(&cfg_id) { - // already done - continue; - } - visited.insert(cfg_id); - - // is this a recursive call? - let local_id = cfg.graph.node_data(idx).id(); - if local_id != hir::DUMMY_ITEM_LOCAL_ID { - let node_id = cx.tcx.hir.hir_to_node_id(hir::HirId { - owner: body.value.hir_id.owner, - local_id - }); - let self_recursive = match method { - Some(ref method) => expr_refers_to_this_method(cx, method, node_id), - None => expr_refers_to_this_fn(cx, id, node_id), - }; - if self_recursive { - self_call_spans.push(cx.tcx.hir.span(node_id)); - // this is a self call, so we shouldn't explore past - // this node in the CFG. - continue; - } - } - - // add the successors of this node to explore the graph further. - for (_, edge) in cfg.graph.outgoing_edges(idx) { - let target_idx = edge.target(); - let target_cfg_id = target_idx.node_id(); - if !visited.contains(&target_cfg_id) { - work_queue.push(target_idx) - } - } - } - - // Check the number of self calls because a function that - // doesn't return (e.g. calls a `-> !` function or `loop { /* - // no break */ }`) shouldn't be linted unless it actually - // recurs. - if !reached_exit_without_self_call && !self_call_spans.is_empty() { - let sp = cx.tcx.sess.source_map().def_span(sp); - let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, - sp, - "function cannot return without recursing"); - db.span_label(sp, "cannot return without recursing"); - // offer some help to the programmer. - for call in &self_call_spans { - db.span_label(*call, "recursive call site"); - } - db.help("a `loop` may express intention better if this is on purpose"); - db.emit(); - } - - // all done - return; - - // Functions for identifying if the given Expr NodeId `id` - // represents a call to the function `fn_id`/method `method`. - - fn expr_refers_to_this_fn(cx: &LateContext, fn_id: ast::NodeId, id: ast::NodeId) -> bool { - match cx.tcx.hir.get(id) { - Node::Expr(&hir::Expr { node: hir::ExprKind::Call(ref callee, _), .. }) => { - let def = if let hir::ExprKind::Path(ref qpath) = callee.node { - cx.tables.qpath_def(qpath, callee.hir_id) - } else { - return false; - }; - match def { - Def::Local(..) | Def::Upvar(..) => false, - _ => def.def_id() == cx.tcx.hir.local_def_id(fn_id) - } - } - _ => false, - } - } - - // Check if the expression `id` performs a call to `method`. - fn expr_refers_to_this_method(cx: &LateContext, - method: &ty::AssociatedItem, - id: ast::NodeId) - -> bool { - use rustc::ty::adjustment::*; - - // Ignore non-expressions. - let expr = if let Node::Expr(e) = cx.tcx.hir.get(id) { - e - } else { - return false; - }; - - // Check for overloaded autoderef method calls. - let mut source = cx.tables.expr_ty(expr); - for adjustment in cx.tables.expr_adjustments(expr) { - if let Adjust::Deref(Some(deref)) = adjustment.kind { - let (def_id, substs) = deref.method_call(cx.tcx, source); - if method_call_refers_to_method(cx, method, def_id, substs, id) { - return true; - } - } - source = adjustment.target; - } - - // Check for method calls and overloaded operators. - if cx.tables.is_method_call(expr) { - let hir_id = cx.tcx.hir.definitions().node_to_hir_id(id); - if let Some(def) = cx.tables.type_dependent_defs().get(hir_id) { - let def_id = def.def_id(); - let substs = cx.tables.node_substs(hir_id); - if method_call_refers_to_method(cx, method, def_id, substs, id) { - return true; - } - } else { - cx.tcx.sess.delay_span_bug(expr.span, - "no type-dependent def for method call"); - } - } - - // Check for calls to methods via explicit paths (e.g. `T::method()`). - match expr.node { - hir::ExprKind::Call(ref callee, _) => { - let def = if let hir::ExprKind::Path(ref qpath) = callee.node { - cx.tables.qpath_def(qpath, callee.hir_id) - } else { - return false; - }; - match def { - Def::Method(def_id) => { - let substs = cx.tables.node_substs(callee.hir_id); - method_call_refers_to_method(cx, method, def_id, substs, id) - } - _ => false, - } - } - _ => false, - } - } - - // Check if the method call to the method with the ID `callee_id` - // and instantiated with `callee_substs` refers to method `method`. - fn method_call_refers_to_method<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, - method: &ty::AssociatedItem, - callee_id: DefId, - callee_substs: &Substs<'tcx>, - expr_id: ast::NodeId) - -> bool { - let tcx = cx.tcx; - let callee_item = tcx.associated_item(callee_id); - - match callee_item.container { - // This is an inherent method, so the `def_id` refers - // directly to the method definition. - ty::ImplContainer(_) => callee_id == method.def_id, - - // A trait method, from any number of possible sources. - // Attempt to select a concrete impl before checking. - ty::TraitContainer(trait_def_id) => { - let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs); - let trait_ref = ty::Binder::bind(trait_ref); - let span = tcx.hir.span(expr_id); - let obligation = - traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), - cx.param_env, - trait_ref.to_poly_trait_predicate()); - - tcx.infer_ctxt().enter(|infcx| { - let mut selcx = traits::SelectionContext::new(&infcx); - match selcx.select(&obligation) { - // The method comes from a `T: Trait` bound. - // If `T` is `Self`, then this call is inside - // a default method definition. - Ok(Some(traits::VtableParam(_))) => { - let on_self = trait_ref.self_ty().is_self(); - // We can only be recursing in a default - // method if we're being called literally - // on the `Self` type. - on_self && callee_id == method.def_id - } - - // The `impl` is known, so we check that with a - // special case: - Ok(Some(traits::VtableImpl(vtable_impl))) => { - let container = ty::ImplContainer(vtable_impl.impl_def_id); - // It matches if it comes from the same impl, - // and has the same method name. - container == method.container && - callee_item.ident.name == method.ident.name - } - - // There's no way to know if this call is - // recursive, so we assume it's not. - _ => false, - } - }) - } - } - } - } -} - declare_lint! { PLUGIN_AS_LIBRARY, Warn, @@ -1724,7 +1448,6 @@ fn get_lints(&self) -> LintArray { MISSING_DEBUG_IMPLEMENTATIONS, ANONYMOUS_PARAMETERS, UNUSED_DOC_COMMENTS, - UNCONDITIONAL_RECURSION, PLUGIN_AS_LIBRARY, NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 5bf2b76e668..f289acc032b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -144,7 +144,6 @@ macro_rules! add_lint_group { UnusedAllocation: UnusedAllocation, MissingCopyImplementations: MissingCopyImplementations, UnstableFeatures: UnstableFeatures, - UnconditionalRecursion: UnconditionalRecursion, InvalidNoMangleItems: InvalidNoMangleItems, PluginAsLibrary: PluginAsLibrary, MutableTransmutes: MutableTransmutes, diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 4cf2072e792..96d04253cc4 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -284,8 +284,13 @@ fn check_unused_parens_expr(&self, parser::contains_exterior_struct_lit(&inner) }; if !necessary { - let pattern = pprust::expr_to_string(value); - Self::remove_outer_parens(cx, value.span, &pattern, msg); + let expr_text = if let Ok(snippet) = cx.sess().source_map() + .span_to_snippet(value.span) { + snippet + } else { + pprust::expr_to_string(value) + }; + Self::remove_outer_parens(cx, value.span, &expr_text, msg); } } } @@ -295,8 +300,13 @@ fn check_unused_parens_pat(&self, value: &ast::Pat, msg: &str) { if let ast::PatKind::Paren(_) = value.node { - let pattern = pprust::pat_to_string(value); - Self::remove_outer_parens(cx, value.span, &pattern, msg); + let pattern_text = if let Ok(snippet) = cx.sess().source_map() + .span_to_snippet(value.span) { + snippet + } else { + pprust::pat_to_string(value) + }; + Self::remove_outer_parens(cx, value.span, &pattern_text, msg); } } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 7988de28b5d..e6e1367b592 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -68,7 +68,7 @@ pub fn provide_extern<$lt>(providers: &mut Providers<$lt>) { let $cdata = $tcx.crate_data_as_rc_any($def_id.krate); let $cdata = $cdata.downcast_ref::() - .expect("CrateStore crated ata is not a CrateMetadata"); + .expect("CrateStore created data is not a CrateMetadata"); $compute })* diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 6db10734474..bbbe02fda6a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -42,7 +42,7 @@ use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts}; +use rustc::ty::subst::{Subst, Substs, UnpackedKind}; use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; use std::rc::Rc; use std::{fmt, iter}; @@ -975,126 +975,43 @@ fn relate_type_and_user_type( locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - let tcx = self.tcx(); - debug!( - "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})", - a, v, user_ty, locations + "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})", + a, v, user_ty, locations, ); - // The `TypeRelating` code assumes that "unresolved inference - // variables" appear in the "a" side, so flip `Contravariant` - // ambient variance to get the right relationship. - let v1 = ty::Contravariant.xform(v); - match user_ty { UserTypeAnnotation::Ty(canonical_ty) => { let (ty, _) = self.infcx .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); - self.relate_types(ty, v1, a, locations, category)?; + // The `TypeRelating` code assumes that "unresolved inference + // variables" appear in the "a" side, so flip `Contravariant` + // ambient variance to get the right relationship. + let v1 = ty::Contravariant.xform(v); - self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); + self.relate_types(ty, v1, a, locations, category)?; } UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { let ( - UserSubsts { - substs, - user_self_ty, - }, + user_substs, _, ) = self.infcx .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - let ty = self.tcx().type_of(def_id); - let ty = ty.subst(tcx, substs); - let ty = self.normalize(ty, locations); - - self.relate_types(ty, v1, a, locations, category)?; - - if let Some(UserSelfTy { - impl_def_id, - self_ty, - }) = user_self_ty - { - let impl_self_ty = tcx.type_of(impl_def_id); - let impl_self_ty = impl_self_ty.subst(tcx, &substs); - let impl_self_ty = self.normalize(impl_self_ty, locations); - - // There may be type variables in `substs` and hence - // in `impl_self_ty`, but they should all have been - // resolved to some fixed value during the first call - // to `relate`, above. Therefore, if we use - // `resolve_type_vars_if_possible` we should get to - // something without type variables. This is important - // because the `b` type in `relate_with_variance` - // below is not permitted to have inference variables. - let impl_self_ty = self.infcx.resolve_type_vars_if_possible(&impl_self_ty); - assert!(!impl_self_ty.has_infer_types()); - - self.eq_types(self_ty, impl_self_ty, locations, category)?; - - self.prove_predicate( - ty::Predicate::WellFormed(impl_self_ty), - locations, - category, - ); - } - - // Prove the predicates coming along with `def_id`. - // - // Also, normalize the `instantiated_predicates` - // because otherwise we wind up with duplicate "type - // outlives" error messages. - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates); - self.normalize_and_prove_instantiated_predicates( - instantiated_predicates, + self.fully_perform_op( locations, - ); - - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // them? This would only be relevant if some input - // type were ill-formed but did not appear in `ty`, - // which...could happen with normalization... - self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); + category, + self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( + a, v, def_id, user_substs, + )), + )?; } } Ok(()) } - /// Replace all free regions in `value` with their NLL `RegionVid` - /// equivalents; if not in NLL, does nothing. This is never - /// particularly necessary -- we'll do it lazilly as we process - /// the value anyway -- but in some specific cases it is useful to - /// normalize so we can suppress duplicate error messages. - fn fold_to_region_vid(&self, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - if let Some(borrowck_context) = &self.borrowck_context { - self.tcx().fold_regions(&value, &mut false, |r, _debruijn| { - if r.has_free_regions() { - self.tcx().mk_region(ty::RegionKind::ReVar( - borrowck_context.universal_regions.to_region_vid(r), - )) - } else { - r - } - }) - } else { - value - } - } - fn eq_opaque_type_and_type( &mut self, revealed_ty: Ty<'tcx>, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 9e78932bffe..e6dd0107e91 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -35,6 +35,8 @@ use transform::MirSource; use util as mir_util; +use super::lints; + /// Construct the MIR for a given def-id. pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'tcx> { let id = tcx.hir.as_local_node_id(def_id).unwrap(); @@ -176,6 +178,8 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t mir_util::dump_mir(tcx, None, "mir_map", &0, MirSource::item(def_id), &mir, |_, _| Ok(()) ); + lints::check(tcx, &mir, def_id); + mir }) } diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index bc917140bbd..9702e94a9e0 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -129,7 +129,7 @@ pub fn op_to_const<'tcx>( assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= op.layout.size.bytes()); let mut alloc = alloc.clone(); alloc.align = align; - // FIXME shouldnt it be the case that `mark_static_initialized` has already + // FIXME shouldn't it be the case that `mark_static_initialized` has already // interned this? I thought that is the entire point of that `FinishStatic` stuff? let alloc = ecx.tcx.intern_const_alloc(alloc); ConstValue::ByRef(ptr.alloc_id, alloc, ptr.offset) diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index bb3e4a8d881..56a9daf84f7 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -2279,7 +2279,7 @@ impl<'a> Drop for S<'a> { Note that this approach needs a reference to S with lifetime `'a`. Nothing shorter than `'a` will suffice: a shorter lifetime would imply -that after `demo` finishes excuting, something else (such as the +that after `demo` finishes executing, something else (such as the destructor!) could access `s.data` after the end of that shorter lifetime, which would again violate the `&mut`-borrow's exclusive access. diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 04a297d0a83..d53bb1dc4d6 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -931,12 +931,37 @@ fn intersection(&self, other: &Self) -> Option { } } -// Return a set of constructors equivalent to `all_ctors \ used_ctors`. +// A request for missing constructor data in terms of either: +// - whether or not there any missing constructors; or +// - the actual set of missing constructors. +#[derive(PartialEq)] +enum MissingCtorsInfo { + Emptiness, + Ctors, +} + +// Used by `compute_missing_ctors`. +#[derive(Debug, PartialEq)] +enum MissingCtors<'tcx> { + Empty, + NonEmpty, + + // Note that the Vec can be empty. + Ctors(Vec>), +} + +// When `info` is `MissingCtorsInfo::Ctors`, compute a set of constructors +// equivalent to `all_ctors \ used_ctors`. When `info` is +// `MissingCtorsInfo::Emptiness`, just determines if that set is empty or not. +// (The split logic gives a performance win, because we always need to know if +// the set is empty, but we rarely need the full set, and it can be expensive +// to compute the full set.) fn compute_missing_ctors<'a, 'tcx: 'a>( + info: MissingCtorsInfo, tcx: TyCtxt<'a, 'tcx, 'tcx>, all_ctors: &Vec>, used_ctors: &Vec>, -) -> Vec> { +) -> MissingCtors<'tcx> { let mut missing_ctors = vec![]; for req_ctor in all_ctors { @@ -965,10 +990,22 @@ fn compute_missing_ctors<'a, 'tcx: 'a>( // We add `refined_ctors` instead of `req_ctor`, because then we can // provide more detailed error information about precisely which // ranges have been omitted. - missing_ctors.extend(refined_ctors); + if info == MissingCtorsInfo::Emptiness { + if !refined_ctors.is_empty() { + // The set is non-empty; return early. + return MissingCtors::NonEmpty; + } + } else { + missing_ctors.extend(refined_ctors); + } } - missing_ctors + if info == MissingCtorsInfo::Emptiness { + // If we reached here, the set is empty. + MissingCtors::Empty + } else { + MissingCtors::Ctors(missing_ctors) + } } /// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html @@ -1048,7 +1085,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, if let Some(constructors) = pat_constructors(cx, v[0], pcx) { debug!("is_useful - expanding constructors: {:#?}", constructors); split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) + is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) ).find(|result| result.is_useful()).unwrap_or(NotUseful) } else { debug!("is_useful - expanding wildcard"); @@ -1081,22 +1118,25 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, // feature flag is not present, so this is only // needed for that case. - // Find those constructors that are not matched by any non-wildcard patterns in the - // current column. - let missing_ctors = compute_missing_ctors(cx.tcx, &all_ctors, &used_ctors); + // Missing constructors are those that are not matched by any + // non-wildcard patterns in the current column. We always determine if + // the set is empty, but we only fully construct them on-demand, + // because they're rarely used and can be big. + let cheap_missing_ctors = + compute_missing_ctors(MissingCtorsInfo::Emptiness, cx.tcx, &all_ctors, &used_ctors); let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty); let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty); - debug!("missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", - missing_ctors, is_privately_empty, is_declared_nonexhaustive); + debug!("cheap_missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}", + cheap_missing_ctors, is_privately_empty, is_declared_nonexhaustive); // For privately empty and non-exhaustive enums, we work as if there were an "extra" // `_` constructor for the type, so we can never match over all constructors. let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive; - if missing_ctors.is_empty() && !is_non_exhaustive { + if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive { split_grouped_constructors(cx.tcx, all_ctors, matrix, pcx.ty).into_iter().map(|c| { - is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness) + is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) }).find(|result| result.is_useful()).unwrap_or(NotUseful) } else { let matrix = rows.iter().filter_map(|r| { @@ -1165,15 +1205,22 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, witness }).collect() } else { - pats.into_iter().flat_map(|witness| { - missing_ctors.iter().map(move |ctor| { - // Extends the witness with a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, this pushes the witness for `Some(_)`. - witness.clone().push_wild_constructor(cx, ctor, pcx.ty) - }) - }).collect() + let expensive_missing_ctors = + compute_missing_ctors(MissingCtorsInfo::Ctors, cx.tcx, &all_ctors, + &used_ctors); + if let MissingCtors::Ctors(missing_ctors) = expensive_missing_ctors { + pats.into_iter().flat_map(|witness| { + missing_ctors.iter().map(move |ctor| { + // Extends the witness with a "wild" version of this + // constructor, that matches everything that can be built with + // it. For example, if `ctor` is a `Constructor::Variant` for + // `Option::Some`, this pushes the witness for `Some(_)`. + witness.clone().push_wild_constructor(cx, ctor, pcx.ty) + }) + }).collect() + } else { + bug!("cheap missing ctors") + } }; UsefulWithWitness(new_witnesses) } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 18938892165..64ad4c2eec1 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -556,7 +556,7 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> { )?; } } else { - // Uh, that shouln't happen... the function did not intend to return + // Uh, that shouldn't happen... the function did not intend to return return err!(Unreachable); } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 9adca6c4297..6fe490c6efc 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -94,7 +94,7 @@ fn data_layout(&self) -> &TargetDataLayout { } } -// FIXME: Really we shouldnt clone memory, ever. Snapshot machinery should instad +// FIXME: Really we shouldn't clone memory, ever. Snapshot machinery should instead // carefully copy only the reachable parts. impl<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> Clone for Memory<'a, 'mir, 'tcx, M> @@ -658,7 +658,7 @@ fn get_bytes( } /// It is the caller's responsibility to handle undefined and pointer bytes. - /// However, this still checks that there are no relocations on the *egdes*. + /// However, this still checks that there are no relocations on the *edges*. #[inline] fn get_bytes_with_undef_and_ptr( &self, @@ -1098,7 +1098,7 @@ fn clear_relocations(&mut self, ptr: Pointer, size: Size) -> Eval Ok(()) } - /// Error if there are relocations overlapping with the egdes of the + /// Error if there are relocations overlapping with the edges of the /// given memory range. #[inline] fn check_relocation_edges(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> { diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 71b2f4b53a6..021e2d58f84 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -357,14 +357,14 @@ fn from_known_layout<'tcx>( } impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { - /// Try reading a value in memory; this is interesting particularily for ScalarPair. + /// Try reading a value in memory; this is interesting particularly for ScalarPair. /// Return None if the layout does not permit loading this as a value. pub(super) fn try_read_value_from_mplace( &self, mplace: MPlaceTy<'tcx, M::PointerTag>, ) -> EvalResult<'tcx, Option>> { if mplace.layout.is_unsized() { - // Dont touch unsized + // Don't touch unsized return Ok(None); } let (ptr, ptr_align) = mplace.to_scalar_ptr_align(); diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 047a0125f78..cff2288fd87 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -6,9 +6,8 @@ // it is not used by the general miri engine, just by CTFE. use std::hash::{Hash, Hasher}; -use std::mem; -use rustc::ich::{StableHashingContext, StableHashingContextProvider}; +use rustc::ich::StableHashingContextProvider; use rustc::mir; use rustc::mir::interpret::{ AllocId, Pointer, Scalar, @@ -20,7 +19,7 @@ use rustc::ty::layout::Align; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use syntax::ast::Mutability; use syntax::source_map::Span; @@ -217,23 +216,10 @@ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { align -> *align, // just copy alignment verbatim }); -// Can't use the macro here because that does not support named enum fields. -impl<'a> HashStable> for Place { - fn hash_stable( - &self, hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) - { - mem::discriminant(self).hash_stable(hcx, hasher); - match self { - Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher), - - Place::Local { frame, local } => { - frame.hash_stable(hcx, hasher); - local.hash_stable(hcx, hasher); - }, - } - } -} +impl_stable_hash_for!(enum ::interpret::Place { + Ptr(mem_place), + Local { frame, local }, +}); impl<'a, Ctx> Snapshot<'a, Ctx> for Place where Ctx: SnapshotContext<'a>, { @@ -317,20 +303,10 @@ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { } } -// Can't use the macro here because that does not support named enum fields. -impl<'a> HashStable> for StackPopCleanup { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) - { - mem::discriminant(self).hash_stable(hcx, hasher); - match self { - StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher), - StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher), - } - } -} +impl_stable_hash_for!(enum ::interpret::eval_context::StackPopCleanup { + Goto(block), + None { cleanup }, +}); #[derive(Eq, PartialEq)] struct FrameSnapshot<'a, 'tcx: 'a> { @@ -343,28 +319,17 @@ struct FrameSnapshot<'a, 'tcx: 'a> { stmt: usize, } -// Not using the macro because that does not support types depending on two lifetimes -impl<'a, 'mir, 'tcx: 'mir> HashStable> for Frame<'mir, 'tcx> { - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - - let Frame { - mir, - instance, - span, - return_to_block, - return_place, - locals, - block, - stmt, - } = self; +impl_stable_hash_for!(impl<'tcx, 'mir: 'tcx> for struct Frame<'mir, 'tcx> { + mir, + instance, + span, + return_to_block, + return_place -> (return_place.as_ref().map(|r| &**r)), + locals, + block, + stmt, +}); - (mir, instance, span, return_to_block).hash_stable(hcx, hasher); - (return_place.as_ref().map(|r| &**r), locals, block, stmt).hash_stable(hcx, hasher); - } -} impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx> where Ctx: SnapshotContext<'a>, { @@ -443,21 +408,11 @@ fn hash(&self, state: &mut H) { } } -// Not using the macro because we need special handling for `memory`, which the macro -// does not support at the same time as the extra bounds on the type. -impl<'a, 'b, 'mir, 'tcx> HashStable> - for EvalSnapshot<'a, 'mir, 'tcx> -{ - fn hash_stable( - &self, - hcx: &mut StableHashingContext<'b>, - hasher: &mut StableHasher) - { - // Not hashing memory: Avoid hashing memory all the time during execution - let EvalSnapshot{ memory: _, stack } = self; - stack.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(impl<'tcx, 'b, 'mir> for struct EvalSnapshot<'b, 'mir, 'tcx> { + // Not hashing memory: Avoid hashing memory all the time during execution + memory -> _, + stack, +}); impl<'a, 'mir, 'tcx> Eq for EvalSnapshot<'a, 'mir, 'tcx> {} diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 38cf79d8fa0..ac1ba0edc3b 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -230,7 +230,7 @@ fn validate_primitive_type( ), } } - // non-ZST also have to be dereferencable + // non-ZST also have to be dereferenceable if size != Size::ZERO { let ptr = try_validation!(place.ptr.to_ptr(), "integer pointer in non-ZST reference", path); @@ -272,7 +272,7 @@ fn validate_primitive_type( // FIXME: Check if the signature matches } // This should be all the primitive types - ty::Never => bug!("Uninhabited type should have been catched earlier"), + ty::Never => bug!("Uninhabited type should have been caught earlier"), _ => bug!("Unexpected primitive type {}", value.layout.ty) } Ok(()) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 2f44dff2e22..75417982aa1 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -79,6 +79,7 @@ macro_rules! try_block { mod build; mod dataflow; mod hair; +mod lints; mod shim; pub mod transform; pub mod util; diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs new file mode 100644 index 00000000000..4c7938504c1 --- /dev/null +++ b/src/librustc_mir/lints.rs @@ -0,0 +1,156 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc_data_structures::bit_set::BitSet; +use rustc::hir::def_id::DefId; +use rustc::hir::intravisit::FnKind; +use rustc::hir::map::blocks::FnLikeNode; +use rustc::lint::builtin::UNCONDITIONAL_RECURSION; +use rustc::mir::{self, Mir, TerminatorKind}; +use rustc::ty::{AssociatedItem, AssociatedItemContainer, Instance, TyCtxt, TyKind}; +use rustc::ty::subst::Substs; + +pub fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + def_id: DefId) { + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + + if let Some(fn_like_node) = FnLikeNode::from_node(tcx.hir.get(node_id)) { + check_fn_for_unconditional_recursion(tcx, fn_like_node.kind(), mir, def_id); + } +} + +fn check_fn_for_unconditional_recursion(tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn_kind: FnKind, + mir: &Mir<'tcx>, + def_id: DefId) { + if let FnKind::Closure(_) = fn_kind { + // closures can't recur, so they don't matter. + return; + } + + //FIXME(#54444) rewrite this lint to use the dataflow framework + + // Walk through this function (say `f`) looking to see if + // every possible path references itself, i.e. the function is + // called recursively unconditionally. This is done by trying + // to find a path from the entry node to the exit node that + // *doesn't* call `f` by traversing from the entry while + // pretending that calls of `f` are sinks (i.e. ignoring any + // exit edges from them). + // + // NB. this has an edge case with non-returning statements, + // like `loop {}` or `panic!()`: control flow never reaches + // the exit node through these, so one can have a function + // that never actually calls itself but is still picked up by + // this lint: + // + // fn f(cond: bool) { + // if !cond { panic!() } // could come from `assert!(cond)` + // f(false) + // } + // + // In general, functions of that form may be able to call + // itself a finite number of times and then diverge. The lint + // considers this to be an error for two reasons, (a) it is + // easier to implement, and (b) it seems rare to actually want + // to have behaviour like the above, rather than + // e.g. accidentally recursing after an assert. + + let basic_blocks = mir.basic_blocks(); + let mut reachable_without_self_call_queue = vec![mir::START_BLOCK]; + let mut reached_exit_without_self_call = false; + let mut self_call_locations = vec![]; + let mut visited = BitSet::new_empty(basic_blocks.len()); + + let param_env = tcx.param_env(def_id); + let trait_substs_count = + match tcx.opt_associated_item(def_id) { + Some(AssociatedItem { + container: AssociatedItemContainer::TraitContainer(trait_def_id), + .. + }) => tcx.generics_of(trait_def_id).count(), + _ => 0 + }; + let caller_substs = &Substs::identity_for_item(tcx, def_id)[..trait_substs_count]; + + while let Some(bb) = reachable_without_self_call_queue.pop() { + if visited.contains(bb) { + //already done + continue; + } + + visited.insert(bb); + + let block = &basic_blocks[bb]; + + if let Some(ref terminator) = block.terminator { + match terminator.kind { + TerminatorKind::Call { ref func, .. } => { + let func_ty = func.ty(mir, tcx); + + if let TyKind::FnDef(fn_def_id, substs) = func_ty.sty { + let (call_fn_id, call_substs) = + if let Some(instance) = Instance::resolve(tcx, + param_env, + fn_def_id, + substs) { + (instance.def_id(), instance.substs) + } else { + (fn_def_id, substs) + }; + + let is_self_call = + call_fn_id == def_id && + &call_substs[..caller_substs.len()] == caller_substs; + + if is_self_call { + self_call_locations.push(terminator.source_info); + + //this is a self call so we shouldn't explore + //further down this path + continue; + } + } + }, + TerminatorKind::Abort | TerminatorKind::Return => { + //found a path! + reached_exit_without_self_call = true; + break; + } + _ => {} + } + + for successor in terminator.successors() { + reachable_without_self_call_queue.push(*successor); + } + } + } + + // Check the number of self calls because a function that + // doesn't return (e.g. calls a `-> !` function or `loop { /* + // no break */ }`) shouldn't be linted unless it actually + // recurs. + if !reached_exit_without_self_call && !self_call_locations.is_empty() { + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + let sp = tcx.sess.source_map().def_span(tcx.hir.span(node_id)); + let mut db = tcx.struct_span_lint_node(UNCONDITIONAL_RECURSION, + node_id, + sp, + "function cannot return without recursing"); + db.span_label(sp, "cannot return without recursing"); + // offer some help to the programmer. + for location in &self_call_locations { + db.span_label(location.span, "recursive call site"); + } + db.help("a `loop` may express intention better if this is on purpose"); + db.emit(); + } +} diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index f4efe33da70..5114fa87974 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -333,6 +333,14 @@ fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>) let operand = Operand::Copy(promoted_place(ty, span)); mem::replace(&mut args[index], operand) } + // We expected a `TerminatorKind::Call` for which we'd like to promote an + // argument. `qualify_consts` saw a `TerminatorKind::Call` here, but + // we are seeing a `Goto`. That means that the `promote_temps` method + // already promoted this call away entirely. This case occurs when calling + // a function requiring a constant argument and as that constant value + // providing a value whose computation contains another call to a function + // requiring a constant argument. + TerminatorKind::Goto { .. } => return, _ => bug!() } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 78547abf9d9..c4d8ec35868 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -820,7 +820,9 @@ fn visit_terminator_kind(&mut self, let fn_ty = func.ty(self.mir, self.tcx); let mut callee_def_id = None; - let (mut is_shuffle, mut is_const_fn) = (false, false); + let mut is_shuffle = false; + let mut is_const_fn = false; + let mut is_promotable_const_fn = false; if let ty::FnDef(def_id, _) = fn_ty.sty { callee_def_id = Some(def_id); match self.tcx.fn_sig(def_id).abi() { @@ -881,6 +883,9 @@ fn visit_terminator_kind(&mut self, // functions without #[rustc_promotable] if self.tcx.is_promotable_const_fn(def_id) { is_const_fn = true; + is_promotable_const_fn = true; + } else if self.tcx.is_const_fn(def_id) { + is_const_fn = true; } } else { // stable const fn or unstable const fns with their feature gate @@ -982,7 +987,17 @@ fn visit_terminator_kind(&mut self, if !constant_arguments.contains(&i) { return } - if this.qualif.is_empty() { + // Since the argument is required to be constant, + // we care about constness, not promotability. + // If we checked for promotability, we'd miss out on + // the results of function calls (which are never promoted + // in runtime code) + // This is not a problem, because the argument explicitly + // requests constness, in contrast to regular promotion + // which happens even without the user requesting it. + // We can error out with a hard error if the argument is not + // constant here. + if (this.qualif - Qualif::NOT_PROMOTABLE).is_empty() { this.promotion_candidates.push(candidate); } else { this.tcx.sess.span_err(this.span, @@ -1011,7 +1026,11 @@ fn visit_terminator_kind(&mut self, // Be conservative about the returned value of a const fn. let tcx = self.tcx; let ty = dest.ty(self.mir, tcx).to_ty(tcx); - self.qualif = Qualif::empty(); + if is_const_fn && !is_promotable_const_fn && self.mode == Mode::Fn { + self.qualif = Qualif::NOT_PROMOTABLE; + } else { + self.qualif = Qualif::empty(); + } self.add_type(ty); } self.assign(dest, location); diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index f6ace57f5e0..0e9596244cd 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -166,12 +166,12 @@ fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) { } } - /// With eRFC 2497, we need to check whether an expression is ambigious and warn or error + /// With eRFC 2497, we need to check whether an expression is ambiguous and warn or error /// depending on the edition, this function handles that. fn while_if_let_ambiguity(&self, expr: &P) { if let Some((span, op_kind)) = self.while_if_let_expr_ambiguity(&expr) { let mut err = self.err_handler().struct_span_err( - span, &format!("ambigious use of `{}`", op_kind.to_string()) + span, &format!("ambiguous use of `{}`", op_kind.to_string()) ); err.note( @@ -193,9 +193,9 @@ fn while_if_let_ambiguity(&self, expr: &P) { } /// With eRFC 2497 adding if-let chains, there is a requirement that the parsing of - /// `&&` and `||` in a if-let statement be unambigious. This function returns a span and - /// a `BinOpKind` (either `&&` or `||` depending on what was ambigious) if it is determined - /// that the current expression parsed is ambigious and will break in future. + /// `&&` and `||` in a if-let statement be unambiguous. This function returns a span and + /// a `BinOpKind` (either `&&` or `||` depending on what was ambiguous) if it is determined + /// that the current expression parsed is ambiguous and will break in future. fn while_if_let_expr_ambiguity(&self, expr: &P) -> Option<(Span, BinOpKind)> { debug!("while_if_let_expr_ambiguity: expr.node: {:?}", expr.node); match &expr.node { @@ -203,12 +203,12 @@ fn while_if_let_expr_ambiguity(&self, expr: &P) -> Option<(Span, BinOpKind Some((expr.span, op.node)) }, ExprKind::Range(ref lhs, ref rhs, _) => { - let lhs_ambigious = lhs.as_ref() + let lhs_ambiguous = lhs.as_ref() .and_then(|lhs| self.while_if_let_expr_ambiguity(lhs)); - let rhs_ambigious = rhs.as_ref() + let rhs_ambiguous = rhs.as_ref() .and_then(|rhs| self.while_if_let_expr_ambiguity(rhs)); - lhs_ambigious.or(rhs_ambigious) + lhs_ambiguous.or(rhs_ambiguous) } _ => None, } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 5222dd27d34..b7ed3ef59b4 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -16,8 +16,8 @@ use macros::{InvocationData, ParentScope, LegacyScope}; use resolve_imports::ImportDirective; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport}; -use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding}; -use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas}; +use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; +use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry}; use Namespace::{self, TypeNS, ValueNS, MacroNS}; use {resolve_error, resolve_struct_error, ResolutionError}; @@ -28,6 +28,7 @@ use rustc_metadata::cstore::LoadedMacro; use std::cell::Cell; +use std::ptr; use rustc_data_structures::sync::Lrc; use syntax::ast::{Name, Ident}; @@ -121,7 +122,7 @@ fn build_reduced_graph_for_use_tree( use_tree: &ast::UseTree, id: NodeId, vis: ty::Visibility, - parent_prefix: &[Ident], + parent_prefix: &[Segment], mut uniform_paths_canary_emitted: bool, nested: bool, item: &Item, @@ -138,10 +139,10 @@ fn build_reduced_graph_for_use_tree( self.session.features_untracked().uniform_paths; let prefix_iter = || parent_prefix.iter().cloned() - .chain(use_tree.prefix.segments.iter().map(|seg| seg.ident)); + .chain(use_tree.prefix.segments.iter().map(|seg| seg.into())); let prefix_start = prefix_iter().next(); - let starts_with_non_keyword = prefix_start.map_or(false, |ident| { - !ident.is_path_segment_keyword() + let starts_with_non_keyword = prefix_start.map_or(false, |seg| { + !seg.ident.is_path_segment_keyword() }); // Imports are resolved as global by default, prepend `CrateRoot`, @@ -155,7 +156,7 @@ fn build_reduced_graph_for_use_tree( }; let root = if inject_crate_root { let span = use_tree.prefix.span.shrink_to_lo(); - Some(Ident::new(keywords::CrateRoot.name(), span)) + Some(Segment::from_ident(Ident::new(keywords::CrateRoot.name(), span))) } else { None }; @@ -201,13 +202,13 @@ fn build_reduced_graph_for_use_tree( let source = prefix_start.unwrap(); // Helper closure to emit a canary with the given base path. - let emit = |this: &mut Self, base: Option| { + let emit = |this: &mut Self, base: Option| { let subclass = SingleImport { target: Ident { name: keywords::Underscore.name().gensymed(), - span: source.span, + span: source.ident.span, }, - source, + source: source.ident, result: PerNS { type_ns: Cell::new(Err(Undetermined)), value_ns: Cell::new(Err(Undetermined)), @@ -218,7 +219,7 @@ fn build_reduced_graph_for_use_tree( this.add_import_directive( base.into_iter().collect(), subclass.clone(), - source.span, + source.ident.span, id, root_use_tree.span, root_id, @@ -229,15 +230,18 @@ fn build_reduced_graph_for_use_tree( }; // A single simple `self::x` canary. - emit(self, Some(Ident { - name: keywords::SelfValue.name(), - span: source.span, + emit(self, Some(Segment { + ident: Ident { + name: keywords::SelfValue.name(), + span: source.ident.span, + }, + id: source.id })); // One special unprefixed canary per block scope around // the import, to detect items unreachable by `self::x`. let orig_current_module = self.current_module; - let mut span = source.span.modern(); + let mut span = source.ident.span.modern(); loop { match self.current_module.kind { ModuleKind::Block(..) => emit(self, None), @@ -264,11 +268,11 @@ fn build_reduced_graph_for_use_tree( if nested { // Correctly handle `self` - if source.name == keywords::SelfValue.name() { + if source.ident.name == keywords::SelfValue.name() { type_ns_only = true; - let empty_prefix = module_path.last().map_or(true, |ident| { - ident.name == keywords::CrateRoot.name() + let empty_prefix = module_path.last().map_or(true, |seg| { + seg.ident.name == keywords::CrateRoot.name() }); if empty_prefix { resolve_error( @@ -283,20 +287,20 @@ fn build_reduced_graph_for_use_tree( // Replace `use foo::self;` with `use foo;` source = module_path.pop().unwrap(); if rename.is_none() { - ident = source; + ident = source.ident; } } } else { // Disallow `self` - if source.name == keywords::SelfValue.name() { + if source.ident.name == keywords::SelfValue.name() { resolve_error(self, use_tree.span, ResolutionError::SelfImportsOnlyAllowedWithin); } // Disallow `use $crate;` - if source.name == keywords::DollarCrate.name() && module_path.is_empty() { - let crate_root = self.resolve_crate_root(source); + if source.ident.name == keywords::DollarCrate.name() && module_path.is_empty() { + let crate_root = self.resolve_crate_root(source.ident); let crate_name = match crate_root.kind { ModuleKind::Def(_, name) => name, ModuleKind::Block(..) => unreachable!(), @@ -306,11 +310,14 @@ fn build_reduced_graph_for_use_tree( // while the current crate doesn't have a valid `crate_name`. if crate_name != keywords::Invalid.name() { // `crate_name` should not be interpreted as relative. - module_path.push(Ident { - name: keywords::CrateRoot.name(), - span: source.span, + module_path.push(Segment { + ident: Ident { + name: keywords::CrateRoot.name(), + span: source.ident.span, + }, + id: Some(self.session.next_node_id()), }); - source.name = crate_name; + source.ident.name = crate_name; } if rename.is_none() { ident.name = crate_name; @@ -331,7 +338,7 @@ fn build_reduced_graph_for_use_tree( let subclass = SingleImport { target: ident, - source, + source: source.ident, result: PerNS { type_ns: Cell::new(Err(Undetermined)), value_ns: Cell::new(Err(Undetermined)), @@ -437,13 +444,32 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) { let module = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(module); - if injected_crate_name().map_or(false, |name| item.ident.name == name) { + if injected_crate_name().map_or(false, |name| ident.name == name) { self.injected_crate = Some(module); } let used = self.process_legacy_macro_imports(item, module, expansion); let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas); + if ptr::eq(self.current_module, self.graph_root) { + if let Some(entry) = self.extern_prelude.get(&ident.modern()) { + if expansion != Mark::root() && orig_name.is_some() && + entry.extern_crate_item.is_none() { + self.session.span_err(item.span, "macro-expanded `extern crate` items \ + cannot shadow names passed with \ + `--extern`"); + } + } + let entry = self.extern_prelude.entry(ident.modern()) + .or_insert(ExternPreludeEntry { + extern_crate_item: None, + introduced_by_item: true, + }); + entry.extern_crate_item = Some(binding); + if orig_name.is_some() { + entry.introduced_by_item = true; + } + } let directive = self.arenas.alloc_import_directive(ImportDirective { root_id: item.id, id: item.id, @@ -468,7 +494,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) { ItemKind::GlobalAsm(..) => {} - ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root + ItemKind::Mod(..) if ident == keywords::Invalid.ident() => {} // Crate root ItemKind::Mod(..) => { let def_id = self.definitions.local_def_id(item.id); diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 74d1ae96e79..d77b1868ed7 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {CrateLint, PathResult}; +use {CrateLint, PathResult, Segment}; use std::collections::BTreeSet; @@ -23,8 +23,8 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { pub(crate) fn make_path_suggestion( &mut self, span: Span, - path: Vec - ) -> Option> { + path: Vec + ) -> Option> { debug!("make_path_suggestion: span={:?} path={:?}", span, path); // If we don't have a path to suggest changes to, then return. if path.is_empty() { @@ -37,13 +37,13 @@ pub(crate) fn make_path_suggestion( match (path.get(0), path.get(1)) { // Make suggestions that require at least two non-special path segments. - (Some(fst), Some(snd)) if !is_special(*fst) && !is_special(*snd) => { + (Some(fst), Some(snd)) if !is_special(fst.ident) && !is_special(snd.ident) => { debug!("make_path_suggestion: fst={:?} snd={:?}", fst, snd); self.make_missing_self_suggestion(span, path.clone()) .or_else(|| self.make_missing_crate_suggestion(span, path.clone())) .or_else(|| self.make_missing_super_suggestion(span, path.clone())) - .or_else(|| self.make_external_crate_suggestion(span, path.clone())) + .or_else(|| self.make_external_crate_suggestion(span, path)) }, _ => None, } @@ -59,10 +59,10 @@ pub(crate) fn make_path_suggestion( fn make_missing_self_suggestion( &mut self, span: Span, - mut path: Vec - ) -> Option> { + mut path: Vec + ) -> Option> { // Replace first ident with `self` and check if that is valid. - path[0].name = keywords::SelfValue.name(); + path[0].ident.name = keywords::SelfValue.name(); let result = self.resolve_path(None, &path, None, false, span, CrateLint::No); debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { @@ -82,10 +82,10 @@ fn make_missing_self_suggestion( fn make_missing_crate_suggestion( &mut self, span: Span, - mut path: Vec - ) -> Option> { + mut path: Vec + ) -> Option> { // Replace first ident with `crate` and check if that is valid. - path[0].name = keywords::Crate.name(); + path[0].ident.name = keywords::Crate.name(); let result = self.resolve_path(None, &path, None, false, span, CrateLint::No); debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { @@ -105,10 +105,10 @@ fn make_missing_crate_suggestion( fn make_missing_super_suggestion( &mut self, span: Span, - mut path: Vec - ) -> Option> { + mut path: Vec + ) -> Option> { // Replace first ident with `crate` and check if that is valid. - path[0].name = keywords::Super.name(); + path[0].ident.name = keywords::Super.name(); let result = self.resolve_path(None, &path, None, false, span, CrateLint::No); debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { @@ -131,13 +131,13 @@ fn make_missing_super_suggestion( fn make_external_crate_suggestion( &mut self, span: Span, - mut path: Vec - ) -> Option> { + mut path: Vec + ) -> Option> { // Need to clone else we can't call `resolve_path` without a borrow error. We also store // into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic) // each time. let external_crate_names: BTreeSet = self.resolver.extern_prelude - .clone().drain().collect(); + .iter().map(|(ident, _)| ident.name).collect(); // Insert a new path segment that we can replace. let new_path_segment = path[0].clone(); @@ -146,24 +146,17 @@ fn make_external_crate_suggestion( // Iterate in reverse so that we start with crates at the end of the alphabet. This means // that we'll always get `std` before `core`. for name in external_crate_names.iter().rev() { - let ident = Ident::with_empty_ctxt(*name); - // Calling `maybe_process_path_extern` ensures that we're only running `resolve_path` - // on a crate name that won't ICE. - if let Some(_) = self.crate_loader.maybe_process_path_extern(*name, ident.span) { - // Replace the first after root (a placeholder we inserted) with a crate name - // and check if that is valid. - path[1].name = *name; - let result = self.resolve_path(None, &path, None, false, span, CrateLint::No); - debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}", - name, path, result); - if let PathResult::Module(..) = result { - return Some(path) - } + // Replace the first after root (a placeholder we inserted) with a crate name + // and check if that is valid. + path[1].ident.name = *name; + let result = self.resolve_path(None, &path, None, false, span, CrateLint::No); + debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}", + name, path, result); + if let PathResult::Module(..) = result { + return Some(path) } } - // Remove our placeholder segment. - path.remove(1); None } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2c09ae7b7d2..546c5a5ed3d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -58,6 +58,7 @@ use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::base::MacroKind; +use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::symbol::{Symbol, keywords}; use syntax::util::lev_distance::find_best_match_for_name; @@ -631,6 +632,43 @@ fn error_code(self, has_unexpected_resolution: bool) -> &'static str { } } +// A minimal representation of a path segment. We use this in resolve because +// we synthesize 'path segments' which don't have the rest of an AST or HIR +// PathSegment. +#[derive(Clone, Copy, Debug)] +pub struct Segment { + ident: Ident, + id: Option, +} + +impl Segment { + fn from_path(path: &Path) -> Vec { + path.segments.iter().map(|s| s.into()).collect() + } + + fn from_ident(ident: Ident) -> Segment { + Segment { + ident, + id: None, + } + } + + fn names_to_string(segments: &[Segment]) -> String { + names_to_string(&segments.iter() + .map(|seg| seg.ident) + .collect::>()) + } +} + +impl<'a> From<&'a ast::PathSegment> for Segment { + fn from(seg: &'a ast::PathSegment) -> Segment { + Segment { + ident: seg.ident, + id: Some(seg.id), + } + } +} + struct UsePlacementFinder { target_module: NodeId, span: Option, @@ -1340,6 +1378,12 @@ fn intern(&mut self, string: &str, primitive_type: PrimTy) { } } +#[derive(Default, Clone)] +pub struct ExternPreludeEntry<'a> { + extern_crate_item: Option<&'a NameBinding<'a>>, + pub introduced_by_item: bool, +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -1352,7 +1396,7 @@ pub struct Resolver<'a, 'b: 'a> { graph_root: Module<'a>, prelude: Option>, - pub extern_prelude: FxHashSet, + pub extern_prelude: FxHashMap>, /// n.b. This is used only for better diagnostics, not name resolution itself. has_self: FxHashSet, @@ -1527,7 +1571,11 @@ fn parent(self, id: DefId) -> Option { /// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that /// the resolver is no longer needed as all the relevant information is inline. impl<'a, 'cl> hir::lowering::Resolver for Resolver<'a, 'cl> { - fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) { + fn resolve_hir_path( + &mut self, + path: &ast::Path, + is_value: bool, + ) -> hir::Path { self.resolve_hir_path_cb(path, is_value, |resolver, span, error| resolve_error(resolver, span, error)) } @@ -1537,33 +1585,22 @@ fn resolve_str_path( span: Span, crate_root: Option<&str>, components: &[&str], - args: Option>, is_value: bool ) -> hir::Path { - let mut segments = iter::once(keywords::CrateRoot.ident()) + let segments = iter::once(keywords::CrateRoot.ident()) .chain( crate_root.into_iter() .chain(components.iter().cloned()) .map(Ident::from_str) - ).map(hir::PathSegment::from_ident).collect::>(); + ).map(|i| self.new_ast_path_segment(i)).collect::>(); - if let Some(args) = args { - let ident = segments.last().unwrap().ident; - *segments.last_mut().unwrap() = hir::PathSegment { - ident, - args: Some(args), - infer_types: true, - }; - } - let mut path = hir::Path { + let path = ast::Path { span, - def: Def::Err, - segments: segments.into(), + segments, }; - self.resolve_hir_path(&mut path, is_value); - path + self.resolve_hir_path(&path, is_value) } fn get_resolution(&mut self, id: NodeId) -> Option { @@ -1589,23 +1626,27 @@ pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: b use std::iter; let mut errored = false; - let mut path = if path_str.starts_with("::") { - hir::Path { + let path = if path_str.starts_with("::") { + ast::Path { span, - def: Def::Err, - segments: iter::once(keywords::CrateRoot.ident()).chain({ - path_str.split("::").skip(1).map(Ident::from_str) - }).map(hir::PathSegment::from_ident).collect(), + segments: iter::once(keywords::CrateRoot.ident()) + .chain({ + path_str.split("::").skip(1).map(Ident::from_str) + }) + .map(|i| self.new_ast_path_segment(i)) + .collect(), } } else { - hir::Path { + ast::Path { span, - def: Def::Err, - segments: path_str.split("::").map(Ident::from_str) - .map(hir::PathSegment::from_ident).collect(), + segments: path_str + .split("::") + .map(Ident::from_str) + .map(|i| self.new_ast_path_segment(i)) + .collect(), } }; - self.resolve_hir_path_cb(&mut path, is_value, |_, _, _| errored = true); + let path = self.resolve_hir_path_cb(&path, is_value, |_, _, _| errored = true); if errored || path.def == Def::Err { Err(()) } else { @@ -1614,19 +1655,25 @@ pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: b } /// resolve_hir_path, but takes a callback in case there was an error - fn resolve_hir_path_cb(&mut self, path: &mut hir::Path, is_value: bool, error_callback: F) + fn resolve_hir_path_cb( + &mut self, + path: &ast::Path, + is_value: bool, + error_callback: F, + ) -> hir::Path where F: for<'c, 'b> FnOnce(&'c mut Resolver, Span, ResolutionError<'b>) { let namespace = if is_value { ValueNS } else { TypeNS }; - let hir::Path { ref segments, span, ref mut def } = *path; - let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect(); + let span = path.span; + let segments = &path.segments; + let path = Segment::from_path(&path); // FIXME (Manishearth): Intra doc links won't get warned of epoch changes - match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) { + let def = match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => - *def = module.def().unwrap(), + module.def().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => - *def = path_res.base_def(), - PathResult::NonModule(..) => + path_res.base_def(), + PathResult::NonModule(..) => { if let PathResult::Failed(span, msg, _) = self.resolve_path( None, &path, @@ -1636,14 +1683,34 @@ fn resolve_hir_path_cb(&mut self, path: &mut hir::Path, is_value: bool, error CrateLint::No, ) { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); - }, + } + Def::Err + } PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) | PathResult::Indeterminate => unreachable!(), PathResult::Failed(span, msg, _) => { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); + Def::Err } + }; + + let segments: Vec<_> = segments.iter().map(|seg| { + let mut hir_seg = hir::PathSegment::from_ident(seg.ident); + hir_seg.def = Some(self.def_map.get(&seg.id).map_or(Def::Err, |p| p.base_def())); + hir_seg + }).collect(); + hir::Path { + span, + def, + segments: segments.into(), } } + + fn new_ast_path_segment(&self, ident: Ident) -> ast::PathSegment { + let mut seg = ast::PathSegment::from_ident(ident); + seg.id = self.session.next_node_id(); + seg + } } impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { @@ -1668,15 +1735,16 @@ pub fn new(session: &'a Session, DefCollector::new(&mut definitions, Mark::root()) .collect_root(crate_name, session.local_crate_disambiguator()); - let mut extern_prelude: FxHashSet = - session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect(); + let mut extern_prelude: FxHashMap = + session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default())) + .collect(); if !attr::contains_name(&krate.attrs, "no_core") { - extern_prelude.insert(Symbol::intern("core")); + extern_prelude.insert(Ident::from_str("core"), Default::default()); if !attr::contains_name(&krate.attrs, "no_std") { - extern_prelude.insert(Symbol::intern("std")); + extern_prelude.insert(Ident::from_str("std"), Default::default()); if session.rust_2018() { - extern_prelude.insert(Symbol::intern("meta")); + extern_prelude.insert(Ident::from_str("meta"), Default::default()); } } } @@ -1963,21 +2031,10 @@ fn resolve_ident_in_lexical_scope(&mut self, } if !module.no_implicit_prelude { - if ns == TypeNS && self.extern_prelude.contains(&ident.name) { - let crate_id = if record_used { - self.crate_loader.process_path_extern(ident.name, ident.span) - } else if let Some(crate_id) = - self.crate_loader.maybe_process_path_extern(ident.name, ident.span) { - crate_id - } else { - return None; - }; - let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); - self.populate_module_if_necessary(&crate_root); - - let binding = (crate_root, ty::Visibility::Public, - ident.span, Mark::root()).to_name_binding(self.arenas); - return Some(LexicalScopeBinding::Item(binding)); + if ns == TypeNS { + if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) { + return Some(LexicalScopeBinding::Item(binding)); + } } if ns == TypeNS && is_known_tool(ident.name) { let binding = (Def::ToolMod, ty::Visibility::Public, @@ -2460,9 +2517,7 @@ fn with_optional_trait_ref(&mut self, opt_trait_ref: Option<&TraitRef>, f: let mut new_val = None; let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { - let path: Vec<_> = trait_ref.path.segments.iter() - .map(|seg| seg.ident) - .collect(); + let path: Vec<_> = Segment::from_path(&trait_ref.path); let def = self.smart_resolve_path_fragment( trait_ref.ref_id, None, @@ -2958,21 +3013,25 @@ fn smart_resolve_path_with_crate_lint( source: PathSource, crate_lint: CrateLint ) -> PathResolution { - let segments = &path.segments.iter() - .map(|seg| seg.ident) - .collect::>(); - self.smart_resolve_path_fragment(id, qself, segments, path.span, source, crate_lint) + self.smart_resolve_path_fragment( + id, + qself, + &Segment::from_path(path), + path.span, + source, + crate_lint, + ) } fn smart_resolve_path_fragment(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[Segment], span: Span, source: PathSource, crate_lint: CrateLint) -> PathResolution { - let ident_span = path.last().map_or(span, |ident| ident.span); + let ident_span = path.last().map_or(span, |ident| ident.ident.span); let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; @@ -2981,18 +3040,18 @@ fn smart_resolve_path_fragment(&mut self, let report_errors = |this: &mut Self, def: Option| { // Make the base error. let expected = source.descr_expected(); - let path_str = names_to_string(path); - let item_str = path.last().unwrap(); + let path_str = Segment::names_to_string(path); + let item_str = path.last().unwrap().ident; let code = source.error_code(def.is_some()); let (base_msg, fallback_label, base_span) = if let Some(def) = def { (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), format!("not a {}", expected), span) } else { - let item_span = path.last().unwrap().span; + let item_span = path.last().unwrap().ident.span; let (mod_prefix, mod_str) = if path.len() == 1 { (String::new(), "this scope".to_string()) - } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() { + } else if path.len() == 2 && path[0].ident.name == keywords::CrateRoot.name() { (String::new(), "the crate root".to_string()) } else { let mod_path = &path[..path.len() - 1]; @@ -3002,7 +3061,7 @@ fn smart_resolve_path_fragment(&mut self, module.def(), _ => None, }.map_or(String::new(), |def| format!("{} ", def.kind_name())); - (mod_prefix, format!("`{}`", names_to_string(mod_path))) + (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path))) }; (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), format!("not found in {}", mod_str), @@ -3013,7 +3072,7 @@ fn smart_resolve_path_fragment(&mut self, // Emit help message for fake-self from other languages like `this`(javascript) if ["this", "my"].contains(&&*item_str.as_str()) - && this.self_value_is_available(path[0].span, span) { + && this.self_value_is_available(path[0].ident.span, span) { err.span_suggestion_with_applicability( span, "did you mean", @@ -3048,7 +3107,7 @@ fn smart_resolve_path_fragment(&mut self, } // Try to lookup the name in more relaxed fashion for better error reporting. - let ident = *path.last().unwrap(); + let ident = path.last().unwrap().ident; let candidates = this.lookup_import_candidates(ident.name, ns, is_expected); if candidates.is_empty() && is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = @@ -3075,7 +3134,7 @@ fn smart_resolve_path_fragment(&mut self, } if path.len() == 1 && this.self_type_is_available(span) { if let Some(candidate) = this.lookup_assoc_candidate(ident, ns, is_expected) { - let self_is_available = this.self_value_is_available(path[0].span, span); + let self_is_available = this.self_value_is_available(path[0].ident.span, span); match candidate { AssocSuggestion::Field => { err.span_suggestion_with_applicability( @@ -3310,7 +3369,7 @@ fn smart_resolve_path_fragment(&mut self, // or `::A::B`. If `B` should be resolved in value namespace then // it needs to be added to the trait map. if ns == ValueNS { - let item_name = *path.last().unwrap(); + let item_name = path.last().unwrap().ident; let traits = self.get_traits_containing_item(item_name, ns); self.trait_map.insert(id, traits); } @@ -3380,7 +3439,7 @@ fn self_value_is_available(&mut self, self_span: Span, path_span: Span) -> bool fn resolve_qpath_anywhere(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[Segment], primary_ns: Namespace, span: Span, defer_to_typeck: bool, @@ -3402,10 +3461,10 @@ fn resolve_qpath_anywhere(&mut self, } } if primary_ns != MacroNS && - (self.macro_names.contains(&path[0].modern()) || - self.builtin_macros.get(&path[0].name).cloned() + (self.macro_names.contains(&path[0].ident.modern()) || + self.builtin_macros.get(&path[0].ident.name).cloned() .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang) || - self.macro_use_prelude.get(&path[0].name).cloned() + self.macro_use_prelude.get(&path[0].ident.name).cloned() .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) { // Return some dummy definition, it's enough for error reporting. return Some( @@ -3419,7 +3478,7 @@ fn resolve_qpath_anywhere(&mut self, fn resolve_qpath(&mut self, id: NodeId, qself: Option<&QSelf>, - path: &[Ident], + path: &[Segment], ns: Namespace, span: Span, global_by_default: bool, @@ -3509,8 +3568,8 @@ fn resolve_qpath(&mut self, PathResult::Failed(..) if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types - .contains_key(&path[0].name) => { - let prim = self.primitive_type_table.primitive_types[&path[0].name]; + .contains_key(&path[0].ident.name) => { + let prim = self.primitive_type_table.primitive_types[&path[0].ident.name]; PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) } PathResult::Module(ModuleOrUniformRoot::Module(module)) => @@ -3525,8 +3584,8 @@ fn resolve_qpath(&mut self, }; if path.len() > 1 && !global_by_default && result.base_def() != Def::Err && - path[0].name != keywords::CrateRoot.name() && - path[0].name != keywords::DollarCrate.name() { + path[0].ident.name != keywords::CrateRoot.name() && + path[0].ident.name != keywords::DollarCrate.name() { let unqualified_result = { match self.resolve_path( None, @@ -3554,7 +3613,7 @@ fn resolve_qpath(&mut self, fn resolve_path( &mut self, base_module: Option>, - path: &[Ident], + path: &[Segment], opt_ns: Option, // `None` indicates a module path record_used: bool, path_span: Span, @@ -3568,7 +3627,7 @@ fn resolve_path( fn resolve_path_with_parent_scope( &mut self, base_module: Option>, - path: &[Ident], + path: &[Segment], opt_ns: Option, // `None` indicates a module path parent_scope: &ParentScope<'a>, record_used: bool, @@ -3590,8 +3649,9 @@ fn resolve_path_with_parent_scope( crate_lint, ); - for (i, &ident) in path.iter().enumerate() { + for (i, &Segment { ident, id }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?}", i, ident); + let is_last = i == path.len() - 1; let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; let name = ident.name; @@ -3651,7 +3711,7 @@ fn resolve_path_with_parent_scope( } else { format!("`{}`", name) }; - let msg = if i == 1 && path[0].name == keywords::CrateRoot.name() { + let msg = if i == 1 && path[0].ident.name == keywords::CrateRoot.name() { format!("global paths cannot start with {}", name_str) } else { format!("{} in paths can only be used in start position", name_str) @@ -3691,6 +3751,14 @@ fn resolve_path_with_parent_scope( let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def); if let Some(next_module) = binding.module() { module = Some(ModuleOrUniformRoot::Module(next_module)); + if record_used { + if let Some(id) = id { + if !self.def_map.contains_key(&id) { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + self.record_def(id, PathResolution::new(def)); + } + } + } } else if def == Def::ToolMod && i + 1 != path.len() { let def = Def::NonMacroAttr(NonMacroAttrKind::Tool); return PathResult::NonModule(PathResolution::new(def)); @@ -3740,7 +3808,7 @@ fn resolve_path_with_parent_scope( } else if i == 0 { format!("Use of undeclared type or module `{}`", ident) } else { - format!("Could not find `{}` in `{}`", ident, path[i - 1]) + format!("Could not find `{}` in `{}`", ident, path[i - 1].ident) }; return PathResult::Failed(ident.span, msg, is_last); } @@ -3758,7 +3826,7 @@ fn resolve_path_with_parent_scope( fn lint_if_path_starts_with_module( &self, crate_lint: CrateLint, - path: &[Ident], + path: &[Segment], path_span: Span, second_binding: Option<&NameBinding>, ) { @@ -3775,7 +3843,7 @@ fn lint_if_path_starts_with_module( }; let first_name = match path.get(0) { - Some(ident) => ident.name, + Some(ident) => ident.ident.name, None => return, }; @@ -3787,7 +3855,7 @@ fn lint_if_path_starts_with_module( match path.get(1) { // If this import looks like `crate::...` it's already good - Some(ident) if ident.name == keywords::Crate.name() => return, + Some(Segment { ident, .. }) if ident.name == keywords::Crate.name() => return, // Otherwise go below to see if it's an extern crate Some(_) => {} // If the path has length one (and it's `CrateRoot` most likely) @@ -3980,7 +4048,7 @@ fn extract_node_id(t: &Ty) -> Option { } fn lookup_typo_candidate(&mut self, - path: &[Ident], + path: &[Segment], ns: Namespace, filter_fn: FilterFn, span: Span) @@ -4018,7 +4086,7 @@ fn lookup_typo_candidate(&mut self, } else { // Items from the prelude if !module.no_implicit_prelude { - names.extend(self.extern_prelude.iter().cloned()); + names.extend(self.extern_prelude.iter().map(|(ident, _)| ident.name)); if let Some(prelude) = self.prelude { add_module_candidates(prelude, &mut names); } @@ -4044,7 +4112,7 @@ fn lookup_typo_candidate(&mut self, } } - let name = path[path.len() - 1].name; + let name = path[path.len() - 1].ident.name; // Make sure error reporting is deterministic. names.sort_by_cached_key(|name| name.as_str()); match find_best_match_for_name(names.iter(), &name.as_str(), None) { @@ -4459,11 +4527,9 @@ fn lookup_import_candidates(&mut self, if self.session.rust_2018() { let extern_prelude_names = self.extern_prelude.clone(); - for &name in extern_prelude_names.iter() { - let ident = Ident::with_empty_ctxt(name); - if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(name, - ident.span) - { + for (ident, _) in extern_prelude_names.into_iter() { + if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name, + ident.span) { let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX, @@ -4563,7 +4629,7 @@ fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility { ast::VisibilityKind::Restricted { ref path, id, .. } => { // Visibilities are resolved as global by default, add starting root segment. let segments = path.make_root().iter().chain(path.segments.iter()) - .map(|seg| seg.ident) + .map(|seg| Segment { ident: seg.ident, id: Some(seg.id) }) .collect::>(); let def = self.smart_resolve_path_fragment( id, @@ -4825,14 +4891,43 @@ fn report_conflict<'b>(&mut self, err.emit(); self.name_already_seen.insert(name, span); } + + fn extern_prelude_get(&mut self, ident: Ident, speculative: bool, skip_feature_gate: bool) + -> Option<&'a NameBinding<'a>> { + self.extern_prelude.get(&ident.modern()).cloned().and_then(|entry| { + if let Some(binding) = entry.extern_crate_item { + if !speculative && !skip_feature_gate && entry.introduced_by_item && + !self.session.features_untracked().extern_crate_item_prelude { + emit_feature_err(&self.session.parse_sess, "extern_crate_item_prelude", + ident.span, GateIssue::Language, + "use of extern prelude names introduced \ + with `extern crate` items is unstable"); + } + Some(binding) + } else { + let crate_id = if !speculative { + self.crate_loader.process_path_extern(ident.name, ident.span) + } else if let Some(crate_id) = + self.crate_loader.maybe_process_path_extern(ident.name, ident.span) { + crate_id + } else { + return None; + }; + let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); + self.populate_module_if_necessary(&crate_root); + Some((crate_root, ty::Visibility::Public, ident.span, Mark::root()) + .to_name_binding(self.arenas)) + } + }) + } } -fn is_self_type(path: &[Ident], namespace: Namespace) -> bool { - namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name() +fn is_self_type(path: &[Segment], namespace: Namespace) -> bool { + namespace == TypeNS && path.len() == 1 && path[0].ident.name == keywords::SelfType.name() } -fn is_self_value(path: &[Ident], namespace: Namespace) -> bool { - namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name() +fn is_self_value(path: &[Segment], namespace: Namespace) -> bool { + namespace == ValueNS && path.len() == 1 && path[0].ident.name == keywords::SelfValue.name() } fn names_to_string(idents: &[Ident]) -> String { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 28284a45bcd..68b3a6be292 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -9,7 +9,7 @@ // except according to those terms. use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error}; -use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding}; +use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding}; use ModuleOrUniformRoot; use Namespace::{self, *}; use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; @@ -461,14 +461,15 @@ pub fn resolve_macro_to_def_inner( parent_scope: &ParentScope<'a>, force: bool, ) -> Result { - let ast::Path { ref segments, span } = *path; - let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect(); + let span = path.span; + let mut path = Segment::from_path(path); // Possibly apply the macro helper hack if kind == MacroKind::Bang && path.len() == 1 && - path[0].span.ctxt().outer().expn_info().map_or(false, |info| info.local_inner_macros) { - let root = Ident::new(keywords::DollarCrate.name(), path[0].span); - path.insert(0, root); + path[0].ident.span.ctxt().outer().expn_info() + .map_or(false, |info| info.local_inner_macros) { + let root = Ident::new(keywords::DollarCrate.name(), path[0].ident.span); + path.insert(0, Segment::from_ident(root)); } if path.len() > 1 { @@ -496,12 +497,16 @@ pub fn resolve_macro_to_def_inner( }; parent_scope.module.macro_resolutions.borrow_mut() - .push((path.into_boxed_slice(), span)); + .push((path + .iter() + .map(|seg| seg.ident) + .collect::>() + .into_boxed_slice(), span)); def } else { let binding = self.early_resolve_ident_in_lexical_scope( - path[0], MacroNS, Some(kind), parent_scope, false, force, span + path[0].ident, MacroNS, Some(kind), parent_scope, false, force, span ); match binding { Ok(..) => {} @@ -510,7 +515,7 @@ pub fn resolve_macro_to_def_inner( } parent_scope.module.legacy_macro_resolutions.borrow_mut() - .push((path[0], kind, parent_scope.clone(), binding.ok())); + .push((path[0].ident, kind, parent_scope.clone(), binding.ok())); binding.map(|binding| binding.def_ignoring_ambiguity()) } @@ -691,19 +696,14 @@ struct Flags: u8 { } } WhereToResolve::ExternPrelude => { - if use_prelude && self.extern_prelude.contains(&ident.name) { - let crate_id = - self.crate_loader.process_path_extern(ident.name, ident.span); - let crate_root = - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); - self.populate_module_if_necessary(crate_root); - - let binding = (crate_root, ty::Visibility::Public, - ident.span, Mark::root()).to_name_binding(self.arenas); - Ok((binding, Flags::PRELUDE, Flags::empty())) - } else { - Err(Determinacy::Determined) + let mut result = Err(Determinacy::Determined); + if use_prelude { + if let Some(binding) = self.extern_prelude_get(ident, !record_used, + innermost_result.is_some()) { + result = Ok((binding, Flags::PRELUDE, Flags::empty())); + } } + result } WhereToResolve::ToolPrelude => { if use_prelude && is_known_tool(ident.name) { @@ -851,6 +851,7 @@ macro_rules! continue_search { () => { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; for &(ref path, span) in module.macro_resolutions.borrow().iter() { + let path: Vec<_> = path.iter().map(|&ident| Segment::from_ident(ident)).collect(); match self.resolve_path(None, &path, Some(MacroNS), true, span, CrateLint::No) { PathResult::NonModule(_) => {}, PathResult::Failed(span, msg, _) => { @@ -943,7 +944,7 @@ fn suggest_macro_name(&mut self, name: &str, kind: MacroKind, } }; let ident = Ident::new(Symbol::intern(name), span); - self.lookup_typo_candidate(&[ident], MacroNS, is_macro, span) + self.lookup_typo_candidate(&[Segment::from_ident(ident)], MacroNS, is_macro, span) }); if let Some(suggestion) = suggestion { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 27ba1ced749..810aff7f9b0 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -13,7 +13,7 @@ use {AmbiguityError, CrateLint, Module, ModuleOrUniformRoot, PerNS}; use Namespace::{self, TypeNS, MacroNS}; use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; -use Resolver; +use {Resolver, Segment}; use {names_to_string, module_to_string}; use {resolve_error, ResolutionError}; @@ -21,7 +21,7 @@ use rustc::ty; use rustc::lint::builtin::BuiltinLintDiagnostics; use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE}; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::DefId; use rustc::hir::def::*; use rustc::session::DiagnosticMessageId; use rustc::util::nodemap::FxHashSet; @@ -89,7 +89,7 @@ pub struct ImportDirective<'a> { pub root_span: Span, pub parent: Module<'a>, - pub module_path: Vec, + pub module_path: Vec, /// The resolution of `module_path`. pub imported_module: Cell>>, pub subclass: ImportDirectiveSubclass<'a>, @@ -202,7 +202,7 @@ pub fn resolve_ident_in_module_unadjusted(&mut self, if !( ns == TypeNS && !ident.is_path_segment_keyword() && - self.extern_prelude.contains(&ident.name) + self.extern_prelude.contains_key(&ident.modern()) ) { // ... unless the crate name is not in the `extern_prelude`. return binding; @@ -220,12 +220,15 @@ pub fn resolve_ident_in_module_unadjusted(&mut self, self.resolve_crate_root(ident) } else if ns == TypeNS && - !ident.is_path_segment_keyword() && - self.extern_prelude.contains(&ident.name) + !ident.is_path_segment_keyword() { - let crate_id = - self.crate_loader.process_path_extern(ident.name, ident.span); - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) + if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) { + let module = self.get_module(binding.def().def_id()); + self.populate_module_if_necessary(module); + return Ok(binding); + } else { + return Err(Determined); + } } else { return Err(Determined); }; @@ -390,7 +393,7 @@ pub fn resolve_ident_in_module_unadjusted(&mut self, // Add an import directive to the current module. pub fn add_import_directive(&mut self, - module_path: Vec, + module_path: Vec, subclass: ImportDirectiveSubclass<'a>, span: Span, id: NodeId, @@ -676,7 +679,7 @@ struct UniformPathsCanaryResults<'a> { let has_explicit_self = !import.module_path.is_empty() && - import.module_path[0].name == keywords::SelfValue.name(); + import.module_path[0].ident.name == keywords::SelfValue.name(); self.per_ns(|_, ns| { if let Some(result) = result[ns].get().ok() { @@ -725,9 +728,11 @@ struct UniformPathsCanaryResults<'a> { self.throw_unresolved_import_error(empty_vec, None); } if !seen_spans.contains(&span) { - let path = import_path_to_string(&import.module_path[..], - &import.subclass, - span); + let path = import_path_to_string( + &import.module_path.iter().map(|seg| seg.ident).collect::>(), + &import.subclass, + span, + ); error_vec.push((span, path, err)); seen_spans.insert(span); prev_root_id = import.root_id; @@ -738,10 +743,9 @@ struct UniformPathsCanaryResults<'a> { let uniform_paths_feature = self.session.features_untracked().uniform_paths; for ((span, _, ns), results) in uniform_paths_canaries { let name = results.name; - let external_crate = if ns == TypeNS && self.extern_prelude.contains(&name) { - let crate_id = - self.crate_loader.process_path_extern(name, span); - Some(Def::Mod(DefId { krate: crate_id, index: CRATE_DEF_INDEX })) + let external_crate = if ns == TypeNS { + self.extern_prelude_get(Ident::with_empty_ctxt(name), true, false) + .map(|binding| binding.def()) } else { None }; @@ -849,9 +853,10 @@ fn throw_unresolved_import_error(&self, error_vec: Vec<(Span, String, String)>, /// If successful, the resolved bindings are written into the module. fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool { debug!("(resolving import for module) resolving import `{}::...` in `{}`", - names_to_string(&directive.module_path[..]), + Segment::names_to_string(&directive.module_path[..]), module_to_string(self.current_module).unwrap_or_else(|| "???".to_string())); + self.current_module = directive.parent; let module = if let Some(module) = directive.imported_module.get() { @@ -964,7 +969,7 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa ) { Some(( span, - format!("Did you mean `{}`?", names_to_string(&suggested_path[..])) + format!("Did you mean `{}`?", Segment::names_to_string(&suggested_path)) )) } else { Some((span, msg)) @@ -980,7 +985,7 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = module_path.clone(); - full_path.push(keywords::Invalid.ident()); + full_path.push(Segment::from_ident(keywords::Invalid.ident())); self.lint_if_path_starts_with_module( directive.crate_lint(), &full_path, @@ -1021,6 +1026,13 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa Some(this.dummy_binding); } } + if record_used && ns == TypeNS { + if let ModuleOrUniformRoot::UniformRoot(..) = module { + // Make sure single-segment import is resolved non-speculatively + // at least once to report the feature error. + this.extern_prelude_get(ident, false, false); + } + } } }); @@ -1137,7 +1149,7 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa // HACK(eddyb) `lint_if_path_starts_with_module` needs at least // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = module_path.clone(); - full_path.push(ident); + full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { if let Ok(binding) = result[ns].get() { this.lint_if_path_starts_with_module( @@ -1279,7 +1291,7 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) { let resolutions = imported_module.parent.expect("parent should exist") .resolutions.borrow(); let enum_path_segment_index = directive.module_path.len() - 1; - let enum_ident = directive.module_path[enum_path_segment_index]; + let enum_ident = directive.module_path[enum_path_segment_index].ident; let enum_resolution = resolutions.get(&(enum_ident, TypeNS)) .expect("resolution should exist"); diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 97bdb9e5fa3..a7fe1bb421c 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -34,12 +34,10 @@ use syntax::ast::{self, Attribute, NodeId, PatKind, CRATE_NODE_ID}; use syntax::parse::token; -use syntax::symbol::keywords; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ bounds_to_string, generic_params_to_string, - path_to_string, ty_to_string }; use syntax::ptr::P; @@ -219,95 +217,21 @@ pub fn dump_compilation_options(&mut self, input: &Input, crate_name: &str) { self.dumper.compilation_opts(data); } - // Return all non-empty prefixes of a path. - // For each prefix, we return the span for the last segment in the prefix and - // a str representation of the entire prefix. - fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> { - let segments = &path.segments[if path.is_global() { 1 } else { 0 }..]; - - let mut result = Vec::with_capacity(segments.len()); - let mut segs = Vec::with_capacity(segments.len()); - - for (i, seg) in segments.iter().enumerate() { - segs.push(seg.clone()); - let sub_path = ast::Path { - span: seg.ident.span, // span for the last segment - segments: segs, - }; - let qualname = if i == 0 && path.is_global() { - format!("::{}", path_to_string(&sub_path)) - } else { - path_to_string(&sub_path) - }; - result.push((seg.ident.span, qualname)); - segs = sub_path.segments; - } - - result - } - fn write_sub_paths(&mut self, path: &ast::Path) { - let sub_paths = self.process_path_prefixes(path); - for (span, _) in sub_paths { - let span = self.span_from_span(span); - self.dumper.dump_ref(Ref { - kind: RefKind::Mod, - span, - ref_id: ::null_id(), - }); + for seg in &path.segments { + if let Some(data) = self.save_ctxt.get_path_segment_data(seg) { + self.dumper.dump_ref(data); + } } } // As write_sub_paths, but does not process the last ident in the path (assuming it // will be processed elsewhere). See note on write_sub_paths about global. fn write_sub_paths_truncated(&mut self, path: &ast::Path) { - let sub_paths = self.process_path_prefixes(path); - let len = sub_paths.len(); - if len <= 1 { - return; - } - - for (span, _) in sub_paths.into_iter().take(len - 1) { - let span = self.span_from_span(span); - self.dumper.dump_ref(Ref { - kind: RefKind::Mod, - span, - ref_id: ::null_id(), - }); - } - } - - // As write_sub_paths, but expects a path of the form module_path::trait::method - // Where trait could actually be a struct too. - fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) { - let sub_paths = self.process_path_prefixes(path); - let len = sub_paths.len(); - if len <= 1 { - return; - } - let sub_paths = &sub_paths[..(len - 1)]; - - // write the trait part of the sub-path - let (ref span, _) = sub_paths[len - 2]; - let span = self.span_from_span(*span); - self.dumper.dump_ref(Ref { - kind: RefKind::Type, - ref_id: ::null_id(), - span, - }); - - // write the other sub-paths - if len <= 2 { - return; - } - let sub_paths = &sub_paths[..len - 2]; - for &(ref span, _) in sub_paths { - let span = self.span_from_span(*span); - self.dumper.dump_ref(Ref { - kind: RefKind::Mod, - span, - ref_id: ::null_id(), - }); + for seg in &path.segments[..path.segments.len() - 1] { + if let Some(data) = self.save_ctxt.get_path_segment_data(seg) { + self.dumper.dump_ref(data); + } } } @@ -323,7 +247,6 @@ fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { self.visit_pat(&arg.pat); let mut collector = PathCollector::new(); collector.visit_pat(&arg.pat); - let span_utils = self.span.clone(); for (id, ident, ..) in collector.collected_idents { let hir_id = self.tcx.hir.node_to_hir_id(id); @@ -331,10 +254,9 @@ fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { Some(s) => s.to_string(), None => continue, }; - let sub_span = span_utils.span_for_last_ident(ident.span); - if !self.span.filter_generated(sub_span, ident.span) { + if !self.span.filter_generated(ident.span) { let id = ::id_from_node_id(id, &self.save_ctxt); - let span = self.span_from_span(sub_span.expect("No span found for variable")); + let span = self.span_from_span(ident.span); self.dumper.dump_def( &Access { @@ -373,7 +295,7 @@ fn process_method( ) { debug!("process_method: {}:{}", id, ident); - if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident.name, span) { + if let Some(mut method_data) = self.save_ctxt.get_method_data(id, ident, span) { let sig_str = ::make_signature(&sig.decl, &generics); if body.is_some() { self.nest_tables( @@ -382,7 +304,7 @@ fn process_method( ); } - self.process_generic_params(&generics, span, &method_data.qualname, id); + self.process_generic_params(&generics, &method_data.qualname, id); method_data.value = sig_str; method_data.sig = sig::method_signature(id, ident, generics, sig, &self.save_ctxt); @@ -415,7 +337,6 @@ fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: Node fn process_generic_params( &mut self, generics: &'l ast::Generics, - full_span: Span, prefix: &str, id: NodeId, ) { @@ -427,7 +348,7 @@ fn process_generic_params( let name = escape(self.span.snippet(param_ss)); // Append $id to name to make sure each one is unique. let qualname = format!("{}::{}${}", prefix, name, id); - if !self.span.filter_generated(Some(param_ss), full_span) { + if !self.span.filter_generated(param_ss) { let id = ::id_from_node_id(param.id, &self.save_ctxt); let span = self.span_from_span(param_ss); @@ -471,7 +392,7 @@ fn process_fn( item.id, |v| v.process_formals(&decl.inputs, &fn_data.qualname), ); - self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); + self.process_generic_params(ty_params, &fn_data.qualname, item.id); self.dumper.dump_def(&access_from!(self.save_ctxt, item), fn_data); } @@ -505,8 +426,7 @@ fn process_static_or_const_item( fn process_assoc_const( &mut self, id: ast::NodeId, - name: ast::Name, - span: Span, + ident: ast::Ident, typ: &'l ast::Ty, expr: Option<&'l ast::Expr>, parent_id: DefId, @@ -515,11 +435,9 @@ fn process_assoc_const( ) { let qualname = format!("::{}", self.tcx.node_path_str(id)); - let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); - - if !self.span.filter_generated(sub_span, span) { - let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt); - let span = self.span_from_span(sub_span.expect("No span found for variable")); + if !self.span.filter_generated(ident.span) { + let sig = sig::assoc_const_signature(id, ident.name, typ, expr, &self.save_ctxt); + let span = self.span_from_span(ident.span); self.dumper.dump_def( &access_from!(self.save_ctxt, vis, id), @@ -527,7 +445,7 @@ fn process_assoc_const( kind: DefKind::Const, id: ::id_from_node_id(id, &self.save_ctxt), span, - name: name.to_string(), + name: ident.name.to_string(), qualname, value: ty_to_string(&typ), parent: Some(::id_from_def_id(parent_id)), @@ -558,13 +476,12 @@ fn process_struct( let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - let (kind, keyword) = match item.node { - ast::ItemKind::Struct(_, _) => (DefKind::Struct, keywords::Struct), - ast::ItemKind::Union(_, _) => (DefKind::Union, keywords::Union), + let kind = match item.node { + ast::ItemKind::Struct(_, _) => DefKind::Struct, + ast::ItemKind::Union(_, _) => DefKind::Union, _ => unreachable!(), }; - let sub_span = self.span.sub_span_after_keyword(item.span, keyword); let (value, fields) = match item.node { ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) | ast::ItemKind::Union(ast::VariantData::Struct(ref fields, _), _) => { @@ -595,8 +512,8 @@ fn process_struct( _ => (String::new(), vec![]), }; - if !self.span.filter_generated(sub_span, item.span) { - let span = self.span_from_span(sub_span.expect("No span found for struct")); + if !self.span.filter_generated(item.ident.span) { + let span = self.span_from_span(item.ident.span); self.dumper.dump_def( &access_from!(self.save_ctxt, item), Def { @@ -621,7 +538,7 @@ fn process_struct( self.visit_ty(&field.ty); } - self.process_generic_params(ty_params, item.span, &qualname, item.id); + self.process_generic_params(ty_params, &qualname, item.id); } fn process_enum( @@ -642,10 +559,10 @@ fn process_enum( for variant in &enum_definition.variants { let name = variant.node.ident.name.to_string(); let qualname = format!("{}::{}", enum_data.qualname, name); + let name_span = variant.node.ident.span; match variant.node.data { ast::VariantData::Struct(ref fields, _) => { - let sub_span = self.span.span_for_first_ident(variant.span); let fields_str = fields .iter() .enumerate() @@ -655,9 +572,8 @@ fn process_enum( .collect::>() .join(", "); let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); - if !self.span.filter_generated(sub_span, variant.span) { - let span = self - .span_from_span(sub_span.expect("No span found for struct variant")); + if !self.span.filter_generated(name_span) { + let span = self.span_from_span(name_span); let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt); let parent = Some(::id_from_node_id(item.id, &self.save_ctxt)); @@ -684,7 +600,6 @@ fn process_enum( } } ref v => { - let sub_span = self.span.span_for_first_ident(variant.span); let mut value = format!("{}::{}", enum_data.name, name); if let &ast::VariantData::Tuple(ref fields, _) = v { value.push('('); @@ -695,9 +610,8 @@ fn process_enum( .join(", ")); value.push(')'); } - if !self.span.filter_generated(sub_span, variant.span) { - let span = - self.span_from_span(sub_span.expect("No span found for tuple variant")); + if !self.span.filter_generated(name_span) { + let span = self.span_from_span(name_span); let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt); let parent = Some(::id_from_node_id(item.id, &self.save_ctxt)); @@ -731,7 +645,7 @@ fn process_enum( self.visit_ty(&field.ty); } } - self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id); + self.process_generic_params(ty_params, &enum_data.qualname, item.id); self.dumper.dump_def(&access, enum_data); } @@ -755,7 +669,7 @@ fn process_impl( if let &Some(ref trait_ref) = trait_ref { self.process_path(trait_ref.ref_id, &trait_ref.path); } - self.process_generic_params(type_parameters, item.span, "", item.id); + self.process_generic_params(type_parameters, "", item.id); for impl_item in impl_items { let map = &self.tcx.hir; self.process_impl_item(impl_item, map.local_def_id(item.id)); @@ -779,10 +693,9 @@ fn process_trait( val.push_str(": "); val.push_str(&bounds_to_string(trait_refs)); } - let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait); - if !self.span.filter_generated(sub_span, item.span) { + if !self.span.filter_generated(item.ident.span) { let id = ::id_from_node_id(item.id, &self.save_ctxt); - let span = self.span_from_span(sub_span.expect("No span found for trait")); + let span = self.span_from_span(item.ident.span); let children = methods .iter() .map(|i| ::id_from_node_id(i.id, &self.save_ctxt)) @@ -815,21 +728,18 @@ fn process_trait( let trait_ref = &trait_ref.trait_ref; if let Some(id) = self.lookup_def_id(trait_ref.ref_id) { - let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); - if !self.span.filter_generated(sub_span, trait_ref.path.span) { - let span = self.span_from_span(sub_span.expect("No span found for trait ref")); + let sub_span = trait_ref.path.segments.last().unwrap().ident.span; + if !self.span.filter_generated(sub_span) { + let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { kind: RefKind::Type, - span, + span: span.clone(), ref_id: ::id_from_def_id(id), }); - } - if !self.span.filter_generated(sub_span, trait_ref.path.span) { - let sub_span = self.span_from_span(sub_span.expect("No span for inheritance")); self.dumper.dump_relation(Relation { kind: RelationKind::SuperTrait, - span: sub_span, + span, from: ::id_from_def_id(id), to: ::id_from_node_id(item.id, &self.save_ctxt), }); @@ -838,7 +748,7 @@ fn process_trait( } // walk generics and methods - self.process_generic_params(generics, item.span, &qualname, item.id); + self.process_generic_params(generics, &qualname, item.id); for method in methods { let map = &self.tcx.hir; self.process_trait_item(method, map.local_def_id(item.id)) @@ -891,29 +801,7 @@ fn process_path(&mut self, id: NodeId, path: &'l ast::Path) { } } - // Modules or types in the path prefix. - match self.save_ctxt.get_path_def(id) { - HirDef::Method(did) => { - let ti = self.tcx.associated_item(did); - if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument { - self.write_sub_path_trait_truncated(path); - } - } - HirDef::Fn(..) | - HirDef::Const(..) | - HirDef::Static(..) | - HirDef::StructCtor(..) | - HirDef::VariantCtor(..) | - HirDef::AssociatedConst(..) | - HirDef::Local(..) | - HirDef::Upvar(..) | - HirDef::Struct(..) | - HirDef::Union(..) | - HirDef::Variant(..) | - HirDef::TyAlias(..) | - HirDef::AssociatedTy(..) => self.write_sub_paths_truncated(path), - _ => {} - } + self.write_sub_paths_truncated(path); } fn process_struct_lit( @@ -924,9 +812,8 @@ fn process_struct_lit( variant: &'l ty::VariantDef, base: &'l Option>, ) { - self.write_sub_paths_truncated(path); - if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { + self.write_sub_paths_truncated(path); down_cast_data!(struct_lit_data, RefData, ex.span); if !generated_code(ex.span) { self.dumper.dump_ref(struct_lit_data); @@ -988,12 +875,10 @@ fn process_pat(&mut self, p: &'l ast::Pat) { }; let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id)); - for &Spanned { node: ref field, span } in fields { - let sub_span = self.span.span_for_first_ident(span); + for &Spanned { node: ref field, .. } in fields { if let Some(index) = self.tcx.find_field_index(field.ident, variant) { - if !self.span.filter_generated(sub_span, span) { - let span = - self.span_from_span(sub_span.expect("No span fund for var ref")); + if !self.span.filter_generated(field.ident.span) { + let span = self.span_from_span(field.ident.span); self.dumper.dump_ref(Ref { kind: RefKind::Variable, span, @@ -1034,7 +919,7 @@ fn process_var_decl_multi(&mut self, pats: &'l [P]) { value.push_str(": "); value.push_str(&typ); - if !self.span.filter_generated(Some(ident.span), ident.span) { + if !self.span.filter_generated(ident.span) { let qualname = format!("{}${}", ident.to_string(), id); let id = ::id_from_node_id(id, &self.save_ctxt); let span = self.span_from_span(ident.span); @@ -1109,14 +994,11 @@ fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) { None => String::new(), }; - // Get the span only for the name of the variable (I hope the path - // is only ever a variable name, but who knows?). - let sub_span = self.span.span_for_last_ident(ident.span); // Rust uses the id of the pattern for var lookups, so we'll use it too. - if !self.span.filter_generated(sub_span, ident.span) { + if !self.span.filter_generated(ident.span) { let qualname = format!("{}${}", ident.to_string(), id); let id = ::id_from_node_id(id, &self.save_ctxt); - let span = self.span_from_span(sub_span.expect("No span found for variable")); + let span = self.span_from_span(ident.span); self.dumper.dump_def( &Access { @@ -1190,8 +1072,7 @@ fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId ast::TraitItemKind::Const(ref ty, ref expr) => { self.process_assoc_const( trait_item.id, - trait_item.ident.name, - trait_item.span, + trait_item.ident, &ty, expr.as_ref().map(|e| &**e), trait_id, @@ -1214,11 +1095,9 @@ fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId // FIXME do something with _bounds (for type refs) let name = trait_item.ident.name.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); - let sub_span = self.span - .sub_span_after_keyword(trait_item.span, keywords::Type); - if !self.span.filter_generated(sub_span, trait_item.span) { - let span = self.span_from_span(sub_span.expect("No span found for assoc type")); + if !self.span.filter_generated(trait_item.ident.span) { + let span = self.span_from_span(trait_item.ident.span); let id = ::id_from_node_id(trait_item.id, &self.save_ctxt); self.dumper.dump_def( @@ -1263,8 +1142,7 @@ fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) { ast::ImplItemKind::Const(ref ty, ref expr) => { self.process_assoc_const( impl_item.id, - impl_item.ident.name, - impl_item.span, + impl_item.ident, &ty, Some(expr), impl_id, @@ -1328,7 +1206,7 @@ fn process_use_tree(&mut self, .map(::id_from_def_id); match use_tree.kind { - ast::UseTreeKind::Simple(..) => { + ast::UseTreeKind::Simple(alias, ..) => { let ident = use_tree.ident(); let path = ast::Path { segments: prefix.segments @@ -1339,24 +1217,22 @@ fn process_use_tree(&mut self, span: path.span, }; - let sub_span = self.span.span_for_last_ident(path.span); - let alias_span = self.span.sub_span_after_keyword(use_tree.span, keywords::As); - let ref_id = self.lookup_def_id(id); - - if !self.span.filter_generated(sub_span, path.span) { - let span = self.span_from_span(sub_span.expect("No span found for use")); - let alias_span = alias_span.map(|sp| self.span_from_span(sp)); + let sub_span = path.segments.last().unwrap().ident.span; + if !self.span.filter_generated(sub_span) { + let ref_id = self.lookup_def_id(id).map(|id| ::id_from_def_id(id)); + let alias_span = alias.map(|i| self.span_from_span(i.span)); + let span = self.span_from_span(sub_span); self.dumper.import(&access, Import { kind: ImportKind::Use, - ref_id: ref_id.map(|id| ::id_from_def_id(id)), + ref_id, span, alias_span, name: ident.to_string(), value: String::new(), parent, }); + self.write_sub_paths_truncated(&path); } - self.write_sub_paths_truncated(&path); } ast::UseTreeKind::Glob => { let path = ast::Path { @@ -1377,9 +1253,9 @@ fn process_use_tree(&mut self, Vec::new() }; - let sub_span = self.span.sub_span_of_token(use_tree.span, - token::BinOp(token::Star)); - if !self.span.filter_generated(sub_span, use_tree.span) { + let sub_span = + self.span.sub_span_of_token(use_tree.span, token::BinOp(token::Star)); + if !self.span.filter_generated(use_tree.span) { let span = self.span_from_span(sub_span.expect("No span found for use glob")); self.dumper.import(&access, Import { @@ -1391,8 +1267,8 @@ fn process_use_tree(&mut self, value: names.join(", "), parent, }); + self.write_sub_paths(&path); } - self.write_sub_paths(&path); } ast::UseTreeKind::Nested(ref nested_items) => { let prefix = ast::Path { @@ -1471,11 +1347,9 @@ fn visit_item(&mut self, item: &'l ast::Item) { self.process_use_tree(use_tree, item.id, item, &prefix); } ExternCrate(_) => { - let alias_span = self.span.span_for_last_ident(item.span); - - if !self.span.filter_generated(alias_span, item.span) { - let span = - self.span_from_span(alias_span.expect("No span found for extern crate")); + let name_span = item.ident.span; + if !self.span.filter_generated(name_span) { + let span = self.span_from_span(name_span); let parent = self.save_ctxt.tcx.hir.opt_local_def_id(item.id) .and_then(|id| self.save_ctxt.tcx.parent_def_id(id)) .map(::id_from_def_id); @@ -1518,9 +1392,8 @@ fn visit_item(&mut self, item: &'l ast::Item) { Ty(ref ty, ref ty_params) => { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let value = ty_to_string(&ty); - let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); - if !self.span.filter_generated(sub_span, item.span) { - let span = self.span_from_span(sub_span.expect("No span found for typedef")); + if !self.span.filter_generated(item.ident.span) { + let span = self.span_from_span(item.ident.span); let id = ::id_from_node_id(item.id, &self.save_ctxt); self.dumper.dump_def( @@ -1543,15 +1416,14 @@ fn visit_item(&mut self, item: &'l ast::Item) { } self.visit_ty(&ty); - self.process_generic_params(ty_params, item.span, &qualname, item.id); + self.process_generic_params(ty_params, &qualname, item.id); } Existential(ref _bounds, ref ty_params) => { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); // FIXME do something with _bounds let value = String::new(); - let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); - if !self.span.filter_generated(sub_span, item.span) { - let span = self.span_from_span(sub_span.expect("No span found for typedef")); + if !self.span.filter_generated(item.ident.span) { + let span = self.span_from_span(item.ident.span); let id = ::id_from_node_id(item.id, &self.save_ctxt); self.dumper.dump_def( @@ -1573,7 +1445,7 @@ fn visit_item(&mut self, item: &'l ast::Item) { ); } - self.process_generic_params(ty_params, item.span, &qualname, item.id); + self.process_generic_params(ty_params, &qualname, item.id); } Mac(_) => (), _ => visit::walk_item(self, item), @@ -1606,14 +1478,13 @@ fn visit_ty(&mut self, t: &'l ast::Ty) { } if let Some(id) = self.lookup_def_id(t.id) { - if let Some(sub_span) = self.span.sub_span_for_type_name(t.span) { - let span = self.span_from_span(sub_span); - self.dumper.dump_ref(Ref { - kind: RefKind::Type, - span, - ref_id: ::id_from_def_id(id), - }); - } + let sub_span = path.segments.last().unwrap().ident.span; + let span = self.span_from_span(sub_span); + self.dumper.dump_ref(Ref { + kind: RefKind::Type, + span, + ref_id: ::id_from_def_id(id), + }); } self.write_sub_paths_truncated(path); @@ -1753,11 +1624,7 @@ fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) { if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { down_cast_data!(fn_data, DefData, item.span); - self.nest_tables( - item.id, - |v| v.process_formals(&decl.inputs, &fn_data.qualname), - ); - self.process_generic_params(generics, item.span, &fn_data.qualname, item.id); + self.process_generic_params(generics, &fn_data.qualname, item.id); self.dumper.dump_def(&access, fn_data); } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4b43a1a6270..7689406b59a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -57,12 +57,10 @@ use std::fs::File; use std::path::{Path, PathBuf}; -use syntax::ast::{self, Attribute, NodeId, PatKind}; +use syntax::ast::{self, Attribute, DUMMY_NODE_ID, NodeId, PatKind}; use syntax::source_map::Spanned; use syntax::parse::lexer::comments::strip_doc_comment_decoration; -use syntax::parse::token; use syntax::print::pprust; -use syntax::symbol::keywords; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{arg_to_string, ty_to_string}; use syntax::source_map::MacroAttribute; @@ -162,14 +160,12 @@ pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { - let sub_span = self.span_utils - .sub_span_after_keyword(item.span, keywords::Fn); - filter!(self.span_utils, sub_span, item.span, None); + filter!(self.span_utils, item.ident.span); Some(Data::DefData(Def { kind: DefKind::ForeignFunction, id: id_from_node_id(item.id, self), - span: self.span_from_span(sub_span.unwrap()), + span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, value: make_signature(decl, generics), @@ -181,13 +177,11 @@ pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option { attributes: lower_attributes(item.attrs.clone(), self), })) } - ast::ForeignItemKind::Static(ref ty, m) => { - let keyword = if m { keywords::Mut } else { keywords::Static }; - let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); - filter!(self.span_utils, sub_span, item.span, None); + ast::ForeignItemKind::Static(ref ty, _) => { + filter!(self.span_utils, item.ident.span); let id = ::id_from_node_id(item.id, self); - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(item.ident.span); Some(Data::DefData(Def { kind: DefKind::ForeignStatic, @@ -214,13 +208,11 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.node { ast::ItemKind::Fn(ref decl, .., ref generics, _) => { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - let sub_span = self.span_utils - .sub_span_after_keyword(item.span, keywords::Fn); - filter!(self.span_utils, sub_span, item.span, None); + filter!(self.span_utils, item.ident.span); Some(Data::DefData(Def { kind: DefKind::Function, id: id_from_node_id(item.id, self), - span: self.span_from_span(sub_span.unwrap()), + span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, value: make_signature(decl, generics), @@ -232,19 +224,13 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option { attributes: lower_attributes(item.attrs.clone(), self), })) } - ast::ItemKind::Static(ref typ, mt, _) => { + ast::ItemKind::Static(ref typ, ..) => { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - let keyword = match mt { - ast::Mutability::Mutable => keywords::Mut, - ast::Mutability::Immutable => keywords::Static, - }; - - let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); - filter!(self.span_utils, sub_span, item.span, None); + filter!(self.span_utils, item.ident.span); let id = id_from_node_id(item.id, self); - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(item.ident.span); Some(Data::DefData(Def { kind: DefKind::Static, @@ -263,12 +249,10 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option { } ast::ItemKind::Const(ref typ, _) => { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - let sub_span = self.span_utils - .sub_span_after_keyword(item.span, keywords::Const); - filter!(self.span_utils, sub_span, item.span, None); + filter!(self.span_utils, item.ident.span); let id = id_from_node_id(item.id, self); - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(item.ident.span); Some(Data::DefData(Def { kind: DefKind::Const, @@ -291,16 +275,14 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option { let cm = self.tcx.sess.source_map(); let filename = cm.span_to_filename(m.inner); - let sub_span = self.span_utils - .sub_span_after_keyword(item.span, keywords::Mod); - filter!(self.span_utils, sub_span, item.span, None); + filter!(self.span_utils, item.ident.span); Some(Data::DefData(Def { kind: DefKind::Mod, id: id_from_node_id(item.id, self), name: item.ident.to_string(), qualname, - span: self.span_from_span(sub_span.unwrap()), + span: self.span_from_span(item.ident.span), value: filename.to_string(), parent: None, children: m.items @@ -316,9 +298,7 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option { ast::ItemKind::Enum(ref def, _) => { let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - let sub_span = self.span_utils - .sub_span_after_keyword(item.span, keywords::Enum); - filter!(self.span_utils, sub_span, item.span, None); + filter!(self.span_utils, item.ident.span); let variants_str = def.variants .iter() .map(|v| v.node.ident.to_string()) @@ -328,7 +308,7 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option { Some(Data::DefData(Def { kind: DefKind::Enum, id: id_from_node_id(item.id, self), - span: self.span_from_span(sub_span.unwrap()), + span: self.span_from_span(item.ident.span), name, qualname, value, @@ -349,11 +329,11 @@ pub fn get_item_data(&self, item: &ast::Item) -> Option { if generated_code(path.span) { return None; } - let sub_span = self.span_utils.sub_span_for_type_name(path.span); - filter!(self.span_utils, sub_span, typ.span, None); + let sub_span = path.segments.last().unwrap().ident.span; + filter!(self.span_utils, sub_span); let impl_id = self.next_impl_id(); - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(sub_span); let type_data = self.lookup_ref_id(typ.id); type_data.map(|type_data| { @@ -402,15 +382,13 @@ pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option< if let Some(ident) = field.ident { let name = ident.to_string(); let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident); - let sub_span = self.span_utils - .sub_span_before_token(field.span, token::Colon); - filter!(self.span_utils, sub_span, field.span, None); + filter!(self.span_utils, ident.span); let def_id = self.tcx.hir.local_def_id(field.id); let typ = self.tcx.type_of(def_id).to_string(); let id = id_from_node_id(field.id, self); - let span = self.span_from_span(sub_span.unwrap()); + let span = self.span_from_span(ident.span); Some(Def { kind: DefKind::Field, @@ -433,7 +411,7 @@ pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option< // FIXME would be nice to take a MethodItem here, but the ast provides both // trait and impl flavours, so the caller must do the disassembly. - pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> Option { + pub fn get_method_data(&self, id: ast::NodeId, ident: ast::Ident, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. let (qualname, parent_scope, decl_id, docs, attributes) = @@ -459,7 +437,7 @@ pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> O qualname.push_str(&self.tcx.item_path_str(def_id)); self.tcx .associated_items(def_id) - .find(|item| item.ident.name == name) + .find(|item| item.ident.name == ident.name) .map(|item| decl_id = Some(item.def_id)); } qualname.push_str(">"); @@ -512,16 +490,15 @@ pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> O }, }; - let qualname = format!("{}::{}", qualname, name); + let qualname = format!("{}::{}", qualname, ident.name); - let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); - filter!(self.span_utils, sub_span, span, None); + filter!(self.span_utils, ident.span); Some(Def { kind: DefKind::Method, id: id_from_node_id(id, self), - span: self.span_from_span(sub_span.unwrap()), - name: name.to_string(), + span: self.span_from_span(ident.span), + name: ident.name.to_string(), qualname, // FIXME you get better data here by using the visitor. value: String::new(), @@ -540,9 +517,9 @@ pub fn get_trait_ref_data(&self, trait_ref: &ast::TraitRef) -> Option { if generated_code(span) { return None; } - let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span)); - filter!(self.span_utils, sub_span, span, None); - let span = self.span_from_span(sub_span.unwrap()); + let sub_span = trait_ref.path.segments.last().unwrap().ident.span; + filter!(self.span_utils, sub_span); + let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Type, span, @@ -574,9 +551,8 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { ty::Adt(def, _) if !def.is_enum() => { let variant = &def.non_enum_variant(); let index = self.tcx.find_field_index(ident, variant).unwrap(); - let sub_span = self.span_utils.span_for_last_ident(expr.span); - filter!(self.span_utils, sub_span, expr.span, None); - let span = self.span_from_span(sub_span.unwrap()); + filter!(self.span_utils, ident.span); + let span = self.span_from_span(ident.span); return Some(Data::RefData(Ref { kind: RefKind::Variable, span, @@ -593,9 +569,9 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { ast::ExprKind::Struct(ref path, ..) => { match self.tables.expr_ty_adjusted(&hir_node).sty { ty::Adt(def, _) if !def.is_enum() => { - let sub_span = self.span_utils.span_for_last_ident(path.span); - filter!(self.span_utils, sub_span, path.span, None); - let span = self.span_from_span(sub_span.unwrap()); + let sub_span = path.segments.last().unwrap().ident.span; + filter!(self.span_utils, sub_span); + let span = self.span_from_span(sub_span); Some(Data::RefData(Ref { kind: RefKind::Type, span, @@ -624,7 +600,7 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { ty::TraitContainer(_) => (None, Some(method_id)), }; let sub_span = seg.ident.span; - filter!(self.span_utils, Some(sub_span), expr.span, None); + filter!(self.span_utils, sub_span); let span = self.span_from_span(sub_span); Some(Data::RefData(Ref { kind: RefKind::Function, @@ -656,6 +632,10 @@ pub fn get_path_def(&self, id: NodeId) -> HirDef { Node::Visibility(&Spanned { node: hir::VisibilityKind::Restricted { ref path, .. }, .. }) => path.def, + Node::PathSegment(seg) => match seg.def { + Some(def) => def, + None => HirDef::Err, + }, Node::Expr(&hir::Expr { node: hir::ExprKind::Struct(ref qpath, ..), .. @@ -708,13 +688,14 @@ pub fn get_path_def(&self, id: NodeId) -> HirDef { } } - pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option { + pub fn get_path_data(&self, _id: NodeId, path: &ast::Path) -> Option { + path.segments.last().and_then(|seg| self.get_path_segment_data(seg)) + } + + pub fn get_path_segment_data(&self, path_seg: &ast::PathSegment) -> Option { // Returns true if the path is function type sugar, e.g., `Fn(A) -> B`. - fn fn_type(path: &ast::Path) -> bool { - if path.segments.len() != 1 { - return false; - } - if let Some(ref generic_args) = path.segments[0].args { + fn fn_type(seg: &ast::PathSegment) -> bool { + if let Some(ref generic_args) = seg.args { if let ast::GenericArgs::Parenthesized(_) = **generic_args { return true; } @@ -722,17 +703,17 @@ fn fn_type(path: &ast::Path) -> bool { false } - if path.segments.is_empty() { + if path_seg.id == DUMMY_NODE_ID { return None; } - let def = self.get_path_def(id); - let last_seg = &path.segments[path.segments.len() - 1]; - let sub_span = last_seg.ident.span; - filter!(self.span_utils, Some(sub_span), path.span, None); + let def = self.get_path_def(path_seg.id); + let span = path_seg.ident.span; + filter!(self.span_utils, span); + let span = self.span_from_span(span); + match def { HirDef::Upvar(id, ..) | HirDef::Local(id) => { - let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Variable, span, @@ -743,23 +724,17 @@ fn fn_type(path: &ast::Path) -> bool { HirDef::Const(..) | HirDef::AssociatedConst(..) | HirDef::VariantCtor(..) => { - let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(def.def_id()), }) } - HirDef::Trait(def_id) if fn_type(path) => { - // Function type bounds are desugared in the parser, so we have to - // special case them here. - let fn_span = self.span_utils.span_for_first_ident(path.span); - fn_span.map(|span| { - Ref { - kind: RefKind::Type, - span: self.span_from_span(span), - ref_id: id_from_def_id(def_id), - } + HirDef::Trait(def_id) if fn_type(path_seg) => { + Some(Ref { + kind: RefKind::Type, + span, + ref_id: id_from_def_id(def_id), }) } HirDef::Struct(def_id) | @@ -774,7 +749,6 @@ fn fn_type(path: &ast::Path) -> bool { HirDef::Trait(def_id) | HirDef::Existential(def_id) | HirDef::TyParam(def_id) => { - let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Type, span, @@ -785,7 +759,6 @@ fn fn_type(path: &ast::Path) -> bool { // This is a reference to a tuple struct where the def_id points // to an invisible constructor function. That is not a very useful // def, so adjust to point to the tuple struct itself. - let span = self.span_from_span(sub_span); let parent_def_id = self.tcx.parent_def_id(def_id).unwrap(); Some(Ref { kind: RefKind::Type, @@ -804,7 +777,6 @@ fn fn_type(path: &ast::Path) -> bool { } else { None }; - let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Function, span, @@ -812,7 +784,6 @@ fn fn_type(path: &ast::Path) -> bool { }) } HirDef::Fn(def_id) => { - let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Function, span, @@ -820,7 +791,6 @@ fn fn_type(path: &ast::Path) -> bool { }) } HirDef::Mod(def_id) => { - let span = self.span_from_span(sub_span); Some(Ref { kind: RefKind::Mod, span, @@ -843,15 +813,14 @@ pub fn get_field_ref_data( field_ref: &ast::Field, variant: &ty::VariantDef, ) -> Option { - let index = self.tcx.find_field_index(field_ref.ident, variant).unwrap(); - // We don't really need a sub-span here, but no harm done - let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span); - filter!(self.span_utils, sub_span, field_ref.ident.span, None); - let span = self.span_from_span(sub_span.unwrap()); - Some(Ref { - kind: RefKind::Variable, - span, - ref_id: id_from_def_id(variant.fields[index].did), + filter!(self.span_utils, field_ref.ident.span); + self.tcx.find_field_index(field_ref.ident, variant).map(|index| { + let span = self.span_from_span(field_ref.ident.span); + Ref { + kind: RefKind::Variable, + span, + ref_id: id_from_def_id(variant.fields[index].did), + } }) } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 47677a75171..902353da13f 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -16,7 +16,6 @@ use syntax::parse::lexer::{self, StringReader}; use syntax::parse::token::{self, Token}; -use syntax::symbol::keywords; use syntax_pos::*; #[derive(Clone)] @@ -67,131 +66,6 @@ pub fn retokenise_span(&self, span: Span) -> StringReader<'a> { lexer::StringReader::retokenize(&self.sess.parse_sess, span) } - // Re-parses a path and returns the span for the last identifier in the path - pub fn span_for_last_ident(&self, span: Span) -> Option { - let mut result = None; - - let mut toks = self.retokenise_span(span); - let mut bracket_count = 0; - loop { - let ts = toks.real_token(); - if ts.tok == token::Eof { - return result; - } - if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) { - result = Some(ts.sp); - } - - bracket_count += match ts.tok { - token::Lt => 1, - token::Gt => -1, - token::BinOp(token::Shr) => -2, - _ => 0, - } - } - } - - // Return the span for the first identifier in the path. - pub fn span_for_first_ident(&self, span: Span) -> Option { - let mut toks = self.retokenise_span(span); - let mut bracket_count = 0; - loop { - let ts = toks.real_token(); - if ts.tok == token::Eof { - return None; - } - if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) { - return Some(ts.sp); - } - - bracket_count += match ts.tok { - token::Lt => 1, - token::Gt => -1, - token::BinOp(token::Shr) => -2, - _ => 0, - } - } - } - - // Return the span for the last ident before a `<` and outside any - // angle brackets, or the last span. - pub fn sub_span_for_type_name(&self, span: Span) -> Option { - let mut toks = self.retokenise_span(span); - let mut prev = toks.real_token(); - let mut result = None; - - // We keep track of the following two counts - the depth of nesting of - // angle brackets, and the depth of nesting of square brackets. For the - // angle bracket count, we only count tokens which occur outside of any - // square brackets (i.e. bracket_count == 0). The intuition here is - // that we want to count angle brackets in the type, but not any which - // could be in expression context (because these could mean 'less than', - // etc.). - let mut angle_count = 0; - let mut bracket_count = 0; - loop { - let next = toks.real_token(); - - if (next.tok == token::Lt || next.tok == token::Colon) && angle_count == 0 - && bracket_count == 0 && prev.tok.is_ident() - { - result = Some(prev.sp); - } - - if bracket_count == 0 { - angle_count += match prev.tok { - token::Lt => 1, - token::Gt => -1, - token::BinOp(token::Shl) => 2, - token::BinOp(token::Shr) => -2, - _ => 0, - }; - } - - bracket_count += match prev.tok { - token::OpenDelim(token::Bracket) => 1, - token::CloseDelim(token::Bracket) => -1, - _ => 0, - }; - - if next.tok == token::Eof { - break; - } - prev = next; - } - #[cfg(debug_assertions)] { - if angle_count != 0 || bracket_count != 0 { - let loc = self.sess.source_map().lookup_char_pos(span.lo()); - span_bug!( - span, - "Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}", - self.snippet(span), - loc.file.name, - loc.line - ); - } - } - if result.is_none() && prev.tok.is_ident() { - return Some(prev.sp); - } - result - } - - pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option { - let mut toks = self.retokenise_span(span); - let mut prev = toks.real_token(); - loop { - if prev.tok == token::Eof { - return None; - } - let next = toks.real_token(); - if next.tok == tok { - return Some(prev.sp); - } - prev = next; - } - } - pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option { let mut toks = self.retokenise_span(span); loop { @@ -205,28 +79,6 @@ pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option { } } - pub fn sub_span_after_keyword(&self, span: Span, keyword: keywords::Keyword) -> Option { - self.sub_span_after(span, |t| t.is_keyword(keyword)) - } - - fn sub_span_after bool>(&self, span: Span, f: F) -> Option { - let mut toks = self.retokenise_span(span); - loop { - let ts = toks.real_token(); - if ts.tok == token::Eof { - return None; - } - if f(ts.tok) { - let ts = toks.real_token(); - if ts.tok == token::Eof { - return None; - } else { - return Some(ts.sp); - } - } - } - } - // // Return the name for a macro definition (identifier after first `!`) // pub fn span_for_macro_def_name(&self, span: Span) -> Option { // let mut toks = self.retokenise_span(span); @@ -271,42 +123,28 @@ fn sub_span_after bool>(&self, span: Span, f: F) -> Option /// /// Used to filter out spans of minimal value, /// such as references to macro internal variables. - pub fn filter_generated(&self, sub_span: Option, parent: Span) -> bool { - if !generated_code(parent) { - // Edge case - this occurs on generated code with incorrect expansion info. - return sub_span.is_none() + pub fn filter_generated(&self, span: Span) -> bool { + if span.is_dummy() { + return true; + } + + if !generated_code(span) { + return false; } - // If sub_span is none, filter out generated code. - let sub_span = match sub_span { - Some(ss) => ss, - None => return true, - }; //If the span comes from a fake source_file, filter it. - if !self.sess + !self.sess .source_map() - .lookup_char_pos(parent.lo()) + .lookup_char_pos(span.lo()) .file .is_real_file() - { - return true; - } - - // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root - // callsite. This filters out macro internal variables and most malformed spans. - !parent.source_callsite().contains(sub_span) } } macro_rules! filter { - ($util: expr, $span: expr, $parent: expr, None) => { - if $util.filter_generated($span, $parent) { + ($util: expr, $parent: expr) => { + if $util.filter_generated($parent) { return None; } }; - ($util: expr, $span: ident, $parent: expr) => { - if $util.filter_generated($span, $parent) { - return; - } - }; } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 6b28fd09174..1a5d2801af0 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -430,7 +430,7 @@ pub fn max_for_offset(offset: Size) -> Align { } /// Lower the alignment, if necessary, such that the given offset - /// is aligned to it (the offset is a multiple of the aligment). + /// is aligned to it (the offset is a multiple of the alignment). pub fn restrict_for_offset(self, offset: Size) -> Align { self.min(Align::max_for_offset(offset)) } diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index a857cdbda45..cf274a9c851 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -8,22 +8,32 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::infer::at::ToTrace; use rustc::infer::canonical::{Canonical, QueryResponse}; use rustc::infer::InferCtxt; +use rustc::hir::def_id::DefId; +use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType; use rustc::traits::query::type_op::eq::Eq; use rustc::traits::query::type_op::normalize::Normalize; use rustc::traits::query::type_op::prove_predicate::ProvePredicate; use rustc::traits::query::type_op::subtype::Subtype; use rustc::traits::query::{Fallible, NoSolution}; -use rustc::traits::{FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine, - TraitEngineExt}; +use rustc::traits::{ + FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt, +}; use rustc::ty::query::Providers; -use rustc::ty::{FnSig, Lift, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts}; +use rustc::ty::{ + FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance, +}; use rustc_data_structures::sync::Lrc; use std::fmt; +use syntax::ast; +use syntax_pos::DUMMY_SP; crate fn provide(p: &mut Providers) { *p = Providers { + type_op_ascribe_user_type, type_op_eq, type_op_prove_predicate, type_op_subtype, @@ -35,6 +45,152 @@ }; } +fn type_op_ascribe_user_type<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>, +) -> Result>>, NoSolution> { + tcx.infer_ctxt() + .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { + let ( + param_env, + AscribeUserType { + mir_ty, + variance, + def_id, + user_substs, + }, + ) = key.into_parts(); + + debug!( + "type_op_ascribe_user_type(\ + mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}\ + )", + mir_ty, variance, def_id, user_substs, + ); + + let mut cx = AscribeUserTypeCx { + infcx, + param_env, + fulfill_cx, + }; + cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs)?; + + Ok(()) + }) +} + +struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> { + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, + param_env: ParamEnv<'tcx>, + fulfill_cx: &'me mut FulfillmentContext<'tcx>, +} + +impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { + fn normalize(&mut self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + self.infcx + .partially_normalize_associated_types_in( + DUMMY_SP, + ast::CRATE_NODE_ID, + self.param_env, + &value, + ) + .into_value_registering_obligations(self.infcx, self.fulfill_cx) + } + + fn relate(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution> + where + T: ToTrace<'tcx>, + { + Ok(self.infcx + .at(&ObligationCause::dummy(), self.param_env) + .relate(a, variance, b)? + .into_value_registering_obligations(self.infcx, self.fulfill_cx)) + } + + fn prove_predicate(&mut self, predicate: Predicate<'tcx>) { + self.fulfill_cx.register_predicate_obligation( + self.infcx, + Obligation::new(ObligationCause::dummy(), self.param_env, predicate), + ); + } + + fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { + self.infcx.tcx + } + + fn subst(&self, value: T, substs: &[Kind<'tcx>]) -> T + where + T: TypeFoldable<'tcx>, + { + value.subst(self.tcx(), substs) + } + + fn relate_mir_and_user_ty( + &mut self, + mir_ty: Ty<'tcx>, + variance: Variance, + def_id: DefId, + user_substs: UserSubsts<'tcx>, + ) -> Result<(), NoSolution> { + let UserSubsts { + substs, + user_self_ty, + } = user_substs; + + let ty = self.tcx().type_of(def_id); + let ty = self.subst(ty, substs); + debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); + let ty = self.normalize(ty); + + self.relate(mir_ty, variance, ty)?; + + if let Some(UserSelfTy { + impl_def_id, + self_ty, + }) = user_self_ty + { + let impl_self_ty = self.tcx().type_of(impl_def_id); + let impl_self_ty = self.subst(impl_self_ty, &substs); + let impl_self_ty = self.normalize(impl_self_ty); + + self.relate(self_ty, Variance::Invariant, impl_self_ty)?; + + self.prove_predicate(Predicate::WellFormed(impl_self_ty)); + } + + // Prove the predicates coming along with `def_id`. + // + // Also, normalize the `instantiated_predicates` + // because otherwise we wind up with duplicate "type + // outlives" error messages. + let instantiated_predicates = self.tcx() + .predicates_of(def_id) + .instantiate(self.tcx(), substs); + for instantiated_predicate in instantiated_predicates.predicates { + let instantiated_predicate = self.normalize(instantiated_predicate); + self.prove_predicate(instantiated_predicate); + } + + // In addition to proving the predicates, we have to + // prove that `ty` is well-formed -- this is because + // the WF of `ty` is predicated on the substs being + // well-formed, and we haven't proven *that*. We don't + // want to prove the WF of types from `substs` directly because they + // haven't been normalized. + // + // FIXME(nmatsakis): Well, perhaps we should normalize + // them? This would only be relevant if some input + // type were ill-formed but did not appear in `ty`, + // which...could happen with normalization... + self.prove_predicate(Predicate::WellFormed(ty)); + + Ok(()) + } +} + fn type_op_eq<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index d82d36a1937..7773e2d5708 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -111,34 +111,35 @@ pub fn demand_coerce_diag(&self, let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); - // If the expected type is an enum with any variants whose sole - // field is of the found type, suggest such variants. See Issue - // #42764. + // If the expected type is an enum (Issue #55250) with any variants whose + // sole field is of the found type, suggest such variants. (Issue #42764) if let ty::Adt(expected_adt, substs) = expected.sty { - let mut compatible_variants = expected_adt.variants - .iter() - .filter(|variant| variant.fields.len() == 1) - .filter_map(|variant| { - let sole_field = &variant.fields[0]; - let sole_field_ty = sole_field.ty(self.tcx, substs); - if self.can_coerce(expr_ty, sole_field_ty) { - let variant_path = self.tcx.item_path_str(variant.did); - Some(variant_path.trim_left_matches("std::prelude::v1::").to_string()) - } else { - None + if expected_adt.is_enum() { + let mut compatible_variants = expected_adt.variants + .iter() + .filter(|variant| variant.fields.len() == 1) + .filter_map(|variant| { + let sole_field = &variant.fields[0]; + let sole_field_ty = sole_field.ty(self.tcx, substs); + if self.can_coerce(expr_ty, sole_field_ty) { + let variant_path = self.tcx.item_path_str(variant.did); + Some(variant_path.trim_left_matches("std::prelude::v1::").to_string()) + } else { + None + } + }).peekable(); + + if compatible_variants.peek().is_some() { + let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr)); + let suggestions = compatible_variants + .map(|v| format!("{}({})", v, expr_text)).collect::>(); + err.span_suggestions_with_applicability( + expr.span, + "try using a variant of the expected type", + suggestions, + Applicability::MaybeIncorrect, + ); } - }).peekable(); - - if compatible_variants.peek().is_some() { - let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr)); - let suggestions = compatible_variants.map(|v| - format!("{}({})", v, expr_text)).collect::>(); - err.span_suggestions_with_applicability( - expr.span, - "try using a variant of the expected type", - suggestions, - Applicability::MaybeIncorrect, - ); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1c562859bb4..77151351d08 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5198,7 +5198,7 @@ pub fn instantiate_value_path(&self, } else { // If no type arguments were provided, we have to infer them. // This case also occurs as a result of some malformed input, e.g. - // a lifetime argument being given instead of a type paramter. + // a lifetime argument being given instead of a type parameter. // Using inference instead of `Error` gives better error messages. self.var_for_def(span, param) } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index ec773e384af..9990d2ee2b6 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -674,7 +674,7 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>( } // if may_define_existential_type // now register the bounds on the parameters of the existential type - // so the parameters given by the function need to fulfil them + // so the parameters given by the function need to fulfill them // ```rust // existential type Foo: 'static; // fn foo() -> Foo { .. *} diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index f9aa0397257..9d785dfb58a 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -164,7 +164,7 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { // If the extern crate isn't in the extern prelude, // there is no way it can be written as an `use`. let orig_name = extern_crate.orig_name.unwrap_or(item.name); - if !tcx.extern_prelude.contains(&orig_name) { + if !tcx.extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) { continue; } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index c54d9e4b475..05a83dd307c 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -269,7 +269,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, // exactly one (non-phantom) field has changed its // type, which we will expect to be the pointer that // is becoming fat (we could probably generalize this - // to mutiple thin pointers of the same type becoming + // to multiple thin pointers of the same type becoming // fat, but we don't). In this case: // // - `extra` has type `T` before and type `T` after diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index b6bc8d603d5..57c7e2afd62 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -50,6 +50,7 @@ pub fn get_blanket_impls( name: Option, ) -> Vec where F: Fn(DefId) -> Def { + debug!("get_blanket_impls(def_id={:?}, ...)", def_id); let mut impls = Vec::new(); if self.cx .tcx @@ -78,6 +79,8 @@ pub fn get_blanket_impls( } self.cx.tcx.for_each_relevant_impl(trait_def_id, ty, |impl_def_id| { self.cx.tcx.infer_ctxt().enter(|infcx| { + debug!("get_blanet_impls: Considering impl for trait '{:?}' {:?}", + trait_def_id, impl_def_id); let t_generics = infcx.tcx.generics_of(impl_def_id); let trait_ref = infcx.tcx.impl_trait_ref(impl_def_id) .expect("Cannot get impl trait"); @@ -104,8 +107,8 @@ pub fn get_blanket_impls( drop(obligations); debug!( - "invoking predicate_may_hold: {:?}", - trait_ref, + "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}", + param_env, trait_ref, ty ); let may_apply = match infcx.evaluate_obligation( &traits::Obligation::new( @@ -117,6 +120,10 @@ pub fn get_blanket_impls( Ok(eval_result) => eval_result.may_apply(), Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no }; + debug!("get_blanket_impls: found applicable impl: {}\ + for trait_ref={:?}, ty={:?}", + may_apply, trait_ref, ty); + if !may_apply { return } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index db605e57735..9b2720717c9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3632,7 +3632,7 @@ fn name_from_pat(p: &hir::Pat) -> String { fields.iter().map(|&Spanned { node: ref fp, .. }| format!("{}: {}", fp.ident, name_from_pat(&*fp.pat))) .collect::>().join(", "), - if etc { ", ..." } else { "" } + if etc { ", .." } else { "" } ) } PatKind::Tuple(ref elts, _) => format!("({})", elts.iter().map(|p| name_from_pat(&**p)) @@ -4012,6 +4012,8 @@ fn push(&mut self, text: &str) { def: def_ctor(def_id), segments: hir::HirVec::from_vec(apb.names.iter().map(|s| hir::PathSegment { ident: ast::Ident::from_str(&s), + id: None, + def: None, args: None, infer_types: false, }).collect()) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 49f13df64d6..d6b0127e44d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -186,6 +186,8 @@ pub fn get_real_ty(&self, segments.push(hir::PathSegment::new( real_name.unwrap_or(last.ident), + None, + None, self.generics_to_path_params(generics.clone()), false, )); @@ -476,7 +478,9 @@ pub fn run_core(search_paths: SearchPaths, trait_map: resolver.trait_map.clone(), maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(), maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(), - extern_prelude: resolver.extern_prelude.clone(), + extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { + (ident.name, entry.introduced_by_item) + }).collect(), }; let analysis = ty::CrateAnalysis { access_levels: Lrc::new(AccessLevels::default()), diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 87b4527a2a7..6522261fe1e 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -28,9 +28,12 @@ use syntax_pos::{Span, FileName}; /// Highlights `src`, returning the HTML output. -pub fn render_with_highlighting(src: &str, class: Option<&str>, - extension: Option<&str>, - tooltip: Option<(&str, &str)>) -> String { +pub fn render_with_highlighting( + src: &str, + class: Option<&str>, + extension: Option<&str>, + tooltip: Option<(&str, &str)>, +) -> String { debug!("highlighting: ================\n{}\n==============", src); let sess = parse::ParseSess::new(FilePathMapping::empty()); let fm = sess.source_map().new_source_file(FileName::Custom("stdin".to_string()), @@ -384,9 +387,9 @@ fn rustdoc_class(self) -> &'static str { } fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> { - write!(out, "
\n", class.unwrap_or(""))
+    write!(out, "
\n", class.unwrap_or(""))
 }
 
 fn write_footer(out: &mut dyn Write) -> io::Result<()> {
-    write!(out, "
\n") + write!(out, "
\n") } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index dda0f37c3f9..ea51c46a332 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1709,6 +1709,7 @@ pub fn new(root_path: &'a str, suffix: &'a str) -> Settings<'a> { ("method-docs", "Auto-hide item methods' documentation", false), ("go-to-only-result", "Directly go to item in search if there is only one result", false), + ("line-numbers", "Show line numbers on code examples", false), ], root_path, suffix, diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 6307dda454d..9d1a5c38378 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2093,6 +2093,7 @@ return wrapper; } + var hideItemDeclarations = getCurrentValue('rustdoc-item-declarations') === "false"; onEach(document.getElementsByClassName('docblock'), function(e) { if (hasClass(e, 'autohide')) { var wrap = e.previousElementSibling; @@ -2116,16 +2117,14 @@ } } if (e.parentNode.id === "main") { - var otherMessage; + var otherMessage = ''; var fontSize; var extraClass; - var show = true; if (hasClass(e, "type-decl")) { fontSize = "20px"; otherMessage = ' Show declaration'; - show = getCurrentValue('rustdoc-item-declarations') === "false"; - if (!show) { + if (hideItemDeclarations === false) { extraClass = 'collapsed'; } } else if (hasClass(e, "non-exhaustive")) { @@ -2142,8 +2141,12 @@ extraClass = "marg-left"; } - e.parentNode.insertBefore(createToggle(otherMessage, fontSize, extraClass, show), e); - if (otherMessage && show) { + e.parentNode.insertBefore(createToggle(otherMessage, + fontSize, + extraClass, + hideItemDeclarations), + e); + if (otherMessage.length > 0 && hideItemDeclarations === true) { collapseDocs(e.previousSibling.childNodes[0], "toggle"); } } @@ -2186,13 +2189,33 @@ }); } + // To avoid checking on "rustdoc-item-attributes" value on every loop... + var itemAttributesFunc = function() {}; + if (getCurrentValue("rustdoc-item-attributes") !== "false") { + itemAttributesFunc = function(x) { + collapseDocs(x.previousSibling.childNodes[0], "toggle"); + }; + } onEach(document.getElementById('main').getElementsByClassName('attributes'), function(i_e) { i_e.parentNode.insertBefore(createToggleWrapper(toggle.cloneNode(true)), i_e); - if (getCurrentValue("rustdoc-item-attributes") !== "false") { - collapseDocs(i_e.previousSibling.childNodes[0], "toggle"); - } + itemAttributesFunc(i_e); }); + // To avoid checking on "rustdoc-line-numbers" value on every loop... + var lineNumbersFunc = function() {}; + if (getCurrentValue("rustdoc-line-numbers") === "true") { + lineNumbersFunc = function(x) { + var count = x.textContent.split('\n').length; + var elems = []; + for (var i = 0; i < count; ++i) { + elems.push(i + 1); + } + var node = document.createElement('pre'); + addClass(node, 'line-number'); + node.innerHTML = elems.join('\n'); + x.parentNode.insertBefore(node, x); + }; + } onEach(document.getElementsByClassName('rust-example-rendered'), function(e) { if (hasClass(e, 'compile_fail')) { e.addEventListener("mouseover", function(event) { @@ -2209,6 +2232,7 @@ e.previousElementSibling.childNodes[0].style.color = ''; }); } + lineNumbersFunc(e); }); function showModal(content) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 63740ea7291..c0951d9f840 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -282,6 +282,24 @@ nav.sub { padding-left: 0; } +.example-wrap { + display: inline-flex; + width: 100%; +} + +.example-wrap > pre.line-number { + overflow: initial; + border: 1px solid; + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + padding: 13px 8px; + text-align: right; +} + +.example-wrap > pre.rust { + width: 100%; +} + #search { margin-left: 230px; position: relative; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 8e4890d9058..4a8950b236c 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -233,6 +233,10 @@ pre.rust .question-mark { color: #ff9011; } +.example-wrap > pre.line-number { + border-color: #4a4949; +} + a.test-arrow { background-color: rgba(78, 139, 202, 0.2); } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 2742faab017..b3b0b6b2ea9 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -227,6 +227,10 @@ pre.rust .question-mark { color: #ff9011; } +.example-wrap > pre.line-number { + border-color: #c7c7c7; +} + a.test-arrow { background-color: rgba(78, 139, 202, 0.2); } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index c3f225d1eb0..7d17aaf2f26 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -198,12 +198,12 @@ pub fn signum(self) -> f32 { } } - /// Returns a number composed of the magnitude of one number and the sign of - /// another. + /// Returns a number composed of the magnitude of `self` and the sign of + /// `y`. /// /// Equal to `self` if the sign of `self` and `y` are the same, otherwise - /// equal to `-y`. If `self` is a `NAN`, then a `NAN` with the sign of `y` - /// is returned. + /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of + /// `y` is returned. /// /// # Examples /// diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index da062dda77a..ecaaf8323ab 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -176,12 +176,12 @@ pub fn signum(self) -> f64 { } } - /// Returns a number composed of the magnitude of one number and the sign of - /// another. + /// Returns a number composed of the magnitude of `self` and the sign of + /// `y`. /// /// Equal to `self` if the sign of `self` and `y` are the same, otherwise - /// equal to `-y`. If `self` is a `NAN`, then a `NAN` with the sign of `y` - /// is returned. + /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of + /// `y` is returned. /// /// # Examples /// diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index d70cf132b3c..6c95854c66c 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -8,72 +8,713 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[doc(keyword = "as")] +// +/// The keyword for casting a value to a type. +/// +/// `as` is most commonly used to turn primitive types into other primitive types, but it has other +/// uses that include turning pointers into addresses, addresses into pointers, and pointers into +/// other pointers. +/// +/// ```rust +/// let thing1: u8 = 89.0 as u8; +/// assert_eq!('B' as u32, 66); +/// assert_eq!(thing1 as char, 'Y'); +/// let thing2: f32 = thing1 as f32 + 10.5; +/// assert_eq!(true as u8 + thing2 as u8, 100); +/// ``` +/// +/// In general, any cast that can be performed via ascribing the type can also be done using `as`, +/// so instead of writing `let x: u32 = 123`, you can write `let x = 123 as u32` (Note: `let x: u32 +/// = 123` would be best in that situation). The same is not true in the other direction, however, +/// explicitly using `as` allows a few more coercions that aren't allowed implicitly, such as +/// changing the type of a raw pointer or turning closures into raw pointers. +/// +/// Other places `as` is used include as extra syntax for [`crate`] and `use`, to change the name +/// something is imported as. +/// +/// For more information on what `as` is capable of, see the [Reference] +/// +/// [Reference]: +/// https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions +/// [`crate`]: keyword.crate.html +mod as_keyword { } + +#[doc(keyword = "const")] +// +/// The keyword for defining constants. +/// +/// Sometimes a certain value is used many times throughout a program, and it can become +/// inconvenient to copy it over and over. What's more, it's not always possible or desirable to +/// make it a variable that gets carried around to each function that needs it. In these cases, the +/// `const` keyword provides a convenient alternative to code duplication. +/// +/// ```rust +/// const THING: u32 = 0xABAD1DEA; +/// +/// let foo = 123 + THING; +/// ``` +/// +/// Constants must be explicitly typed, unlike with `let` you can't ignore its type and let the +/// compiler figure it out. Any constant value can be defined in a const, which in practice happens +/// to be most things that would be reasonable to have a constant (barring `const fn`s, coming +/// soon). For example, you can't have a File as a `const`. +/// +/// The only lifetime allowed in a constant is `'static`, which is the lifetime that encompasses +/// all others in a Rust program. For example, if you wanted to define a constant string, it would +/// look like this: +/// +/// ```rust +/// const WORDS: &'static str = "hello rust!"; +/// ``` +/// +/// Thanks to static lifetime elision, you usually don't have to explicitly use 'static: +/// +/// ```rust +/// const WORDS: &str = "hello convenience!"; +/// ``` +/// +/// `const` items looks remarkably similar to `static` items, which introduces some confusion as +/// to which one should be used at which times. To put it simply, constants are inlined wherever +/// they're used, making using them identical to simply replacing the name of the const with its +/// value. Static variables on the other hand point to a single location in memory, which all +/// accesses share. This means that, unlike with constants, they can't have destructors, and act as +/// a single value across the entire codebase. +/// +/// Constants, as with statics, should always be in SCREAMING_SNAKE_CASE. +/// +/// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const +/// T` and `*mut T`. More about that can be read at the [pointer] primitive part of the Rust docs. +/// +/// For more detail on `const`, see the [Rust Book] or the [Reference] +/// +/// [pointer]: primitive.pointer.html +/// [Rust Book]: +/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants +/// [Reference]: https://doc.rust-lang.org/reference/items/constant-items.html +mod const_keyword { } + +#[doc(keyword = "crate")] +// +/// The `crate` keyword. +/// +/// The primary use of the `crate` keyword is as a part of `extern crate` declarations, which are +/// used to specify a dependency on a crate external to the one it's declared in. Crates are the +/// fundamental compilation unit of Rust code, and can be seen as libraries or projects. More can +/// be read about crates in the [Reference]. +/// +/// ```rust ignore +/// extern crate rand; +/// extern crate my_crate as thing; +/// extern crate std; // implicitly added to the root of every Rust project +/// ``` +/// +/// The `as` keyword can be used to change what the crate is referred to as in your project. If a +/// crate name includes a dash, it is implicitly imported with the dashes replaced by underscores. +/// +/// `crate` is also used as in conjunction with `pub` to signify that the item it's attached to +/// is public only to other members of the same crate it's in. +/// +/// ```rust +/// # #[allow(unused_imports)] +/// pub(crate) use std::io::Error as IoError; +/// pub(crate) enum CoolMarkerType { } +/// pub struct PublicThing { +/// pub(crate) semi_secret_thing: bool, +/// } +/// ``` +/// +/// [Reference]: https://doc.rust-lang.org/reference/items/extern-crates.html +mod crate_keyword { } + +#[doc(keyword = "enum")] +// +/// For defining enumerations. +/// +/// Enums in Rust are similar to those of other compiled languages like C, but have important +/// differences that make them considerably more powerful. What Rust calls enums are more commonly +/// known as [Algebraic Data Types] if you're coming from a functional programming background. The +/// important detail is that each enum variant can have data to go along with it. +/// +/// ```rust +/// # struct Coord; +/// enum SimpleEnum { +/// FirstVariant, +/// SecondVariant, +/// ThirdVariant, +/// } +/// +/// enum Location { +/// Unknown, +/// Anonymous, +/// Known(Coord), +/// } +/// +/// enum ComplexEnum { +/// Nothing, +/// Something(u32), +/// LotsOfThings { +/// usual_struct_stuff: bool, +/// blah: String, +/// } +/// } +/// +/// enum EmptyEnum { } +/// ``` +/// +/// The first enum shown is the usual kind of enum you'd find in a C-style language. The second +/// shows off a hypothetical example of something storing location data, with `Coord` being any +/// other type that's needed, for example a struct. The third example demonstrates the kind of +/// data a variant can store, ranging from nothing, to a tuple, to an anonymous struct. +/// +/// Instantiating enum variants involves explicitly using the enum's name as its namespace, +/// followed by one of its variants. `SimpleEnum::SecondVariant` would be an example from above. +/// When data follows along with a variant, such as with rust's built-in [`Option`] type, the data +/// is added as the type describes, for example `Option::Some(123)`. The same follows with +/// struct-like variants, with things looking like `ComplexEnum::LotsOfThings { usual_struct_stuff: +/// true, blah: "hello!".to_string(), }`. Empty Enums are similar to () in that they cannot be +/// instantiated at all, and are used mainly to mess with the type system in interesting ways. +/// +/// For more information, take a look at the [Rust Book] or the [Reference] +/// +/// [Algebraic Data Types]: https://en.wikipedia.org/wiki/Algebraic_data_type +/// [`Option`]: option/enum.Option.html +/// [Rust Book]: https://doc.rust-lang.org/book/second-edition/ch06-01-defining-an-enum.html +/// [Reference]: https://doc.rust-lang.org/reference/items/enumerations.html +mod enum_keyword { } + +#[doc(keyword = "extern")] +// +/// For external connections in Rust code. +/// +/// The `extern` keyword is used in two places in Rust. One is in conjunction with the [`crate`] +/// keyword to make your Rust code aware of other Rust crates in your project, i.e. `extern crate +/// lazy_static;`. The other use is in foreign function interfaces (FFI). +/// +/// `extern` is used in two different contexts within FFI. The first is in the form of external +/// blocks, for declaring function interfaces that Rust code can call foreign code by. +/// +/// ```rust ignore +/// #[link(name = "my_c_library")] +/// extern "C" { +/// fn my_c_function(x: i32) -> bool; +/// } +/// ``` +/// +/// This code would attempt to link with `libmy_c_library.so` on unix-like systems and +/// `my_c_library.dll` on Windows at runtime, and panic if it can't find something to link to. Rust +/// code could then use `my_c_function` as if it were any other unsafe Rust function. Working with +/// non-Rust languages and FFI is inherently unsafe, so wrappers are usually built around C APIs. +/// +/// The mirror use case of FFI is also done via the `extern` keyword: +/// +/// ```rust +/// #[no_mangle] +/// pub extern fn callable_from_c(x: i32) -> bool { +/// x % 3 == 0 +/// } +/// ``` +/// +/// If compiled as a dylib, the resulting .so could then be linked to from a C library, and the +/// function could be used as if it was from any other library. +/// +/// For more information on FFI, check the [Rust book] or the [Reference]. +/// +/// [Rust book]: +/// https://doc.rust-lang.org/book/second-edition/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code +/// [Reference]: https://doc.rust-lang.org/reference/items/external-blocks.html +mod extern_keyword { } + #[doc(keyword = "fn")] // -/// The `fn` keyword. +/// The keyword for defining functions. /// -/// The `fn` keyword is used to declare a function. +/// Functions are the primary way code is executed within Rust. Function blocks, usually just +/// called functions, can be defined in a variety of different places and be assigned many +/// different attributes and modifiers. /// -/// Example: +/// Standalone functions that just sit within a module not attached to anything else are common, +/// but most functions will end up being inside [`impl`] blocks, either on another type itself, or +/// as a trait impl for that type. /// /// ```rust -/// fn some_function() { -/// // code goes in here +/// fn standalone_function() { +/// // code +/// } +/// +/// pub fn public_thing(argument: bool) -> String { +/// // code +/// # "".to_string() +/// } +/// +/// struct Thing { +/// foo: i32, +/// } +/// +/// impl Thing { +/// pub fn new() -> Self { +/// Self { +/// foo: 42, +/// } +/// } /// } /// ``` /// -/// For more information about functions, take a look at the [Rust Book][book]. +/// In addition to presenting fixed types in the form of `fn name(arg: type, ..) -> return_type`, +/// functions can also declare a list of type parameters along with trait bounds that they fall +/// into. /// -/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html +/// ```rust +/// fn generic_function(x: T) -> (T, T, T) { +/// (x.clone(), x.clone(), x.clone()) +/// } +/// +/// fn generic_where(x: T) -> T +/// where T: std::ops::Add + Copy +/// { +/// x + x + x +/// } +/// ``` +/// +/// Declaring trait bounds in the angle brackets is functionally identical to using a `where` +/// clause. It's up to the programmer to decide which works better in each situation, but `where` +/// tends to be better when things get longer than one line. +/// +/// Along with being made public via `pub`, `fn` can also have an [`extern`] added for use in +/// FFI. +/// +/// For more information on the various types of functions and how they're used, consult the [Rust +/// book] or the [Reference]. +/// +/// [`impl`]: keyword.impl.html +/// [`extern`]: keyword.extern.html +/// [Rust book]: https://doc.rust-lang.org/book/second-edition/ch03-03-how-functions-work.html +/// [Reference]: https://doc.rust-lang.org/reference/items/functions.html mod fn_keyword { } -#[doc(keyword = "let")] +#[doc(keyword = "for")] // -/// The `let` keyword. +/// The `for` keyword. +/// +/// `for` is primarily used in for-in-loops, but it has a few other pieces of syntactic uses such as +/// `impl Trait for Type` (see [`impl`] for more info on that). for-in-loops, or to be more +/// precise, iterator loops, are a simple syntactic sugar over an exceedingly common practice +/// within Rust, which is to loop over an iterator until that iterator returns None (or `break` +/// is called). +/// +/// ```rust +/// for i in 0..5 { +/// println!("{}", i * 2); +/// } /// -/// The `let` keyword is used to declare a variable. +/// for i in std::iter::repeat(5) { +/// println!("turns out {} never stops being 5", i); +/// break; // would loop forever otherwise +/// } /// -/// Example: +/// 'outer: for x in 5..50 { +/// for y in 0..10 { +/// if x == y { +/// break 'outer; +/// } +/// } +/// } +/// ``` +/// +/// As shown in the example above, `for` loops (along with all other loops) can be tagged, using +/// similar syntax to lifetimes (only visually similar, entirely distinct in practice). Giving the +/// same tag to `break` breaks the tagged loop, which is useful for inner loops. It is definitely +/// not a goto. +/// +/// A `for` loop expands as shown: /// /// ```rust -/// # #![allow(unused_assignments)] -/// let x = 3; // We create a variable named `x` with the value `3`. +/// # fn code() { } +/// # let iterator = 0..2; +/// for loop_variable in iterator { +/// code() +/// } +/// ``` +/// +/// ```rust +/// # fn code() { } +/// # let iterator = 0..2; +/// { +/// let mut _iter = std::iter::IntoIterator::into_iter(iterator); +/// loop { +/// match _iter.next() { +/// Some(loop_variable) => { +/// code() +/// }, +/// None => break, +/// } +/// } +/// } +/// ``` +/// +/// More details on the functionality shown can be seen at the [`IntoIterator`] docs. +/// +/// For more information on for-loops, see the [Rust book] or the [Reference]. +/// +/// [`impl`]: keyword.impl.html +/// [`IntoIterator`]: iter/trait.IntoIterator.html +/// [Rust book]: +/// https://doc.rust-lang.org/book/2018-edition/ch03-05-control-flow.html#looping-through-a-collection-with-for +/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops +mod for_keyword { } + +#[doc(keyword = "if")] +// +/// If statements and expressions. +/// +/// `if` is a familiar construct to most programmers, and is the main way you'll often do logic in +/// your code. However, unlike in most languages, `if` blocks can also act as expressions. +/// +/// ```rust +/// # let rude = true; +/// if 1 == 2 { +/// println!("whoops, mathematics broke"); +/// } else { +/// println!("everything's fine!"); +/// } +/// +/// let greeting = if rude { +/// "sup nerd." +/// } else { +/// "hello, friend!" +/// }; +/// +/// if let Ok(x) = "123".parse::() { +/// println!("{} double that and you get {}!", greeting, x * 2); +/// } +/// ``` +/// +/// Shown above are the three typical forms an `if` block comes in. First is the usual kind of +/// thing you'd see in many languages, with an optional `else` block. Second uses `if` as an +/// expression, which is only possible if all branches return the same type. An `if` expression can +/// be used everywhere you'd expect. The third kind of `if` block is an `if let` block, which +/// behaves similarly to using a `match` expression: +/// +/// ```rust +/// if let Some(x) = Some(123) { +/// // code +/// # let _ = x; +/// } else { +/// // something else +/// } +/// +/// match Some(123) { +/// Some(x) => { +/// // code +/// # let _ = x; +/// }, +/// _ => { +/// // something else +/// }, +/// } +/// ``` +/// +/// Each kind of `if` expression can be mixed and matched as needed. +/// +/// ```rust +/// if true == false { +/// println!("oh no"); +/// } else if "something" == "other thing" { +/// println!("oh dear"); +/// } else if let Some(200) = "blarg".parse::().ok() { +/// println!("uh oh"); +/// } else { +/// println!("phew, nothing's broken"); +/// } +/// ``` +/// +/// The `if` keyword is used in one other place in Rust, namely as a part of pattern matching +/// itself, allowing patterns such as `Some(x) if x > 200` to be used. +/// +/// For more information on `if` expressions, see the [Rust book] or the [Reference]. +/// +/// [Rust book]: +/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-05-control-flow.html#if-expressions +/// [Reference]: https://doc.rust-lang.org/reference/expressions/if-expr.html +mod if_keyword { } + +#[doc(keyword = "impl")] +// +/// The implementation-defining keyword. +/// +/// The `impl` keyword is primarily used to define implementations on types. Inherent +/// implementations are standalone, while trait implementations are used to implement traits for +/// types, or other traits. +/// +/// Functions and consts can both be defined in an implementation. A function defined in an +/// `impl` block can be standalone, meaning it would be called like `Foo::bar()`. If the function +/// takes `self`, `&self`, or `&mut self` as its first argument, it can also be called using +/// method-call syntax, a familiar feature to any object oriented programmer, like `foo.bar()`. +/// +/// ```rust +/// struct Example { +/// number: i32, +/// } +/// +/// impl Example { +/// fn boo() { +/// println!("boo! Example::boo() was called!"); +/// } +/// +/// fn answer(&mut self) { +/// self.number += 42; +/// } +/// +/// fn get_number(&self) -> i32 { +/// self.number +/// } +/// } +/// +/// trait Thingy { +/// fn do_thingy(&self); +/// } +/// +/// impl Thingy for Example { +/// fn do_thingy(&self) { +/// println!("doing a thing! also, number is {}!", self.number); +/// } +/// } /// ``` /// -/// By default, all variables are **not** mutable. If you want a mutable variable, -/// you'll have to use the `mut` keyword. +/// For more information on implementations, see the [Rust book][book1] or the [Reference]. /// -/// Example: +/// The other use of the `impl` keyword is in `impl Trait` syntax, which can be seen as a shorthand +/// for "a concrete type that implements this trait". Its primary use is working with closures, +/// which have type definitions generated at compile time that can't be simply typed out. +/// +/// ```rust +/// fn thing_returning_closure() -> impl Fn(i32) -> bool { +/// println!("here's a closure for you!"); +/// |x: i32| x % 3 == 0 +/// } +/// ``` +/// +/// For more information on `impl Trait` syntax, see the [Rust book][book2]. +/// +/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch05-03-method-syntax.html +/// [Reference]: https://doc.rust-lang.org/reference/items/implementations.html +/// [book2]: +/// https://doc.rust-lang.org/stable/book/2018-edition/ch10-02-traits.html#returning-traits +mod impl_keyword { } + +#[doc(keyword = "let")] +// +/// The variable binding keyword. +/// +/// The primary use for the `let` keyword is in `let` statements, which are used to introduce a new +/// set of variables into the current scope, as given by a pattern. /// /// ```rust /// # #![allow(unused_assignments)] -/// let mut x = 3; // We create a mutable variable named `x` with the value `3`. +/// let thing1: i32 = 100; +/// let thing2 = 200 + thing1; +/// +/// let mut changing_thing = true; +/// changing_thing = false; /// -/// x += 4; // `x` is now equal to `7`. +/// let (part1, part2) = ("first", "second"); +/// +/// struct Example { +/// a: bool, +/// b: u64, +/// } +/// +/// let Example { a, b: _ } = Example { +/// a: true, +/// b: 10004, +/// }; +/// assert!(a); +/// ``` +/// +/// The pattern is most commonly a single variable, which means no pattern matching is done and +/// the expression given is bound to the variable. Apart from that, patterns used in `let` bindings +/// can be as complicated as needed, given that the pattern is exhaustive. See the [Rust +/// book][book1] for more information on pattern matching. The type of the pattern is optionally +/// given afterwards, but if left blank is automatically inferred by the compiler if possible. +/// +/// Variables in Rust are immutable by default, and require the `mut` keyword to be made mutable. +/// +/// Multiple variables can be defined with the same name, known as shadowing. This doesn't affect +/// the original variable in any way beyond being unable to directly access it beyond the point of +/// shadowing. It continues to remain in scope, getting dropped only when it falls out of scope. +/// Shadowed variables don't need to have the same type as the variables shadowing them. +/// +/// ```rust +/// let shadowing_example = true; +/// let shadowing_example = 123.4; +/// let shadowing_example = shadowing_example as u32; +/// let mut shadowing_example = format!("cool! {}", shadowing_example); +/// shadowing_example += " something else!"; // not shadowing /// ``` /// -/// For more information about the `let` keyword, take a look at the [Rust Book][book]. +/// Other places the `let` keyword is used include along with [`if`], in the form of `if let` +/// expressions. They're useful if the pattern being matched isn't exhaustive, such as with +/// enumerations. `while let` also exists, which runs a loop with a pattern matched value until +/// that pattern can't be matched. /// -/// [book]: https://doc.rust-lang.org/book/second-edition/ch03-01-variables-and-mutability.html +/// For more information on the `let` keyword, see the [Rust book] or the [Reference] +/// +/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch06-02-match.html +/// [`if`]: keyword.if.html +/// [book2]: +/// https://doc.rust-lang.org/stable/book/2018-edition/ch18-01-all-the-places-for-patterns.html#let-statements +/// [Reference]: https://doc.rust-lang.org/reference/statements.html#let-statements mod let_keyword { } -#[doc(keyword = "struct")] +#[doc(keyword = "loop")] // -/// The `struct` keyword. +/// The loop-defining keyword. /// -/// The `struct` keyword is used to define a struct type. +/// `loop` is used to define the simplest kind of loop supported in Rust. It runs the code inside +/// it until the code uses `break` or the program exits. /// -/// Example: +/// ```rust +/// loop { +/// println!("hello world forever!"); +/// # break; +/// } /// +/// let mut i = 0; +/// loop { +/// println!("i is {}", i); +/// if i > 10 { +/// break; +/// } +/// i += 1; +/// } /// ``` -/// struct Foo { -/// field1: u32, +/// +/// Unlike the other kinds of loops in Rust (`while`, `while let`, and `for`), loops can be used as +/// expressions that return values via `break`. +/// +/// ```rust +/// let mut i = 1; +/// let something = loop { +/// i *= 2; +/// if i > 100 { +/// break i; +/// } +/// }; +/// assert_eq!(something, 128); +/// ``` +/// +/// Every `break` in a loop has to have the same type. When it's not explicitly giving something, +/// `break;` returns `()`. +/// +/// For more information on `loop` and loops in general, see the [Reference]. +/// +/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html +mod loop_keyword { } + +#[doc(keyword = "struct")] +// +/// The keyword used to define structs. +/// +/// Structs in Rust come in three flavours: Structs with named fields, tuple structs, and unit +/// structs. +/// +/// ```rust +/// struct Regular { +/// field1: f32, /// field2: String, +/// pub field3: bool +/// } +/// +/// struct Tuple(u32, String); +/// +/// struct Unit; +/// ``` +/// +/// Regular structs are the most commonly used. Each field defined within them has a name and a +/// type, and once defined can be accessed using `example_struct.field` syntax. The fields of a +/// struct share its mutability, so `foo.bar = 2;` would only be valid if `foo` was mutable. Adding +/// `pub` to a field makes it visible to code in other modules, as well as allowing it to be +/// directly accessed and modified. +/// +/// Tuple structs are similar to regular structs, but its fields have no names. They are used like +/// tuples, with deconstruction possible via `let TupleStruct(x, y) = foo;` syntax. For accessing +/// individual variables, the same syntax is used as with regular tuples, namely `foo.0`, `foo.1`, +/// etc, starting at zero. +/// +/// Unit structs are most commonly used as marker. They have a size of zero bytes, but unlike empty +/// enums they can be instantiated, making them isomorphic to the unit type `()`. Unit structs are +/// useful when you need to implement a trait on something, but don't need to store any data inside +/// it. +/// +/// # Instantiation +/// +/// Structs can be instantiated in different ways, all of which can be mixed and +/// matched as needed. The most common way to make a new struct is via a constructor method such as +/// `new()`, but when that isn't available (or you're writing the constructor itself), struct +/// literal syntax is used: +/// +/// ```rust +/// # struct Foo { field1: f32, field2: String, etc: bool } +/// let example = Foo { +/// field1: 42.0, +/// field2: "blah".to_string(), +/// etc: true, +/// }; +/// ``` +/// +/// It's only possible to directly instantiate a struct using struct literal syntax when all of its +/// fields are visible to you. +/// +/// There are a handful of shortcuts provided to make writing constructors more convenient, most +/// common of which is the Field Init shorthand. When there is a variable and a field of the same +/// name, the assignment can be simplified from `field: field` into simply `field`. The following +/// example of a hypothetical constructor demonstrates this: +/// +/// ```rust +/// struct User { +/// name: String, +/// admin: bool, +/// } +/// +/// impl User { +/// pub fn new(name: String) -> Self { +/// Self { +/// name, +/// admin: false, +/// } +/// } /// } /// ``` /// -/// There are different kinds of structs. For more information, take a look at the -/// [Rust Book][book]. +/// Another shortcut for struct instantiation is available, used when you need to make a new +/// struct that has the same values as most of a previous struct of the same type, called struct +/// update syntax: +/// +/// ```rust +/// # struct Foo { field1: String, field2: () } +/// # let thing = Foo { field1: "".to_string(), field2: () }; +/// let updated_thing = Foo { +/// field1: "a new value".to_string(), +/// ..thing +/// }; +/// ``` +/// +/// Tuple structs are instantiated in the same way as tuples themselves, except with the struct's +/// name as a prefix: `Foo(123, false, 0.1)`. +/// +/// Empty structs are instantiated with just their name, and don't need anything else. `let thing = +/// EmptyStruct;` +/// +/// # Style conventions +/// +/// Structs are always written in CamelCase, with few exceptions. While the trailing comma on a +/// struct's list of fields can be omitted, it's usually kept for convenience in adding and +/// removing fields down the line. +/// +/// For more information on structs, take a look at the [Rust Book][book] or the +/// [Reference][reference]. /// +/// [`PhantomData`]: marker/struct.PhantomData.html /// [book]: https://doc.rust-lang.org/book/second-edition/ch05-01-defining-structs.html +/// [reference]: https://doc.rust-lang.org/reference/items/structs.html mod struct_keyword { } diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 75c7a3d9280..ad212a54757 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -43,12 +43,12 @@ /// use std::io::prelude::*; /// use std::net::TcpStream; /// -/// { -/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// fn main() -> std::io::Result<()> { +/// let mut stream = TcpStream::connect("127.0.0.1:34254")?; /// -/// // ignore the Result -/// let _ = stream.write(&[1]); -/// let _ = stream.read(&mut [0; 128]); // ignore here too +/// stream.write(&[1])?; +/// stream.read(&mut [0; 128])?; +/// Ok(()) /// } // the stream is closed here /// ``` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 3b432d05132..c2a16122a0d 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -323,8 +323,8 @@ mod prim_never { } /// let s = String::from("love: ❤️"); /// let v: Vec = s.chars().collect(); /// -/// assert_eq!(12, s.len() * std::mem::size_of::()); -/// assert_eq!(32, v.len() * std::mem::size_of::()); +/// assert_eq!(12, std::mem::size_of_val(&s[..])); +/// assert_eq!(32, std::mem::size_of_val(&v[..])); /// ``` #[stable(feature = "rust1", since = "1.0.0")] mod prim_char { } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 58ac4e94408..a9219f75362 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1016,6 +1016,28 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[stable(feature = "stdio_from", since = "1.20.0")] impl From for Stdio { + /// Converts a `ChildStdin` into a `Stdio` + /// + /// # Examples + /// + /// `ChildStdin` will be converted to `Stdio` using `Stdio::from` under the hood. + /// + /// ```rust + /// use std::process::{Command, Stdio}; + /// + /// let reverse = Command::new("rev") + /// .stdin(Stdio::piped()) + /// .spawn() + /// .expect("failed reverse command"); + /// + /// let _echo = Command::new("echo") + /// .arg("Hello, world!") + /// .stdout(reverse.stdin.unwrap()) // Converted into a Stdio here + /// .output() + /// .expect("failed echo command"); + /// + /// // "!dlrow ,olleH" echoed to console + /// ``` fn from(child: ChildStdin) -> Stdio { Stdio::from_inner(child.into_inner().into()) } @@ -1023,6 +1045,28 @@ fn from(child: ChildStdin) -> Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From for Stdio { + /// Converts a `ChildStdout` into a `Stdio` + /// + /// # Examples + /// + /// `ChildStdout` will be converted to `Stdio` using `Stdio::from` under the hood. + /// + /// ```rust + /// use std::process::{Command, Stdio}; + /// + /// let hello = Command::new("echo") + /// .arg("Hello, world!") + /// .stdout(Stdio::piped()) + /// .spawn() + /// .expect("failed echo command"); + /// + /// let reverse = Command::new("rev") + /// .stdin(hello.stdout.unwrap()) // Converted into a Stdio here + /// .output() + /// .expect("failed reverse command"); + /// + /// assert_eq!(reverse.stdout, b"!dlrow ,olleH\n"); + /// ``` fn from(child: ChildStdout) -> Stdio { Stdio::from_inner(child.into_inner().into()) } @@ -1030,6 +1074,30 @@ fn from(child: ChildStdout) -> Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From for Stdio { + /// Converts a `ChildStderr` into a `Stdio` + /// + /// # Examples + /// + /// ```rust,no_run + /// use std::process::{Command, Stdio}; + /// + /// let reverse = Command::new("rev") + /// .arg("non_existing_file.txt") + /// .stderr(Stdio::piped()) + /// .spawn() + /// .expect("failed reverse command"); + /// + /// let cat = Command::new("cat") + /// .arg("-") + /// .stdin(reverse.stderr.unwrap()) // Converted into a Stdio here + /// .output() + /// .expect("failed echo command"); + /// + /// assert_eq!( + /// String::from_utf8_lossy(&cat.stdout), + /// "rev: cannot open non_existing_file.txt: No such file or directory\n" + /// ); + /// ``` fn from(child: ChildStderr) -> Stdio { Stdio::from_inner(child.into_inner().into()) } @@ -1037,6 +1105,26 @@ fn from(child: ChildStderr) -> Stdio { #[stable(feature = "stdio_from", since = "1.20.0")] impl From for Stdio { + /// Converts a `File` into a `Stdio` + /// + /// # Examples + /// + /// `File` will be converted to `Stdio` using `Stdio::from` under the hood. + /// + /// ```rust,no_run + /// use std::fs::File; + /// use std::process::Command; + /// + /// // With the `foo.txt` file containing `Hello, world!" + /// let file = File::open("foo.txt").unwrap(); + /// + /// let reverse = Command::new("rev") + /// .stdin(file) // Implicit File convertion into a Stdio + /// .output() + /// .expect("failed reverse command"); + /// + /// assert_eq!(reverse.stdout, b"!dlrow ,olleH"); + /// ``` fn from(file: fs::File) -> Stdio { Stdio::from_inner(file.into_inner().into()) } diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index d69ebc17622..a7db372a0e2 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -97,7 +97,7 @@ //! - A **multiprocessor** system executing multiple hardware threads //! at the same time: In multi-threaded scenarios, you can use two //! kinds of primitives to deal with synchronization: -//! - [memory fences] to ensure memory accesses are made visibile to +//! - [memory fences] to ensure memory accesses are made visible to //! other CPUs in the right order. //! - [atomic operations] to ensure simultaneous access to the same //! memory location doesn't lead to undefined behavior. diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 98845e457b2..cf9698cb2a9 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -290,8 +290,8 @@ pub fn call_once_force(&self, f: F) where F: FnOnce(&OnceState) { } /// Returns true if some `call_once` call has completed - /// successfuly. Specifically, `is_completed` will return false in - /// the following situtations: + /// successfully. Specifically, `is_completed` will return false in + /// the following situations: /// * `call_once` was not called at all, /// * `call_once` was called, but has not yet completed, /// * the `Once` instance is poisoned diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9ed628e2ed3..ee82b986005 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -129,6 +129,8 @@ pub struct PathSegment { /// The identifier portion of this path segment. pub ident: Ident, + pub id: NodeId, + /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. /// `None` means that no parameter list is supplied (`Path`), @@ -140,7 +142,7 @@ pub struct PathSegment { impl PathSegment { pub fn from_ident(ident: Ident) -> Self { - PathSegment { ident, args: None } + PathSegment { ident, id: DUMMY_NODE_ID, args: None } } pub fn crate_root(span: Span) -> Self { PathSegment::from_ident(Ident::new(keywords::CrateRoot.name(), span)) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index e611eb86dc1..d8fb20d4250 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -96,7 +96,7 @@ pub fn process_cfg_attrs(&mut self, node: T) -> T { /// when the configuration predicate is true, or otherwise expand into an /// empty list of attributes. /// - /// Gives a compiler warning when the `cfg_attr` contains no attribtes and + /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { @@ -138,7 +138,7 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { }; // Check feature gate and lint on zero attributes in source. Even if the feature is gated, - // we still compute as if it wasn't, since the emitted error will stop compilation futher + // we still compute as if it wasn't, since the emitted error will stop compilation further // along the compilation. match (expanded_attrs.len(), gate_cfg_attr_multi) { (0, false) => { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 5bf1a7dd663..1701c8da2c5 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -247,8 +247,13 @@ fn expand<'cx>(&self, /// Represents a thing that maps token trees to Macro Results pub trait TTMacroExpander { - fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream) - -> Box; + fn expand<'cx>( + &self, + ecx: &'cx mut ExtCtxt, + span: Span, + input: TokenStream, + def_span: Option, + ) -> Box; } pub type MacroExpanderFn = @@ -259,8 +264,13 @@ impl TTMacroExpander for F where F: for<'cx> Fn(&'cx mut ExtCtxt, Span, &[tokenstream::TokenTree]) -> Box { - fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream) - -> Box { + fn expand<'cx>( + &self, + ecx: &'cx mut ExtCtxt, + span: Span, + input: TokenStream, + _def_span: Option, + ) -> Box { struct AvoidInterpolatedIdents; impl Folder for AvoidInterpolatedIdents { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 6210003a40d..7928ec1606b 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -329,7 +329,11 @@ fn path_all(&self, } else { None }; - segments.push(ast::PathSegment { ident: last_ident.with_span_pos(span), args }); + segments.push(ast::PathSegment { + ident: last_ident.with_span_pos(span), + id: ast::DUMMY_NODE_ID, + args, + }); let mut path = ast::Path { span, segments }; if global { if let Some(seg) = path.make_root() { @@ -366,7 +370,7 @@ fn qpath_all(&self, } else { None }; - path.segments.push(ast::PathSegment { ident, args }); + path.segments.push(ast::PathSegment { ident, id: ast::DUMMY_NODE_ID, args }); (ast::QSelf { ty: self_type, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9e06384f5a8..33b651e1b38 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -764,7 +764,7 @@ fn expand_bang_invoc(&mut self, edition) { dummy_span } else { - kind.make_from(expander.expand(self.cx, span, mac.node.stream())) + kind.make_from(expander.expand(self.cx, span, mac.node.stream(), None)) } } @@ -785,7 +785,12 @@ fn expand_bang_invoc(&mut self, edition) { dummy_span } else { - kind.make_from(expander.expand(self.cx, span, mac.node.stream())) + kind.make_from(expander.expand( + self.cx, + span, + mac.node.stream(), + def_info.map(|(_, s)| s), + )) } } @@ -1036,10 +1041,28 @@ pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span // Avoid emitting backtrace info twice. let def_site_span = self.span.with_ctxt(SyntaxContext::empty()); let mut err = self.diagnostic().struct_span_err(def_site_span, &msg); - let msg = format!("caused by the macro expansion here; the usage \ - of `{}!` is likely invalid in {} context", - macro_path, kind_name); - err.span_note(span, &msg).emit(); + err.span_label(span, "caused by the macro expansion here"); + let msg = format!( + "the usage of `{}!` is likely invalid in {} context", + macro_path, + kind_name, + ); + err.note(&msg); + let semi_span = self.sess.source_map().next_point(span); + + let semi_full_span = semi_span.to(self.sess.source_map().next_point(semi_span)); + match self.sess.source_map().span_to_snippet(semi_full_span) { + Ok(ref snippet) if &snippet[..] != ";" && kind_name == "expression" => { + err.span_suggestion_with_applicability( + semi_span, + "you might be missing a semicolon here", + ";".to_owned(), + Applicability::MaybeIncorrect, + ); + } + _ => {} + } + err.emit(); } } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 87ade278c68..f298d626cd8 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -50,7 +50,12 @@ pub struct ParserAnyMacro<'a> { impl<'a> ParserAnyMacro<'a> { pub fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, ref mut parser } = *self; - let fragment = panictry!(parser.parse_ast_fragment(kind, true)); + let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| { + if e.span.is_dummy() { // Get around lack of span in error (#30128) + e.set_span(site_span); + } + e + })); // We allow semicolons at the end of expressions -- e.g. the semicolon in // `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`, @@ -74,16 +79,19 @@ struct MacroRulesMacroExpander { } impl TTMacroExpander for MacroRulesMacroExpander { - fn expand<'cx>(&self, - cx: &'cx mut ExtCtxt, - sp: Span, - input: TokenStream) - -> Box { + fn expand<'cx>( + &self, + cx: &'cx mut ExtCtxt, + sp: Span, + input: TokenStream, + def_span: Option, + ) -> Box { if !self.valid { return DummyResult::any(sp); } generic_extension(cx, sp, + def_span, self.name, input, &self.lhses, @@ -99,6 +107,7 @@ fn trace_macros_note(cx: &mut ExtCtxt, sp: Span, message: String) { /// Given `lhses` and `rhses`, this is the new macro we create fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, sp: Span, + def_span: Option, name: ast::Ident, arg: TokenStream, lhses: &[quoted::TokenTree], @@ -178,7 +187,14 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, } let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers")); - let mut err = cx.struct_span_err(best_fail_spot.substitute_dummy(sp), &best_fail_msg); + let span = best_fail_spot.substitute_dummy(sp); + let mut err = cx.struct_span_err(span, &best_fail_msg); + err.span_label(span, best_fail_msg); + if let Some(sp) = def_span { + if cx.source_map().span_to_filename(sp).is_real() && !sp.is_dummy() { + err.span_label(cx.source_map().def_span(sp), "when calling this macro"); + } + } // Check whether there's a missing comma in this macro call, like `println!("{}" a);` if let Some((arg, comma_span)) = arg.add_comma() { @@ -189,7 +205,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, }; match TokenTree::parse(cx, lhs_tt, arg.clone()) { Success(_) => { - if comma_span == DUMMY_SP { + if comma_span.is_dummy() { err.note("you might be missing a comma"); } else { err.span_suggestion_short_with_applicability( @@ -792,15 +808,15 @@ fn check_matcher_core(sess: &ParseSess, if let TokenTree::MetaVarDecl(_, ref name, ref frag_spec) = *token { for next_token in &suffix_first.tokens { match is_in_follow(next_token, &frag_spec.as_str()) { - Err((msg, help)) => { + IsInFollow::Invalid(msg, help) => { sess.span_diagnostic.struct_span_err(next_token.span(), &msg) .help(help).emit(); // don't bother reporting every source of // conflict for a particular element of `last`. continue 'each_last; } - Ok(true) => {} - Ok(false) => { + IsInFollow::Yes => {} + IsInFollow::No(ref possible) => { let may_be = if last.tokens.len() == 1 && suffix_first.tokens.len() == 1 { @@ -809,15 +825,41 @@ fn check_matcher_core(sess: &ParseSess, "may be" }; - sess.span_diagnostic.span_err( - next_token.span(), + let sp = next_token.span(); + let mut err = sess.span_diagnostic.struct_span_err( + sp, &format!("`${name}:{frag}` {may_be} followed by `{next}`, which \ is not allowed for `{frag}` fragments", name=name, frag=frag_spec, next=quoted_tt_to_string(next_token), - may_be=may_be) + may_be=may_be), ); + err.span_label( + sp, + format!("not allowed after `{}` fragments", frag_spec), + ); + let msg = "allowed there are: "; + match &possible[..] { + &[] => {} + &[t] => { + err.note(&format!( + "only {} is allowed after `{}` fragments", + t, + frag_spec, + )); + } + ts => { + err.note(&format!( + "{}{} or {}", + msg, + ts[..ts.len() - 1].iter().map(|s| *s) + .collect::>().join(", "), + ts[ts.len() - 1], + )); + } + } + err.emit(); } } } @@ -860,6 +902,12 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool { } } +enum IsInFollow { + Yes, + No(Vec<&'static str>), + Invalid(String, &'static str), +} + /// True if `frag` can legally be followed by the token `tok`. For /// fragments that can consume an unbounded number of tokens, `tok` /// must be within a well-defined follow set. This is intended to @@ -868,80 +916,99 @@ fn frag_can_be_followed_by_any(frag: &str) -> bool { /// break macros that were relying on that binary operator as a /// separator. // when changing this do not forget to update doc/book/macros.md! -fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result { +fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { use self::quoted::TokenTree; if let TokenTree::Token(_, token::CloseDelim(_)) = *tok { // closing a token tree can never be matched by any fragment; // iow, we always require that `(` and `)` match, etc. - Ok(true) + IsInFollow::Yes } else { match frag { "item" => { // since items *must* be followed by either a `;` or a `}`, we can // accept anything after them - Ok(true) + IsInFollow::Yes }, "block" => { // anything can follow block, the braces provide an easy boundary to // maintain - Ok(true) + IsInFollow::Yes }, - "stmt" | "expr" => match *tok { - TokenTree::Token(_, ref tok) => match *tok { - FatArrow | Comma | Semi => Ok(true), - _ => Ok(false) - }, - _ => Ok(false), + "stmt" | "expr" => { + let tokens = vec!["`=>`", "`,`", "`;`"]; + match *tok { + TokenTree::Token(_, ref tok) => match *tok { + FatArrow | Comma | Semi => IsInFollow::Yes, + _ => IsInFollow::No(tokens), + }, + _ => IsInFollow::No(tokens), + } }, - "pat" => match *tok { - TokenTree::Token(_, ref tok) => match *tok { - FatArrow | Comma | Eq | BinOp(token::Or) => Ok(true), - Ident(i, false) if i.name == "if" || i.name == "in" => Ok(true), - _ => Ok(false) - }, - _ => Ok(false), + "pat" => { + let tokens = vec!["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; + match *tok { + TokenTree::Token(_, ref tok) => match *tok { + FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes, + Ident(i, false) if i.name == "if" || i.name == "in" => IsInFollow::Yes, + _ => IsInFollow::No(tokens), + }, + _ => IsInFollow::No(tokens), + } }, - "path" | "ty" => match *tok { - TokenTree::Token(_, ref tok) => match *tok { - OpenDelim(token::DelimToken::Brace) | OpenDelim(token::DelimToken::Bracket) | - Comma | FatArrow | Colon | Eq | Gt | Semi | BinOp(token::Or) => Ok(true), - Ident(i, false) if i.name == "as" || i.name == "where" => Ok(true), - _ => Ok(false) - }, - TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => Ok(true), - _ => Ok(false), + "path" | "ty" => { + let tokens = vec![ + "`{`", "`[`", "`=>`", "`,`", "`>`","`=`", "`:`", "`;`", "`|`", "`as`", + "`where`", + ]; + match *tok { + TokenTree::Token(_, ref tok) => match *tok { + OpenDelim(token::DelimToken::Brace) | + OpenDelim(token::DelimToken::Bracket) | + Comma | FatArrow | Colon | Eq | Gt | BinOp(token::Shr) | Semi | + BinOp(token::Or) => IsInFollow::Yes, + Ident(i, false) if i.name == "as" || i.name == "where" => IsInFollow::Yes, + _ => IsInFollow::No(tokens), + }, + TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => IsInFollow::Yes, + _ => IsInFollow::No(tokens), + } }, "ident" | "lifetime" => { // being a single token, idents and lifetimes are harmless - Ok(true) + IsInFollow::Yes }, "literal" => { // literals may be of a single token, or two tokens (negative numbers) - Ok(true) + IsInFollow::Yes }, "meta" | "tt" => { // being either a single token or a delimited sequence, tt is // harmless - Ok(true) + IsInFollow::Yes }, "vis" => { // Explicitly disallow `priv`, on the off chance it comes back. + let tokens = vec!["`,`", "an ident", "a type"]; match *tok { TokenTree::Token(_, ref tok) => match *tok { - Comma => Ok(true), - Ident(i, is_raw) if is_raw || i.name != "priv" => Ok(true), - ref tok => Ok(tok.can_begin_type()) + Comma => IsInFollow::Yes, + Ident(i, is_raw) if is_raw || i.name != "priv" => IsInFollow::Yes, + ref tok => if tok.can_begin_type() { + IsInFollow::Yes + } else { + IsInFollow::No(tokens) + } }, TokenTree::MetaVarDecl(_, _, frag) if frag.name == "ident" || frag.name == "ty" - || frag.name == "path" => Ok(true), - _ => Ok(false) + || frag.name == "path" => IsInFollow::Yes, + _ => IsInFollow::No(tokens), } }, - "" => Ok(true), // keywords::Invalid - _ => Err((format!("invalid fragment specifier `{}`", frag), - VALID_FRAGMENT_NAMES_MSG)) + "" => IsInFollow::Yes, // keywords::Invalid + _ => IsInFollow::Invalid(format!("invalid fragment specifier `{}`", frag), + VALID_FRAGMENT_NAMES_MSG), } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d0f407aa924..2cd4fd92bc8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -501,6 +501,9 @@ pub fn walk_feature_fields(&self, mut f: F) // Allows `const _: TYPE = VALUE` (active, underscore_const_names, "1.31.0", Some(54912), None), + + // `extern crate foo as bar;` puts `bar` into extern prelude. + (active, extern_crate_item_prelude, "1.31.0", Some(54658), None), ); declare_features! ( diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 95a2298ca75..bec193548e1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -468,8 +468,9 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { pub fn noop_fold_path(Path { segments, span }: Path, fld: &mut T) -> Path { Path { - segments: segments.move_map(|PathSegment { ident, args }| PathSegment { + segments: segments.move_map(|PathSegment { ident, id, args }| PathSegment { ident: fld.fold_ident(ident), + id: fld.new_id(id), args: args.map(|args| args.map(|args| fld.fold_generic_args(args))), }), span: fld.new_span(span) @@ -965,7 +966,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { polarity, defaultness, folder.fold_generics(generics), - ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())), + ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref)), folder.fold_ty(ty), impl_items.move_flat_map(|item| folder.fold_impl_item(item)), ), @@ -1234,6 +1235,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::MethodCall( PathSegment { ident: folder.fold_ident(seg.ident), + id: folder.new_id(seg.id), args: seg.args.map(|args| { args.map(|args| folder.fold_generic_args(args)) }), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9c47589a0bd..589b3e30fcf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2134,7 +2134,7 @@ fn parse_path_segment(&mut self, style: PathStyle, enable_warning: bool) ParenthesisedArgs { inputs, output, span }.into() }; - PathSegment { ident, args } + PathSegment { ident, args, id: ast::DUMMY_NODE_ID } } else { // Generic arguments are not found. PathSegment::from_ident(ident) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 45eaf1d3190..639155636ed 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -612,6 +612,17 @@ pub fn primary_spans(&self) -> &[Span] { &self.primary_spans } + /// Returns `true` if this contains only a dummy primary span with any hygienic context. + pub fn is_dummy(&self) -> bool { + let mut is_dummy = true; + for span in &self.primary_spans { + if !span.is_dummy() { + is_dummy = false; + } + } + is_dummy + } + /// Replaces all occurrences of one Span with another. Used to move Spans in areas that don't /// display well (like std macros). Returns true if replacements occurred. pub fn replace(&mut self, before: Span, after: Span) -> bool { diff --git a/src/stdsimd b/src/stdsimd index 307650500de..431766a3fbc 160000 --- a/src/stdsimd +++ b/src/stdsimd @@ -1 +1 @@ -Subproject commit 307650500de5b44dc1047dc9d15e449e09d92b57 +Subproject commit 431766a3fbcfb6dafb2d5a3866c1609bf44ee554 diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs index 8469f0aa664..85d1f3df05b 100644 --- a/src/test/incremental/hashes/closure_expressions.rs +++ b/src/test/incremental/hashes/closure_expressions.rs @@ -95,7 +95,7 @@ pub fn add_type_ascription_to_parameter() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, MirValidated, TypeckTables")] #[rustc_clean(cfg="cfail3")] pub fn add_type_ascription_to_parameter() { let closure = |x: u32| x + 1u32; diff --git a/src/test/mir-opt/end_region_1.rs b/src/test/mir-opt/end_region_1.rs index 23c00c3bce1..dd1c2bd5126 100644 --- a/src/test/mir-opt/end_region_1.rs +++ b/src/test/mir-opt/end_region_1.rs @@ -22,7 +22,7 @@ fn main() { // START rustc.main.SimplifyCfg-qualify-consts.after.mir // let mut _0: (); // ... -// let _2: &'10_1rs i32; +// let _2: &'11_1rs i32; // ... // let _1: i32; // ... @@ -31,10 +31,10 @@ fn main() { // _1 = const 3i32; // FakeRead(ForLet, _1); // StorageLive(_2); -// _2 = &'10_1rs _1; +// _2 = &'11_1rs _1; // FakeRead(ForLet, _2); // _0 = (); -// EndRegion('10_1rs); +// EndRegion('11_1rs); // StorageDead(_2); // StorageDead(_1); // return; diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs index 08de5320a2b..6b0a28b8110 100644 --- a/src/test/mir-opt/end_region_2.rs +++ b/src/test/mir-opt/end_region_2.rs @@ -27,9 +27,9 @@ fn main() { // START rustc.main.SimplifyCfg-qualify-consts.after.mir // let mut _0: (); // ... -// let _7: &'23_3rs bool; +// let _7: &'26_3rs bool; // ... -// let _3: &'23_1rs bool; +// let _3: &'26_1rs bool; // ... // let _2: bool; // ... @@ -47,7 +47,7 @@ fn main() { // _2 = const true; // FakeRead(ForLet, _2); // StorageLive(_3); -// _3 = &'23_1rs _2; +// _3 = &'26_1rs _2; // FakeRead(ForLet, _3); // StorageLive(_5); // _5 = _2; @@ -59,7 +59,7 @@ fn main() { // bb4: { // _0 = (); // StorageDead(_5); -// EndRegion('23_1rs); +// EndRegion('26_1rs); // StorageDead(_3); // StorageDead(_2); // return; @@ -68,12 +68,12 @@ fn main() { // _4 = (); // StorageDead(_5); // StorageLive(_7); -// _7 = &'23_3rs _2; +// _7 = &'26_3rs _2; // FakeRead(ForLet, _7); // _1 = (); -// EndRegion('23_3rs); +// EndRegion('26_3rs); // StorageDead(_7); -// EndRegion('23_1rs); +// EndRegion('26_1rs); // StorageDead(_3); // StorageDead(_2); // goto -> bb1; diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs index 189154332b8..d8d48358e53 100644 --- a/src/test/mir-opt/end_region_3.rs +++ b/src/test/mir-opt/end_region_3.rs @@ -28,9 +28,9 @@ fn main() { // START rustc.main.SimplifyCfg-qualify-consts.after.mir // let mut _0: (); // ... -// let _7: &'26_3rs bool; +// let _7: &'30_3rs bool; // ... -// let _3: &'26_1rs bool; +// let _3: &'30_1rs bool; // ... // let mut _1: bool; // ... @@ -48,7 +48,7 @@ fn main() { // bb2: { // _1 = const true; // StorageLive(_3); -// _3 = &'26_1rs _1; +// _3 = &'30_1rs _1; // FakeRead(ForLet, _3); // StorageLive(_5); // _5 = _1; @@ -60,7 +60,7 @@ fn main() { // bb4: { // _0 = (); // StorageDead(_5); -// EndRegion('26_1rs); +// EndRegion('30_1rs); // StorageDead(_3); // StorageDead(_1); // return; @@ -69,12 +69,12 @@ fn main() { // _4 = (); // StorageDead(_5); // StorageLive(_7); -// _7 = &'26_3rs _1; +// _7 = &'30_3rs _1; // FakeRead(ForLet, _7); // _2 = (); -// EndRegion('26_3rs); +// EndRegion('30_3rs); // StorageDead(_7); -// EndRegion('26_1rs); +// EndRegion('30_1rs); // StorageDead(_3); // goto -> bb1; // } diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs index d5701669d2b..359ed07a9c0 100644 --- a/src/test/mir-opt/end_region_4.rs +++ b/src/test/mir-opt/end_region_4.rs @@ -32,9 +32,9 @@ fn foo(i: i32) { // START rustc.main.SimplifyCfg-qualify-consts.after.mir // let mut _0: (); // ... -// let _6: &'26_4rs i32; +// let _6: &'31_4rs i32; // ... -// let _3: &'26_2rs i32; +// let _3: &'31_2rs i32; // ... // let _2: i32; // ... @@ -50,7 +50,7 @@ fn foo(i: i32) { // _2 = const 0i32; // FakeRead(ForLet, _2); // StorageLive(_3); -// _3 = &'26_2rs _2; +// _3 = &'31_2rs _2; // FakeRead(ForLet, _3); // StorageLive(_5); // _5 = (*_3); @@ -62,18 +62,18 @@ fn foo(i: i32) { // bb2: { // StorageDead(_5); // StorageLive(_6); -// _6 = &'26_4rs _2; +// _6 = &'31_4rs _2; // FakeRead(ForLet, _6); // _0 = (); -// EndRegion('26_4rs); +// EndRegion('31_4rs); // StorageDead(_6); -// EndRegion('26_2rs); +// EndRegion('31_2rs); // StorageDead(_3); // StorageDead(_2); // drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { -// EndRegion('26_2rs); +// EndRegion('31_2rs); // drop(_1) -> bb1; // } // bb4: { diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs index 7a5d71ee21b..3b632e198cd 100644 --- a/src/test/mir-opt/end_region_5.rs +++ b/src/test/mir-opt/end_region_5.rs @@ -33,16 +33,16 @@ fn foo(f: F) where F: FnOnce() -> i32 { // let _1: D; // ... // let mut _2: (); -// let mut _3: [closure@NodeId(18) d:&'14s D]; -// let mut _4: &'14s D; +// let mut _3: [closure@NodeId(28) d:&'18s D]; +// let mut _4: &'18s D; // bb0: { // StorageLive(_1); // _1 = D::{{constructor}}(const 0i32,); // FakeRead(ForLet, _1); // StorageLive(_3); // StorageLive(_4); -// _4 = &'14s _1; -// _3 = [closure@NodeId(18)] { d: move _4 }; +// _4 = &'18s _1; +// _3 = [closure@NodeId(28)] { d: move _4 }; // StorageDead(_4); // _2 = const foo(move _3) -> [return: bb2, unwind: bb3]; // } @@ -50,13 +50,13 @@ fn foo(f: F) where F: FnOnce() -> i32 { // resume; // } // bb2: { -// EndRegion('14s); +// EndRegion('18s); // StorageDead(_3); // _0 = (); // drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { -// EndRegion('14s); +// EndRegion('18s); // drop(_1) -> bb1; // } // bb4: { @@ -67,11 +67,11 @@ fn foo(f: F) where F: FnOnce() -> i32 { // END rustc.main.SimplifyCfg-qualify-consts.after.mir // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(18) d:&'14s D]) -> i32 { +// fn main::{{closure}}(_1: [closure@NodeId(28) d:&'18s D]) -> i32 { // let mut _0: i32; // // bb0: { -// _0 = ((*(_1.0: &'14s D)).0: i32); +// _0 = ((*(_1.0: &'18s D)).0: i32); // return; // } // END rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs index b9162f85fa7..03c7de02ec1 100644 --- a/src/test/mir-opt/end_region_6.rs +++ b/src/test/mir-opt/end_region_6.rs @@ -33,16 +33,16 @@ fn foo(f: F) where F: FnOnce() -> i32 { // let _1: D; // ... // let mut _2: (); -// let mut _3: [closure@NodeId(22) d:&'19s D]; -// let mut _4: &'19s D; +// let mut _3: [closure@NodeId(33) d:&'24s D]; +// let mut _4: &'24s D; // bb0: { // StorageLive(_1); // _1 = D::{{constructor}}(const 0i32,); // FakeRead(ForLet, _1); // StorageLive(_3); // StorageLive(_4); -// _4 = &'19s _1; -// _3 = [closure@NodeId(22)] { d: move _4 }; +// _4 = &'24s _1; +// _3 = [closure@NodeId(33)] { d: move _4 }; // StorageDead(_4); // _2 = const foo(move _3) -> [return: bb2, unwind: bb3]; // } @@ -50,13 +50,13 @@ fn foo(f: F) where F: FnOnce() -> i32 { // resume; // } // bb2: { -// EndRegion('19s); +// EndRegion('24s); // StorageDead(_3); // _0 = (); // drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { -// EndRegion('19s); +// EndRegion('24s); // drop(_1) -> bb1; // } // bb4: { @@ -66,17 +66,17 @@ fn foo(f: F) where F: FnOnce() -> i32 { // END rustc.main.SimplifyCfg-qualify-consts.after.mir // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(22) d:&'19s D]) -> i32 { +// fn main::{{closure}}(_1: [closure@NodeId(33) d:&'24s D]) -> i32 { // let mut _0: i32; // ... -// let _2: &'16_0rs D; +// let _2: &'21_0rs D; // ... // bb0: { // StorageLive(_2); -// _2 = &'16_0rs (*(_1.0: &'19s D)); +// _2 = &'21_0rs (*(_1.0: &'24s D)); // FakeRead(ForLet, _2); // _0 = ((*_2).0: i32); -// EndRegion('16_0rs); +// EndRegion('21_0rs); // StorageDead(_2); // return; // } diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs index 4deea75e56b..56e3e0aa6f7 100644 --- a/src/test/mir-opt/end_region_7.rs +++ b/src/test/mir-opt/end_region_7.rs @@ -33,13 +33,13 @@ fn foo(f: F) where F: FnOnce() -> i32 { // let _1: D; // ... // let mut _2: (); -// let mut _3: [closure@NodeId(22) d:D]; +// let mut _3: [closure@NodeId(33) d:D]; // bb0: { // StorageLive(_1); // _1 = D::{{constructor}}(const 0i32,); // FakeRead(ForLet, _1); // StorageLive(_3); -// _3 = [closure@NodeId(22)] { d: move _1 }; +// _3 = [closure@NodeId(33)] { d: move _1 }; // _2 = const foo(move _3) -> [return: bb2, unwind: bb4]; // } // bb1: { @@ -67,17 +67,17 @@ fn foo(f: F) where F: FnOnce() -> i32 { // END rustc.main.SimplifyCfg-qualify-consts.after.mir // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 { +// fn main::{{closure}}(_1: [closure@NodeId(33) d:D]) -> i32 { // let mut _0: i32; // ... -// let _2: &'16_0rs D; +// let _2: &'21_0rs D; // ... // bb0: { // StorageLive(_2); -// _2 = &'16_0rs (_1.0: D); +// _2 = &'21_0rs (_1.0: D); // FakeRead(ForLet, _2); // _0 = ((*_2).0: i32); -// EndRegion('16_0rs); +// EndRegion('21_0rs); // StorageDead(_2); // drop(_1) -> [return: bb2, unwind: bb1]; // } diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs index 6f899a0db15..0a54dcaa0d3 100644 --- a/src/test/mir-opt/end_region_8.rs +++ b/src/test/mir-opt/end_region_8.rs @@ -31,37 +31,37 @@ fn foo(f: F) where F: FnOnce() -> i32 { // fn main() -> () { // let mut _0: (); // ... -// let _2: &'21_1rs D; +// let _2: &'26_1rs D; // ... // let _1: D; // ... // let mut _3: (); -// let mut _4: [closure@NodeId(22) r:&'19s D]; +// let mut _4: [closure@NodeId(33) r:&'24s D]; // bb0: { // StorageLive(_1); // _1 = D::{{constructor}}(const 0i32,); // FakeRead(ForLet, _1); // StorageLive(_2); -// _2 = &'21_1rs _1; +// _2 = &'26_1rs _1; // FakeRead(ForLet, _2); // StorageLive(_4); -// _4 = [closure@NodeId(22)] { r: _2 }; +// _4 = [closure@NodeId(33)] { r: _2 }; // _3 = const foo(move _4) -> [return: bb2, unwind: bb3]; // } // bb1: { // resume; // } // bb2: { -// EndRegion('19s); +// EndRegion('24s); // StorageDead(_4); // _0 = (); -// EndRegion('21_1rs); +// EndRegion('26_1rs); // StorageDead(_2); // drop(_1) -> [return: bb4, unwind: bb1]; // } // bb3: { -// EndRegion('19s); -// EndRegion('21_1rs); +// EndRegion('24s); +// EndRegion('26_1rs); // drop(_1) -> bb1; // } // bb4: { @@ -72,11 +72,11 @@ fn foo(f: F) where F: FnOnce() -> i32 { // END rustc.main.SimplifyCfg-qualify-consts.after.mir // START rustc.main-{{closure}}.SimplifyCfg-qualify-consts.after.mir -// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'19s D]) -> i32 { +// fn main::{{closure}}(_1: [closure@NodeId(33) r:&'24s D]) -> i32 { // let mut _0: i32; // // bb0: { -// _0 = ((*(_1.0: &'21_1rs D)).0: i32); +// _0 = ((*(_1.0: &'26_1rs D)).0: i32); // return; // } // } diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs index b43f25e6f54..ef2d949d307 100644 --- a/src/test/mir-opt/end_region_9.rs +++ b/src/test/mir-opt/end_region_9.rs @@ -41,7 +41,7 @@ fn main() { // fn main() -> () { // let mut _0: (); // ... -// let mut _4: &'33_0rs i32; +// let mut _4: &'37_0rs i32; // ... // let _2: i32; // ... @@ -79,14 +79,14 @@ fn main() { // bb5: { // _0 = (); // StorageDead(_7); -// EndRegion('33_0rs); +// EndRegion('37_0rs); // StorageDead(_4); // StorageDead(_2); // StorageDead(_1); // return; // } // bb6: { -// _4 = &'33_0rs _2; +// _4 = &'37_0rs _2; // _6 = (); // StorageDead(_7); // _1 = const true; diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 75cfb5c2f62..3dbc73caf65 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -45,24 +45,24 @@ fn query() -> bool { true } // scope 1 { // } // scope 2 { -// let _2: S<'36_0rs>; +// let _2: S<'49_0rs>; // } // let mut _1: (); -// let mut _3: std::cell::Cell>>; -// let mut _4: std::option::Option<&'36_0rs S<'36_0rs>>; +// let mut _3: std::cell::Cell>>; +// let mut _4: std::option::Option<&'49_0rs S<'49_0rs>>; // let mut _5: (); -// let mut _6: &'17s std::cell::Cell>>; -// let mut _7: std::option::Option<&'36_0rs S<'36_0rs>>; -// let mut _8: &'36_0rs S<'36_0rs>; -// let mut _9: &'36_0rs S<'36_0rs>; +// let mut _6: &'25s std::cell::Cell>>; +// let mut _7: std::option::Option<&'49_0rs S<'49_0rs>>; +// let mut _8: &'49_0rs S<'49_0rs>; +// let mut _9: &'49_0rs S<'49_0rs>; // let mut _10: (); // let mut _11: bool; // let mut _12: !; // let mut _13: (); -// let mut _14: &'34s std::cell::Cell>>; -// let mut _15: std::option::Option<&'36_0rs S<'36_0rs>>; -// let mut _16: &'36_0rs S<'36_0rs>; -// let mut _17: &'36_0rs S<'36_0rs>; +// let mut _14: &'47s std::cell::Cell>>; +// let mut _15: std::option::Option<&'49_0rs S<'49_0rs>>; +// let mut _16: &'49_0rs S<'49_0rs>; +// let mut _17: &'49_0rs S<'49_0rs>; // bb0: { // goto -> bb1; // } @@ -73,7 +73,7 @@ fn query() -> bool { true } // StorageLive(_2); // StorageLive(_3); // StorageLive(_4); -// _4 = std::option::Option<&'36_0rs S<'36_0rs>>::None; +// _4 = std::option::Option<&'49_0rs S<'49_0rs>>::None; // _3 = const >::new(move _4) -> [return: bb4, unwind: bb3]; // } // bb3: { @@ -81,22 +81,22 @@ fn query() -> bool { true } // } // bb4: { // StorageDead(_4); -// _2 = S<'36_0rs> { r: move _3 }; +// _2 = S<'49_0rs> { r: move _3 }; // StorageDead(_3); // FakeRead(ForLet, _2); // StorageLive(_6); -// _6 = &'17s (_2.0: std::cell::Cell>>); +// _6 = &'25s (_2.0: std::cell::Cell>>); // StorageLive(_7); // StorageLive(_8); // StorageLive(_9); -// _9 = &'36_0rs _2; -// _8 = &'36_0rs (*_9); -// _7 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _8,); +// _9 = &'49_0rs _2; +// _8 = &'49_0rs (*_9); +// _7 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _8,); // StorageDead(_8); // _5 = const >::set(move _6, move _7) -> [return: bb5, unwind: bb3]; // } // bb5: { -// EndRegion('17s); +// EndRegion('25s); // StorageDead(_7); // StorageDead(_6); // StorageDead(_9); @@ -109,7 +109,7 @@ fn query() -> bool { true } // bb7: { // _0 = (); // StorageDead(_11); -// EndRegion('36_0rs); +// EndRegion('49_0rs); // StorageDead(_2); // return; // } @@ -117,23 +117,23 @@ fn query() -> bool { true } // _10 = (); // StorageDead(_11); // StorageLive(_14); -// _14 = &'34s (_2.0: std::cell::Cell>>); +// _14 = &'47s (_2.0: std::cell::Cell>>); // StorageLive(_15); // StorageLive(_16); // StorageLive(_17); -// _17 = &'36_0rs _2; -// _16 = &'36_0rs (*_17); -// _15 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _16,); +// _17 = &'49_0rs _2; +// _16 = &'49_0rs (*_17); +// _15 = std::option::Option<&'49_0rs S<'49_0rs>>::Some(move _16,); // StorageDead(_16); // _13 = const >::set(move _14, move _15) -> [return: bb9, unwind: bb3]; // } // bb9: { -// EndRegion('34s); +// EndRegion('47s); // StorageDead(_15); // StorageDead(_14); // StorageDead(_17); // _1 = (); -// EndRegion('36_0rs); +// EndRegion('49_0rs); // StorageDead(_2); // goto -> bb1; // } diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs index 16e2fe046fb..a5107d30438 100644 --- a/src/test/mir-opt/end_region_destruction_extents_1.rs +++ b/src/test/mir-opt/end_region_destruction_extents_1.rs @@ -41,16 +41,16 @@ fn drop(&mut self) { // Notes on the MIR output below: // -// 1. The `EndRegion('10s)` is allowed to precede the `drop(_3)` +// 1. The `EndRegion('13s)` is allowed to precede the `drop(_3)` // solely because of the #[may_dangle] mentioned above. // -// 2. Regarding the occurrence of `EndRegion('12ds)` *after* `StorageDead(_6)` -// (where we have borrows `&'12ds _6`): Eventually: +// 2. Regarding the occurrence of `EndRegion('15ds)` *after* `StorageDead(_6)` +// (where we have borrows `&'15ds _6`): Eventually: // // i. this code should be rejected (by mir-borrowck), or // // ii. the MIR code generation should be changed so that the -// EndRegion('12ds)` precedes `StorageDead(_6)` in the +// EndRegion('15ds)` precedes `StorageDead(_6)` in the // control-flow. (Note: arielb1 views drop+storagedead as one // unit, and does not see this option as a useful avenue to // explore.), or @@ -66,13 +66,13 @@ fn drop(&mut self) { // START rustc.main.QualifyAndPromoteConstants.before.mir // fn main() -> () { // let mut _0: (); -// let mut _1: &'12ds S1; -// let mut _2: D1<'12ds, '10s>; -// let mut _3: &'12ds S1; -// let mut _4: &'12ds S1; +// let mut _1: &'15ds S1; +// let mut _2: D1<'15ds, '13s>; +// let mut _3: &'15ds S1; +// let mut _4: &'15ds S1; // let _5: S1; -// let mut _6: &'10s S1; -// let mut _7: &'10s S1; +// let mut _6: &'13s S1; +// let mut _7: &'13s S1; // let _8: S1; // bb0: { // StorageLive(_2); @@ -80,19 +80,19 @@ fn drop(&mut self) { // StorageLive(_4); // StorageLive(_5); // _5 = S1::{{constructor}}(const "ex1",); -// _4 = &'12ds _5; -// _3 = &'12ds (*_4); +// _4 = &'15ds _5; +// _3 = &'15ds (*_4); // StorageLive(_6); // StorageLive(_7); // StorageLive(_8); // _8 = S1::{{constructor}}(const "dang1",); -// _7 = &'10s _8; -// _6 = &'10s (*_7); -// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6); -// EndRegion('10s); +// _7 = &'13s _8; +// _6 = &'13s (*_7); +// _2 = D1<'15ds, '13s>::{{constructor}}(move _3, move _6); +// EndRegion('13s); // StorageDead(_6); // StorageDead(_3); -// _1 = (_2.0: &'12ds S1); +// _1 = (_2.0: &'15ds S1); // drop(_2) -> [return: bb2, unwind: bb1]; // } // bb1: { @@ -104,7 +104,7 @@ fn drop(&mut self) { // StorageDead(_8); // StorageDead(_4); // StorageDead(_5); -// EndRegion('12ds); +// EndRegion('15ds); // _0 = (); // return; // } @@ -114,29 +114,29 @@ fn drop(&mut self) { // START rustc.main.QualifyAndPromoteConstants.after.mir // fn main() -> (){ // let mut _0: (); -// let mut _1: &'12ds S1; -// let mut _2: D1<'12ds, '10s>; -// let mut _3: &'12ds S1; -// let mut _4: &'12ds S1; +// let mut _1: &'15ds S1; +// let mut _2: D1<'15ds, '13s>; +// let mut _3: &'15ds S1; +// let mut _4: &'15ds S1; // let _5: S1; -// let mut _6: &'10s S1; -// let mut _7: &'10s S1; +// let mut _6: &'13s S1; +// let mut _7: &'13s S1; // let _8: S1; // bb0: { // StorageLive(_2); // StorageLive(_3); // StorageLive(_4); -// _4 = &'12ds (promoted[1]: S1); -// _3 = &'12ds (*_4); +// _4 = &'15ds (promoted[1]: S1); +// _3 = &'15ds (*_4); // StorageLive(_6); // StorageLive(_7); -// _7 = &'10s (promoted[0]: S1); -// _6 = &'10s (*_7); -// _2 = D1<'12ds, '10s>::{{constructor}}(move _3, move _6); -// EndRegion('10s); +// _7 = &'13s (promoted[0]: S1); +// _6 = &'13s (*_7); +// _2 = D1<'15ds, '13s>::{{constructor}}(move _3, move _6); +// EndRegion('13s); // StorageDead(_6); // StorageDead(_3); -// _1 = (_2.0: &'12ds S1); +// _1 = (_2.0: &'15ds S1); // drop(_2) -> [return: bb2, unwind: bb1]; // } // bb1: { @@ -146,7 +146,7 @@ fn drop(&mut self) { // StorageDead(_2); // StorageDead(_7); // StorageDead(_4); -// EndRegion('12ds); +// EndRegion('15ds); // _0 = (); // return; // } diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs index aab432ddc87..ba1712f4ca3 100644 --- a/src/test/mir-opt/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -30,7 +30,7 @@ fn foo(_t: T, q: &i32) -> i32 { // ... // bb0: { // ... -// _3 = [closure@NodeId(39)]; +// _3 = [closure@NodeId(53)]; // ... // _4 = &_3; // ... diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index 22e7de31e90..9cb0a4dc2bf 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -26,7 +26,7 @@ fn foo(_t: T, q: i32) -> i32 { // ... // bb0: { // ... -// _3 = [closure@NodeId(28)]; +// _3 = [closure@NodeId(39)]; // ... // _4 = &_3; // ... diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs index 882579c5710..f1544968adb 100644 --- a/src/test/mir-opt/validate_1.rs +++ b/src/test/mir-opt/validate_1.rs @@ -40,35 +40,35 @@ fn main() { // ... // bb0: { // ... -// Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [_1: i32]); +// Validate(Suspend(ReScope(Node(ItemLocalId(13)))), [_1: i32]); // _6 = &ReErased mut _1; -// Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(10)))]); -// Validate(Suspend(ReScope(Node(ItemLocalId(10)))), [(*_6): i32/ReScope(Node(ItemLocalId(10)))]); +// Validate(Acquire, [(*_6): i32/ReScope(Node(ItemLocalId(13)))]); +// Validate(Suspend(ReScope(Node(ItemLocalId(13)))), [(*_6): i32/ReScope(Node(ItemLocalId(13)))]); // _5 = &ReErased mut (*_6); -// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(10)))]); -// Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(10))) Test, _5: &ReScope(Node(ItemLocalId(10))) mut i32]); +// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(13)))]); +// Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(13))) Test, _5: &ReScope(Node(ItemLocalId(13))) mut i32]); // _2 = const Test::foo(move _3, move _5) -> bb1; // } // // bb1: { // Validate(Acquire, [_2: ()]); -// EndRegion(ReScope(Node(ItemLocalId(10)))); +// EndRegion(ReScope(Node(ItemLocalId(13)))); // ... // return; // } // } // END rustc.main.EraseRegions.after.mir // START rustc.main-{{closure}}.EraseRegions.after.mir -// fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 { +// fn main::{{closure}}(_1: &ReErased [closure@NodeId(65)], _2: &ReErased mut i32) -> i32 { // ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(65)], _2: &ReFree(DefId(0/1:11 ~ validate_1[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); // StorageLive(_3); -// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]); +// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 })), [(*_2): i32]); // _3 = &ReErased (*_2); -// Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]); +// Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 }) (imm)]); // _0 = (*_3); -// EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })); +// EndRegion(ReScope(Remainder { block: ItemLocalId(31), first_statement_index: 0 })); // StorageDead(_3); // return; // } diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs index 07f5b2aa84b..ce840397713 100644 --- a/src/test/mir-opt/validate_3.rs +++ b/src/test/mir-opt/validate_3.rs @@ -48,27 +48,27 @@ fn _unused2(x: *const i32) -> i32 { unsafe { *x }} // StorageLive(_1); // _1 = Test { x: const 0i32 }; // StorageLive(_2); -// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]); +// Validate(Suspend(ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 })), [_1: Test]); // _2 = &ReErased _1; -// Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]); +// Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }) (imm)]); // StorageLive(_4); // StorageLive(_5); -// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]); +// Validate(Suspend(ReScope(Node(ItemLocalId(22)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 }) (imm)]); // _5 = &ReErased ((*_2).0: i32); -// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]); -// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]); +// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(22))) (imm)]); +// Validate(Suspend(ReScope(Node(ItemLocalId(22)))), [(*_5): i32/ReScope(Node(ItemLocalId(22))) (imm)]); // _4 = &ReErased (*_5); -// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(18))) (imm)]); -// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(18))) i32]); +// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(22))) (imm)]); +// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(22))) i32]); // _3 = const foo(move _4) -> bb1; // } // bb1: { // Validate(Acquire, [_3: ()]); -// EndRegion(ReScope(Node(ItemLocalId(18)))); +// EndRegion(ReScope(Node(ItemLocalId(22)))); // StorageDead(_4); // StorageDead(_5); // _0 = (); -// EndRegion(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })); +// EndRegion(ReScope(Remainder { block: ItemLocalId(24), first_statement_index: 3 })); // StorageDead(_2); // StorageDead(_1); // return; diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs index 24a4ebd8429..542ac8a4241 100644 --- a/src/test/mir-opt/validate_4.rs +++ b/src/test/mir-opt/validate_4.rs @@ -48,11 +48,11 @@ fn main() { // } // END rustc.write_42.EraseRegions.after.mir // START rustc.write_42-{{closure}}.EraseRegions.after.mir -// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () { +// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(32)], _2: *mut i32) -> () { // ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]); -// Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(22)], _2: *mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(32)], _2: *mut i32]); +// Validate(Release, [_1: &ReFree(DefId(0/1:9 ~ validate_4[317d]::write_42[0]::{{closure}}[0]), BrEnv) [closure@NodeId(32)], _2: *mut i32]); // (*_2) = const 23i32; // _0 = (); // return; @@ -76,11 +76,11 @@ fn main() { // } // END rustc.test.EraseRegions.after.mir // START rustc.main-{{closure}}.EraseRegions.after.mir -// fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool { +// fn main::{{closure}}(_1: &ReErased [closure@NodeId(80)], _2: &ReErased mut i32) -> bool { // ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); -// Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(80)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); +// Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(80)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); // StorageLive(_3); // ... // _0 = const write_42(move _3) -> bb1; diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs index b4d4479bab9..955de0c3bad 100644 --- a/src/test/mir-opt/validate_5.rs +++ b/src/test/mir-opt/validate_5.rs @@ -46,19 +46,19 @@ fn main() { // } // END rustc.test.EraseRegions.after.mir // START rustc.main-{{closure}}.EraseRegions.after.mir -// fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool { +// fn main::{{closure}}(_1: &ReErased [closure@NodeId(62)], _2: &ReErased mut i32) -> bool { // ... // bb0: { -// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); +// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(62)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); // StorageLive(_3); // StorageLive(_4); // StorageLive(_5); -// Validate(Suspend(ReScope(Node(ItemLocalId(12)))), [(*_2): i32]); +// Validate(Suspend(ReScope(Node(ItemLocalId(16)))), [(*_2): i32]); // _5 = &ReErased mut (*_2); -// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(12)))]); +// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(16)))]); // _4 = move _5 as *mut i32 (Misc); // _3 = move _4; -// EndRegion(ReScope(Node(ItemLocalId(12)))); +// EndRegion(ReScope(Node(ItemLocalId(16)))); // StorageDead(_4); // StorageDead(_5); // Validate(Release, [_0: bool, _3: *mut i32]); diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs index ac39118c5f1..27169299c8a 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs @@ -38,7 +38,8 @@ impl TTMacroExpander for Expander { fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, sp: Span, - _: TokenStream) -> Box { + _: TokenStream, + _: Option) -> Box { let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i)) .collect::>().join(", "); MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args))) diff --git a/src/test/run-pass/issues/issue-18804/main.rs b/src/test/run-pass/issues/issue-18804/main.rs index a3a5337077c..2abcd4b7ba9 100644 --- a/src/test/run-pass/issues/issue-18804/main.rs +++ b/src/test/run-pass/issues/issue-18804/main.rs @@ -9,7 +9,7 @@ // except according to those terms. // run-pass -// Test for issue #18804, #[linkage] does not propagate thorugh generic +// Test for issue #18804, #[linkage] does not propagate through generic // functions. Failure results in a linker error. // ignore-asmjs no weak symbol support diff --git a/src/test/run-pass/macros/issue-25274.rs b/src/test/run-pass/macros/issue-25274.rs new file mode 100644 index 00000000000..e81b2c7a723 --- /dev/null +++ b/src/test/run-pass/macros/issue-25274.rs @@ -0,0 +1,16 @@ +macro_rules! test { + ( + fn fun() -> Option>; + ) => { + fn fun(x: $t) -> Option> + { Some(Box::new(x)) } + } +} + +test! { + fn fun() -> Option>; +} + +fn main() { + println!("{}", fun(0).unwrap()); +} diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index 62e495288cb..932fe1c8eb0 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -15,6 +15,7 @@ // compile-flags:--test // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 +// rustc-env:RUST_BACKTRACE=0 // doctest fails at runtime /// ``` diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index cf417f8d412..876f6c0a80b 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -1,22 +1,22 @@ running 2 tests -test $DIR/failed-doctest-output.rs - OtherStruct (line 26) ... FAILED -test $DIR/failed-doctest-output.rs - SomeStruct (line 20) ... FAILED +test $DIR/failed-doctest-output.rs - OtherStruct (line 27) ... FAILED +test $DIR/failed-doctest-output.rs - SomeStruct (line 21) ... FAILED failures: ----- $DIR/failed-doctest-output.rs - OtherStruct (line 26) stdout ---- +---- $DIR/failed-doctest-output.rs - OtherStruct (line 27) stdout ---- error[E0425]: cannot find value `no` in this scope - --> $DIR/failed-doctest-output.rs:27:1 + --> $DIR/failed-doctest-output.rs:28:1 | 3 | no | ^^ not found in this scope -thread '$DIR/failed-doctest-output.rs - OtherStruct (line 26)' panicked at 'couldn't compile the test', librustdoc/test.rs:332:13 +thread '$DIR/failed-doctest-output.rs - OtherStruct (line 27)' panicked at 'couldn't compile the test', librustdoc/test.rs:332:13 note: Run with `RUST_BACKTRACE=1` for a backtrace. ----- $DIR/failed-doctest-output.rs - SomeStruct (line 20) stdout ---- -thread '$DIR/failed-doctest-output.rs - SomeStruct (line 20)' panicked at 'test executable failed: +---- $DIR/failed-doctest-output.rs - SomeStruct (line 21) stdout ---- +thread '$DIR/failed-doctest-output.rs - SomeStruct (line 21)' panicked at 'test executable failed: thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1 note: Run with `RUST_BACKTRACE=1` for a backtrace. @@ -25,8 +25,8 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: - $DIR/failed-doctest-output.rs - OtherStruct (line 26) - $DIR/failed-doctest-output.rs - SomeStruct (line 20) + $DIR/failed-doctest-output.rs - OtherStruct (line 27) + $DIR/failed-doctest-output.rs - SomeStruct (line 21) test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/src/test/rustdoc/deprecated-impls.rs b/src/test/rustdoc/deprecated-impls.rs index bcf0645766b..3fb83bff916 100644 --- a/src/test/rustdoc/deprecated-impls.rs +++ b/src/test/rustdoc/deprecated-impls.rs @@ -109,7 +109,7 @@ fn fn_empty_without_doc() {} // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.5: fn_def_with_doc' // @has - 'fn_def_with_doc short' - // @!has - 'fn_def_with full' + // @!has - 'fn_def_with_doc full' fn fn_def_with_doc() {} // @has - '//*[@class="stab deprecated"]' 'Deprecated since 1.0.6: fn_def_without_doc' diff --git a/src/test/rustdoc/dont-show-const-contents.rs b/src/test/rustdoc/dont-show-const-contents.rs new file mode 100644 index 00000000000..1392c62b4ab --- /dev/null +++ b/src/test/rustdoc/dont-show-const-contents.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the contents of constants are not displayed as part of the +// documentation. + +// @!has dont_show_const_contents/constant.CONST_S.html 'dont show this' +pub const CONST_S: &'static str = "dont show this"; diff --git a/src/test/rustdoc/empty-section.rs b/src/test/rustdoc/empty-section.rs index 3748313593f..11a027a13f7 100644 --- a/src/test/rustdoc/empty-section.rs +++ b/src/test/rustdoc/empty-section.rs @@ -15,6 +15,6 @@ pub struct Foo; // @has foo/struct.Foo.html -// @!has - '//*[@class="synthetic-implementations"]' 'Auto Trait Implementations' +// @!has - 'Auto Trait Implementations' impl !Send for Foo {} impl !Sync for Foo {} diff --git a/src/test/rustdoc/escape-rust-expr.rs b/src/test/rustdoc/escape-rust-expr.rs deleted file mode 100644 index 4594eb95ea1..00000000000 --- a/src/test/rustdoc/escape-rust-expr.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that we HTML-escape Rust expressions, where HTML special chars -// can occur, and we know it's definitely not markup. - -// @!has escape_rust_expr/constant.CONST_S.html '//pre[@class="rust const"]' '"