]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #55343 - Keruspe:remap-debuginfo-release, r=alexcrichton
authorkennytm <kennytm@gmail.com>
Fri, 26 Oct 2018 10:25:10 +0000 (18:25 +0800)
committerkennytm <kennytm@gmail.com>
Fri, 26 Oct 2018 15:06:41 +0000 (23:06 +0800)
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

228 files changed:
RELEASES.md
src/Cargo.lock
src/bootstrap/bootstrap.py
src/etc/lldb_rust_formatters.py
src/liballoc/collections/btree/map.rs
src/libcore/alloc.rs
src/libcore/intrinsics.rs
src/libcore/ops/range.rs
src/libcore/pin.rs
src/libcore/ptr.rs
src/libcore/task/wake.rs
src/librustc/dep_graph/dep_node.rs
src/librustc/hir/def_id.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/collector.rs
src/librustc/hir/map/hir_id_validator.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc/ich/caching_codemap_view.rs
src/librustc/ich/impls_hir.rs
src/librustc/infer/at.rs
src/librustc/infer/combine.rs
src/librustc/infer/equate.rs
src/librustc/lint/builtin.rs
src/librustc/macros.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/mir/interpret/mod.rs
src/librustc/mir/interpret/value.rs
src/librustc/mir/mod.rs
src/librustc/mir/traversal.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/project.rs
src/librustc/traits/query/mod.rs
src/librustc/traits/query/type_op/ascribe_user_type.rs [new file with mode: 0644]
src/librustc/traits/query/type_op/mod.rs
src/librustc/traits/select.rs
src/librustc/ty/context.rs
src/librustc/ty/item_path.rs
src/librustc/ty/mod.rs
src/librustc/ty/query/config.rs
src/librustc/ty/query/mod.rs
src/librustc/ty/query/plumbing.rs
src/librustc/ty/sty.rs
src/librustc_codegen_llvm/builder.rs
src/librustc_driver/driver.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_lint/unused.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/const_eval.rs
src/librustc_mir/diagnostics.rs
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/memory.rs
src/librustc_mir/interpret/operand.rs
src/librustc_mir/interpret/snapshot.rs
src/librustc_mir/interpret/validity.rs
src/librustc_mir/lib.rs
src/librustc_mir/lints.rs [new file with mode: 0644]
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_passes/ast_validation.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/error_reporting.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/lib.rs
src/librustc_save_analysis/span_utils.rs
src/librustc_target/abi/mod.rs
src/librustc_traits/type_op.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/check_unused.rs
src/librustc_typeck/coherence/builtin.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/librustdoc/html/static/rustdoc.css
src/librustdoc/html/static/themes/dark.css
src/librustdoc/html/static/themes/light.css
src/libstd/f32.rs
src/libstd/f64.rs
src/libstd/keyword_docs.rs
src/libstd/net/tcp.rs
src/libstd/primitive_docs.rs
src/libstd/process.rs
src/libstd/sync/mod.rs
src/libstd/sync/once.rs
src/libsyntax/ast.rs
src/libsyntax/config.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax_pos/lib.rs
src/stdsimd
src/test/incremental/hashes/closure_expressions.rs
src/test/mir-opt/end_region_1.rs
src/test/mir-opt/end_region_2.rs
src/test/mir-opt/end_region_3.rs
src/test/mir-opt/end_region_4.rs
src/test/mir-opt/end_region_5.rs
src/test/mir-opt/end_region_6.rs
src/test/mir-opt/end_region_7.rs
src/test/mir-opt/end_region_8.rs
src/test/mir-opt/end_region_9.rs
src/test/mir-opt/end_region_cyclic.rs
src/test/mir-opt/end_region_destruction_extents_1.rs
src/test/mir-opt/inline-closure-borrows-arg.rs
src/test/mir-opt/inline-closure.rs
src/test/mir-opt/validate_1.rs
src/test/mir-opt/validate_3.rs
src/test/mir-opt/validate_4.rs
src/test/mir-opt/validate_5.rs
src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
src/test/run-pass/issues/issue-18804/main.rs
src/test/run-pass/macros/issue-25274.rs [new file with mode: 0644]
src/test/rustdoc-ui/failed-doctest-output.rs
src/test/rustdoc-ui/failed-doctest-output.stdout
src/test/rustdoc/deprecated-impls.rs
src/test/rustdoc/dont-show-const-contents.rs [new file with mode: 0644]
src/test/rustdoc/empty-section.rs
src/test/rustdoc/escape-rust-expr.rs [deleted file]
src/test/rustdoc/hidden-methods.rs
src/test/rustdoc/issue-13698.rs
src/test/rustdoc/issue-46767.rs
src/test/rustdoc/issue-54478-demo-allocator.rs [new file with mode: 0644]
src/test/rustdoc/issue-55001.rs [new file with mode: 0644]
src/test/rustdoc/manual_impl.rs
src/test/rustdoc/playground-empty.rs
src/test/rustdoc/redirect.rs
src/test/rustdoc/unneeded-trait-implementations-title.rs
src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs [new file with mode: 0644]
src/test/ui-fulldeps/resolve-error.stderr
src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
src/test/ui/block-result/unexpected-return-on-unit.rs
src/test/ui/conditional-compilation/cfg-attr-multi-false.rs
src/test/ui/consts/const-eval/double_promotion.rs [new file with mode: 0644]
src/test/ui/did_you_mean/issue-31424.nll.stderr
src/test/ui/did_you_mean/issue-31424.rs
src/test/ui/did_you_mean/issue-31424.stderr
src/test/ui/did_you_mean/issue-42764.rs
src/test/ui/did_you_mean/issue-42764.stderr
src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr
src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr
src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr
src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr
src/test/ui/empty/empty-comment.stderr
src/test/ui/fail-simple.stderr
src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr [new file with mode: 0644]
src/test/ui/foreign-fn-return-lifetime.fixed [new file with mode: 0644]
src/test/ui/foreign-fn-return-lifetime.rs
src/test/ui/foreign-fn-return-lifetime.stderr
src/test/ui/imports/extern-prelude-extern-crate-cfg.rs [new file with mode: 0644]
src/test/ui/imports/extern-prelude-extern-crate-fail.rs [new file with mode: 0644]
src/test/ui/imports/extern-prelude-extern-crate-fail.stderr [new file with mode: 0644]
src/test/ui/imports/extern-prelude-extern-crate-pass.rs [new file with mode: 0644]
src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs [new file with mode: 0644]
src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr [new file with mode: 0644]
src/test/ui/issues/issue-13497.stderr
src/test/ui/issues/issue-26638.stderr
src/test/ui/issues/issue-30007.stderr
src/test/ui/issues/issue-7970a.stderr
src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs [new file with mode: 0644]
src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr [new file with mode: 0644]
src/test/ui/lint/suggestions.rs
src/test/ui/lint/suggestions.stderr
src/test/ui/macros/macro-at-most-once-rep-2018-feature-gate.stderr
src/test/ui/macros/macro-at-most-once-rep-2018.stderr
src/test/ui/macros/macro-context.stderr
src/test/ui/macros/macro-follow.stderr
src/test/ui/macros/macro-followed-by-seq-bad.stderr
src/test/ui/macros/macro-in-expression-context-2.rs [new file with mode: 0644]
src/test/ui/macros/macro-in-expression-context-2.stderr [new file with mode: 0644]
src/test/ui/macros/macro-in-expression-context.fixed [new file with mode: 0644]
src/test/ui/macros/macro-in-expression-context.rs [new file with mode: 0644]
src/test/ui/macros/macro-in-expression-context.stderr [new file with mode: 0644]
src/test/ui/macros/macro-input-future-proofing.stderr
src/test/ui/macros/macro-non-lifetime.stderr
src/test/ui/macros/macro-path-prelude-shadowing.stderr
src/test/ui/macros/missing-comma.stderr
src/test/ui/macros/nonterminal-matching.stderr
src/test/ui/macros/trace_faulty_macros.stderr
src/test/ui/nll/issue-21232-partial-init-and-use.rs
src/test/ui/nll/issue-51191.rs
src/test/ui/nll/issue-51191.stderr
src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs
src/test/ui/nll/user-annotations/issue-55219.rs [new file with mode: 0644]
src/test/ui/nll/user-annotations/issue-55241.rs [new file with mode: 0644]
src/test/ui/parser/macro/macro-doc-comments-1.stderr
src/test/ui/parser/macro/macro-doc-comments-2.stderr
src/test/ui/parser/macro/macro-incomplete-parse.stderr
src/test/ui/regions/region-bound-on-closure-outlives-call.nll.stderr
src/test/ui/regions/region-bound-on-closure-outlives-call.rs
src/test/ui/regions/region-bound-on-closure-outlives-call.stderr
src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
src/test/ui/resolve/token-error-correct-2.rs
src/test/ui/resolve/token-error-correct-3.rs
src/test/ui/resolve/token-error-correct.rs
src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.rs
src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2015.stderr
src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.rs
src/test/ui/rfc-2497-if-let-chains/syntax-ambiguity-2018.stderr
src/test/ui/rust-2018/edition-lint-infer-outlives.fixed
src/test/ui/rust-2018/edition-lint-infer-outlives.rs
src/test/ui/specialization/issue-52050.rs
src/test/ui/underscore-ident-matcher.stderr
src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr
src/test/ui/unused/unused-macro-with-follow-violation.stderr
src/test/ui/vec/vec-macro-with-comma-only.stderr
src/tools/clippy
src/tools/tidy/src/pal.rs

index 7ae7dc9935b6dfd6799fec98cc4087faa7d7e8b8..15ab97e26fc78cae320cd2108dea76a9ae875d66 100644 (file)
@@ -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 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<CStr>`, `Box<OsStr>`, and `Box<Path>` now implement `Clone`.][51912]
 - [Implemented `PartialEq<&str>` for `OsString` and `PartialEq<OsString>`
@@ -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<Trait> == Box<dyn Trait>`.
 - [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<Item=u8>` or
+   or in function parameters.][49255] E.g. `fn foo() -> impl Iterator<Item=u8>` or
   `fn open(path: impl AsRef<Path>)`.
 - [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]
index 3361e81ecfe6dfbb0c58c41d62b5a986c2995785..dd211083527922861f13b5b6bb884151a50604d8 100644 (file)
@@ -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]]
index c27f4f056d747c8f5ed52f74e703546290c1d99a..ffc5adbebb34f76658714abb6af3c22f9593493b 100644 (file)
@@ -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"
index 4427313f9e5b352b55bbabc9e6ff4b3a2a16548d..2bbd4372721cbc2f724dada47454f68f02573bba 100644 (file)
@@ -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
index 8c950cd06d9e385373f56175d5253060c4e8390a..24c8fd3a969ca3e1bde035f6531cf3c6456d7bb2 100644 (file)
@@ -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") {
index 35e4eea756d41ca0cceef932b15751a3928f1331..4efcaae59b012ce1a192c4a51379d8d9a0c20c53 100644 (file)
@@ -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
index 56a24168e28d959629f08b8d81079488e4b693ad..cceae9249e45626a6642c366242bdc177232f2df 100644 (file)
     ///         // 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);
index 07ba285ea5cb3b8ffc3954178e3621e196dc7009..fd3e50998fe8c5e5909f7d4fb60f63a7c1f96551 100644 (file)
@@ -304,7 +304,7 @@ pub fn contains<U>(&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`.
index 0224560af4c764657e5e667e40434f731b8aba7d..a03c080fb3f3418fad92dba5a06c1390f168de3a 100644 (file)
 /// 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
index 1c761ba21b3ec860ef4cb35675569ac197ee67fa..b699cb028842be995604f77a605c34c7c8a82124 100644 (file)
@@ -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
index ab4ae50c44367f3dce204ba60a4572cf60993e7d..c9fb22e0080dd1c2efc2531e8fcdfaed53336e19 100644 (file)
@@ -188,6 +188,11 @@ pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
 }
 
 impl From<LocalWaker> 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
index de03892b994ef6a962ad4808f82d8bc9dde1b957..4d6d3bd56f2d803292145685b45275f90c4cad0d 100644 (file)
@@ -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>),
index a09fd5df557f5df7ef941aaa86c0ec80a823be9a..e378e1b8be0e922b6b8e56c52330b4ef411c6f34 100644 (file)
@@ -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"),
         }
     }
index 95b73d5f87b39fff6cfc2e260225ef2739333c83..dcc0f8545e5d77f560094aea0dbab7a5ee4b7985 100644 (file)
@@ -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);
     }
index a1363168f0117b732e413dfae32c0edee0d94b3e..6370a52018338842ec60d80a8414032c4745fcc2 100644 (file)
@@ -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<PathResolution>;
@@ -163,7 +167,6 @@ fn resolve_str_path(
         span: Span,
         crate_root: Option<&str>,
         components: &[&str],
-        params: Option<P<hir::GenericArgs>>,
         is_value: bool,
     ) -> hir::Path;
 }
@@ -1064,6 +1067,9 @@ fn lower_attrs(&mut self, attrs: &[Attribute]) -> hir::HirVec<Attribute> {
     }
 
     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<Ident>,
         param_mode: ParamMode,
+        explicit_owner: Option<NodeId>,
     ) -> 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<NodeId>,
     ) -> 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<Attribute>,
     ) -> 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<P<hir::GenericArgs>>,
         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 {
index bd12a5e0cb4d8dccd87f2df68af588b3edf0e0ba..8c701d9e4188fafa44fcebf7fdd4d536f3fb9087 100644 (file)
@@ -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));
 
index 087efbd4a22dd5231087b502c6e79bf420e941a8..896a6163eba64466d44f30d34418c3e0da84bbde 100644 (file)
@@ -88,7 +88,7 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&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<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&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::<Vec<_>>()));
         }
     }
 }
@@ -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 {
index f5f9bcd3b5ea5125d32e70cd09a2028e57dd2266..7a20146130d9480e640e0d1ba328bd980eed2b38 100644 (file)
@@ -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<Def> {
             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)
         }
index d5de6197a2e486d37076326a9a429c4af1c06a25..a2095ff40c0402da70feed0d958ee80d406e2d1d 100644 (file)
@@ -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<NodeId>,
+    pub def: Option<Def>,
 
     /// Type/lifetime parameters attached to this path. They come in
     /// two flavors: `Path<A,B,C>` 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<NodeId>,
+        def: Option<Def>,
+        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),
index 08d46793d97bf60da9beb59ad3717b378deb98bb..e69d32ad1deafbddc9d8420276aeb19dddaf304f 100644 (file)
@@ -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)
index 97114779042af612ec3c0750f13889b7dd821c80..fbf4297222f9bd9109374f432b1cd5f25a744b34 100644 (file)
@@ -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,
         }
     }
index a48bd4eeb09a32eb5b6726280581e087bf992898..b220634d0d90316897725879b39d2189c6a1ae74 100644 (file)
@@ -174,6 +174,8 @@ fn hash_stable<W: StableHasherResult>(&self,
 
 impl_stable_hash_for!(struct hir::PathSegment {
     ident -> (ident.name),
+    id,
+    def,
     infer_types,
     args
 });
index 89dbc76c8a65c2b58306e8d3ea1d95f2de912d29..0e4c94aaaf3942e31755f00f6eb8d13b90e23491 100644 (file)
@@ -142,6 +142,28 @@ pub fn eq<T>(self,
         self.trace(expected, actual).eq(&expected, &actual)
     }
 
+    pub fn relate<T>(
+        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
index de8f57ee796661446670dad90ec2804b6663e0f3..0ee03bc4c6e00902d0026a78e23b8be1c63a0a5d 100644 (file)
@@ -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 })
     }
 }
index 854960492c9bd4c897e3f357747a3c1dcdbbecf5..c7b5ddb83410f6c969a0c088aad262c6d7d6ad3e 100644 (file)
@@ -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);
index 202a4284f4c82a2b07215909275bea8c208cd47c..266b1c4d4a084dc83dd058713a3397f5371ecf0f 100644 (file)
     "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,
index 897e9cc2a381f2305c96a59bc15b3508833637d6..f21f949c9f5cd220d8508c0e95225d1c7e6c6fd0 100644 (file)
@@ -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<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
@@ -94,8 +101,9 @@ fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&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<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&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<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&s
                     $(ref $field),*
                 } = *self;
 
-                $( $field.hash_stable(__ctx, __hasher));*
+                $( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );*
             }
         }
     };
index 98e80d333c1c8cf669801017da4330eec96f1eba..361abb1689619e1cd92ee0557b54cfef1f17b292 100644 (file)
@@ -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
 }
index 4c2b2b2d41d1ba6f36f391c9497316fc76c7a14a..5054f522778706305bf9cdbb653f71f4ac3530e4 100644 (file)
@@ -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 {
index 9e54b146fd02a61edcf79d88ccd9de0ca1d9804d..4304f08a78f0c56b757f8fb0c9f8927f2918d52c 100644 (file)
@@ -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 }
index 62b5327ae4692237d33e0b3899dd54ae0c811c69..9d296e67da1aee0e1771aa9d05379c9d5760d708 100644 (file)
@@ -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[{}]"
index db1bc3e7519c290e1304e77bbef013b48b031a25..a1e2b7a06468d0994bf76868942b3aa352097097 100644 (file)
@@ -34,6 +34,7 @@ pub struct Preorder<'a, 'tcx: 'a> {
     mir: &'a Mir<'tcx>,
     visited: BitSet<BasicBlock>,
     worklist: Vec<BasicBlock>,
+    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<usize>) {
         // 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<BasicBlock>,
-    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<usize>) {
         // 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.
index dc0039926448c48e6dac87d11bef4ad6a5d93c3b..ea30752a820ee430cab1e2a01557f6f41198de8d 100644 (file)
@@ -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())));
         }
index b29ee8f7cdce4ad9a76477ffa947ef4f4ad7434f..b266fbe0d11458e08829a3c721407eb82b78343f 100644 (file)
@@ -340,7 +340,7 @@ fn fold<T:TypeFoldable<'tcx>>(&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)
         }
index 35f17aebc0443481f0bfa1f913ddcc8c00915f7e..13683d8544496477fdc55699ca763ec0e1768bf7 100644 (file)
@@ -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 (file)
index 0000000..b3955b8
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Self::QueryResponse> {
+        None
+    }
+
+    fn perform_query(
+        tcx: TyCtxt<'_, 'gcx, 'tcx>,
+        canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Fallible<CanonicalizedQueryResponse<'gcx, ()>> {
+        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
+    }
+}
index b292df758eeb5636ff83dd50b8dc6493403c9208..d20d43cf7578c3917bc37563ca04b2da0587042e 100644 (file)
@@ -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;
index 49f3717935493ef4bf99765864174bc347e3e23f..2ea16823cc65dadd3ef12f06860045dc75d73c9a 100644 (file)
@@ -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
index c60471c285dcb0f1b35c532853337a23ba44ed08..1a9f86306325f1857a5eded35dce12c4215a7433 100644 (file)
@@ -931,7 +931,9 @@ pub struct GlobalCtxt<'tcx> {
 
     maybe_unused_trait_imports: FxHashSet<DefId>,
     maybe_unused_extern_crates: Vec<(DefId, Span)>,
-    pub extern_prelude: FxHashSet<ast::Name>,
+    /// 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<ast::Name, bool>,
 
     // Internal cache for metadata decoding. No need to track deps on this.
     pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
index 46669f1f9434b551db0725e8dfc838598e8f8583..7153c729d1542b439d8dcec805ca5a8cccf0a37c 100644 (file)
@@ -343,7 +343,7 @@ pub fn push_item_path<T>(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;
                     }
                 }
index bb9346f2f468dc2431ca71b206ccf747bea7a396..5a2f062f233cf17c67e9d5e565dcb773cb46d6c9 100644 (file)
@@ -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<Name>,
+    /// 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<Name, bool>,
 }
 
 #[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<A> <: T<B> iff A <: B -- e.g., function return type
     Invariant,      // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
index d0c3109da52f1570a099009987bf95eed45a5a52..0f6ff93c52336c859b3f240391b8c001c9b755a1 100644 (file)
@@ -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()
index e4fc45f3798415d658196f327da715fc6639a87c..a59a15da08d999842e28adb54f3711e764431bed 100644 (file)
 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;
             CanonicalPredicateGoal<'tcx>
         ) -> Result<traits::EvaluationResult, traits::OverflowError>,
 
+        /// Do not call this query directly: part of the `Eq` type-op
+        [] fn type_op_ascribe_user_type: TypeOpAscribeUserType(
+            CanonicalTypeOpAscribeUserTypeGoal<'tcx>
+        ) -> Result<
+            Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
+            NoSolution,
+        >,
+
         /// Do not call this query directly: part of the `Eq` type-op
         [] fn type_op_eq: TypeOpEq(
             CanonicalTypeOpEqGoal<'tcx>
index 71e435fea77d438cb652b0cb0bc7ee4dc8e35383..789658dcf72dc25b45452464643ddd8393ebf66e 100644 (file)
@@ -1079,6 +1079,7 @@ macro_rules! force {
         DepKind::ImpliedOutlivesBounds |
         DepKind::DropckOutlives |
         DepKind::EvaluateObligation |
+        DepKind::TypeOpAscribeUserType |
         DepKind::TypeOpEq |
         DepKind::TypeOpSubtype |
         DepKind::TypeOpProvePredicate |
index cd9679c876355bda769abfe5a9c3c88d1e446cad..62e38ad9bfa662a84ecd25a2356fce2828332e74 100644 (file)
@@ -967,7 +967,7 @@ pub fn inputs_and_output(&self) -> ty::Binder<&'tcx List<Ty<'tcx>>> {
         self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output)
     }
     pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
-        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
index 169bd9a8466a03b2508b94fc20823d85c55618d5..2fe6a0377f81b14803ab93feae7a03795b3795bb 100644 (file)
@@ -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
             }
         }
index 8020d596afd0f8f04e18822a633f570b9a848db0..7ad012409b53a4bdfacc93b9633e1dd0c338ab1c 100644 (file)
@@ -790,7 +790,9 @@ pub fn phase_2_configure_and_expand<F>(
                 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 {
index bc5f688729c368fa653bf2910f744246fe454261..19f9168cf0a0e2e8c32712eba0c764d9cb659764 100644 (file)
 
 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,
index 5bf2b76e66849b6a5346a8d1a089b0cfd98a7199..f289acc032be8fd5cca2a547d18c253cf1ba1558 100644 (file)
@@ -144,7 +144,6 @@ macro_rules! add_lint_group {
         UnusedAllocation: UnusedAllocation,
         MissingCopyImplementations: MissingCopyImplementations,
         UnstableFeatures: UnstableFeatures,
-        UnconditionalRecursion: UnconditionalRecursion,
         InvalidNoMangleItems: InvalidNoMangleItems,
         PluginAsLibrary: PluginAsLibrary,
         MutableTransmutes: MutableTransmutes,
index 4cf2072e792ca3ee6a50420f4df9c27177f71f67..96d04253cc48549f3fd981e0a774ee922a21ab44 100644 (file)
@@ -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);
         }
     }
 
index 7988de28b5d7b3e35b0a084e5e69a05186d8184e..e6e1367b592df79360ce3061cf30c4de1e3839f3 100644 (file)
@@ -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::<cstore::CrateMetadata>()
-                    .expect("CrateStore crated ata is not a CrateMetadata");
+                    .expect("CrateStore created data is not a CrateMetadata");
                 $compute
             })*
 
index 6db107344747e40733cd00314c6e8af269b5d119..bbbe02fda6a84dd145035e0e6331b5117d3b100a 100644 (file)
@@ -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<T>(&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>,
index 9e78932bffea6d638b3b5b4594af01997f50dccf..e6dd0107e919801234c82242e210e1b4648542b8 100644 (file)
@@ -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
     })
 }
index bc917140bbd679a7907d8ffdc54b63ba21499bc7..9702e94a9e0f0ffae84c155cec25e5a0d7a77e1d 100644 (file)
@@ -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)
index bb3e4a8d8813f7968a4adc6da21b557422b97c57..56a9daf84f768905faedee6d096ea7f99260f143 100644 (file)
@@ -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.
index 04a297d0a8317963ead1be2b656c72e6d66885f8..d53bb1dc4d63a255e12ee4add8dcd8200e605339 100644 (file)
@@ -931,12 +931,37 @@ fn intersection(&self, other: &Self) -> Option<Self> {
     }
 }
 
-// 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<Constructor<'tcx>>),
+}
+
+// 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<Constructor<'tcx>>,
     used_ctors: &Vec<Constructor<'tcx>>,
-) -> Vec<Constructor<'tcx>> {
+) -> 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)
                 }
index 189388921650cd4e6a7ef71daa696511a2a2945c..64ad4c2eec1e1343da2b8cba38f91368e68d717c 100644 (file)
@@ -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);
         }
 
index 9adca6c429798b75ebf8ef9a23a88548edca95be..6fe490c6efc8ffa8434ce9b97a7ff9cc475aac40 100644 (file)
@@ -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<M::PointerTag>, 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<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
index 71b2f4b53a60c4df84a82e78d6a752862a2b6dcc..021e2d58f84b1d4556ec8e2950ac8abf286408da 100644 (file)
@@ -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<Value<M::PointerTag>>> {
         if mplace.layout.is_unsized() {
-            // Dont touch unsized
+            // Don't touch unsized
             return Ok(None);
         }
         let (ptr, ptr_align) = mplace.to_scalar_ptr_align();
index 047a0125f78af968bad83a63ec91696ed517d7f6..cff2288fd8720c3ac04cd97045a105d8617d8d29 100644 (file)
@@ -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<StableHashingContext<'a>> for Place {
-    fn hash_stable<W: StableHasherResult>(
-        &self, hcx: &mut StableHashingContext<'a>,
-        hasher: &mut StableHasher<W>)
-    {
-        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<StableHashingContext<'a>> for StackPopCleanup {
-    fn hash_stable<W: StableHasherResult>(
-        &self,
-        hcx: &mut StableHashingContext<'a>,
-        hasher: &mut StableHasher<W>)
-    {
-        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<StableHashingContext<'a>> for Frame<'mir, 'tcx> {
-    fn hash_stable<W: StableHasherResult>(
-        &self,
-        hcx: &mut StableHashingContext<'a>,
-        hasher: &mut StableHasher<W>) {
-
-        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<H: Hasher>(&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<StableHashingContext<'b>>
-    for EvalSnapshot<'a, 'mir, 'tcx>
-{
-    fn hash_stable<W: StableHasherResult>(
-        &self,
-        hcx: &mut StableHashingContext<'b>,
-        hasher: &mut StableHasher<W>)
-    {
-        // 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>
 {}
index 38cf79d8fa0b9836fcf29422155a58a3ea1716df..ac1ba0edc3b3b850a242a50c9efc5f4ff84805c7 100644 (file)
@@ -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(())
index 2f44dff2e22c3472cc18c58232f2ab585600fb57..75417982aa189992d9743acba2bb54608fb26ac8 100644 (file)
@@ -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 (file)
index 0000000..4c79385
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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();
+    }
+}
index f4efe33da7080f07cd086649baa0f03c2f3432b1..5114fa879746b0a0f64369310abc772d452cd882 100644 (file)
@@ -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!()
                     }
                 }
index 78547abf9d9d309756a92fbf3e48d87f9d38cc5d..c4d8ec35868835d50892a5d3a422e5a537878bfd 100644 (file)
@@ -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);
index f6ace57f5e0fb52b36a93ac795cdc23426f2a53a..0e9596244cd581cb818c89f33d681002edde192f 100644 (file)
@@ -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<Expr>) {
         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<Expr>) {
     }
 
     /// 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<Expr>) -> 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<Expr>) -> 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,
         }
index 5222dd27d34d61b83f153eedc674cb0983685ea8..b7ed3ef59b4c891349c2695af1e7d8bab6108bf0 100644 (file)
@@ -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<Ident>| {
+            let emit = |this: &mut Self, base: Option<Segment>| {
                 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);
index 74d1ae96e794f6c486a4485028ed5c49ca157322..d77b1868ed72e736331ec463aaf0f3d275f0f379 100644 (file)
@@ -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<Ident>
-    ) -> Option<Vec<Ident>> {
+        path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         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<Ident>
-    ) -> Option<Vec<Ident>> {
+        mut path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         // 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<Ident>
-    ) -> Option<Vec<Ident>> {
+        mut path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         // 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<Ident>
-    ) -> Option<Vec<Ident>> {
+        mut path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         // 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<Ident>
-    ) -> Option<Vec<Ident>> {
+        mut path: Vec<Segment>
+    ) -> Option<Vec<Segment>> {
         // 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<Symbol> = 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
     }
 }
index 2c09ae7b7d2a58f1eec47575d171c7b16eebc026..546c5a5ed3d6cadbcf2c019f1dc356fd67b96a29 100644 (file)
@@ -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<NodeId>,
+}
+
+impl Segment {
+    fn from_path(path: &Path) -> Vec<Segment> {
+        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::<Vec<_>>())
+    }
+}
+
+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<Span>,
@@ -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<Module<'a>>,
-    pub extern_prelude: FxHashSet<Name>,
+    pub extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'a>>,
 
     /// n.b. This is used only for better diagnostics, not name resolution itself.
     has_self: FxHashSet<DefId>,
@@ -1527,7 +1571,11 @@ fn parent(self, id: DefId) -> Option<DefId> {
 /// 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<P<hir::GenericArgs>>,
         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::<Vec<_>>();
+            ).map(|i| self.new_ast_path_segment(i)).collect::<Vec<_>>();
 
-        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<PathResolution> {
@@ -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<F>(&mut self, path: &mut hir::Path, is_value: bool, error_callback: F)
+    fn resolve_hir_path_cb<F>(
+        &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<F>(&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<Name> =
-            session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect();
+        let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry> =
+            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<T, F>(&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::<Vec<_>>();
-        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<Def>| {
             // 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 `<T>::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<ModuleOrUniformRoot<'a>>,
-        path: &[Ident],
+        path: &[Segment],
         opt_ns: Option<Namespace>, // `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<ModuleOrUniformRoot<'a>>,
-        path: &[Ident],
+        path: &[Segment],
         opt_ns: Option<Namespace>, // `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<NodeId> {
     }
 
     fn lookup_typo_candidate<FilterFn>(&mut self,
-                                       path: &[Ident],
+                                       path: &[Segment],
                                        ns: Namespace,
                                        filter_fn: FilterFn,
                                        span: Span)
@@ -4018,7 +4086,7 @@ fn lookup_typo_candidate<FilterFn>(&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<FilterFn>(&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<FilterFn>(&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::<Vec<_>>();
                 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 {
index 28284a45bcdd5f03098cf665c25e79013840cb28..68b3a6be2928253a48a385f8aaaa80f1d42da9e3 100644 (file)
@@ -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<Def, Determinacy> {
-        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::<Vec<Ident>>()
+                    .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 {
index 27ba1ced74985dfc073fb09d585c8e6f23e41c08..810aff7f9b0a86c7eaca20a8945f31f04ccc8d87 100644 (file)
@@ -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<Ident>,
+    pub module_path: Vec<Segment>,
     /// The resolution of `module_path`.
     pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
     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<Ident>,
+                                module_path: Vec<Segment>,
                                 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::<Vec<_>>(),
+                        &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");
index 97bdb9e5fa30ccc238ebc80b847cf9a1347bcc0b..a7fe1bb421c378805a4e769479144016243ec8c3 100644 (file)
 
 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::<Vec<_>>()
                         .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<P<ast::Expr>>,
     ) {
-        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<ast::Pat>]) {
                     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);
                 }
 
index 4b43a1a6270f86793b1f89ac1f71a935b4083dcc..7689406b59a04917ab8d67e0c6063618d8a13987 100644 (file)
 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<Data> {
         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<Data> {
                     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<Data> {
         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<Data> {
                     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<Data> {
             }
             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<Data> {
                 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<Data> {
             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<Data> {
                 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<Data> {
                     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<Def> {
+    pub fn get_method_data(&self, id: ast::NodeId, ident: ast::Ident, span: Span) -> Option<Def> {
         // 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<Ref> {
             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<Data> {
                     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<Data> {
             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<Data> {
                     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<Ref> {
+    pub fn get_path_data(&self, _id: NodeId, path: &ast::Path) -> Option<Ref> {
+        path.segments.last().and_then(|seg| self.get_path_segment_data(seg))
+    }
+
+    pub fn get_path_segment_data(&self, path_seg: &ast::PathSegment) -> Option<Ref> {
         // 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<Ref> {
-        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),
+            }
         })
     }
 
index 47677a751712e9ccf837b92df268e7f3ca4d6380..902353da13f76072b14da48ef182521dcd23c1fd 100644 (file)
@@ -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<Span> {
-        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<Span> {
-        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<Span> {
-        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<Span> {
-        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<Span> {
         let mut toks = self.retokenise_span(span);
         loop {
@@ -205,28 +79,6 @@ pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option<Span> {
         }
     }
 
-    pub fn sub_span_after_keyword(&self, span: Span, keyword: keywords::Keyword) -> Option<Span> {
-        self.sub_span_after(span, |t| t.is_keyword(keyword))
-    }
-
-    fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span> {
-        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<Span> {
     //     let mut toks = self.retokenise_span(span);
@@ -271,42 +123,28 @@ fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span>
     ///
     /// Used to filter out spans of minimal value,
     /// such as references to macro internal variables.
-    pub fn filter_generated(&self, sub_span: Option<Span>, 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;
-        }
-    };
 }
index 6b28fd091748f14114b21d7224e82620b5a65d55..1a5d2801af0c5d1b2a6c7be416c99d0368c43494 100644 (file)
@@ -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))
     }
index a857cdbda45ae87cbdb6510d329a6b90470c12ec..cf274a9c8510576d51570c8c0feba0805600834e 100644 (file)
@@ -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,
     };
 }
 
+fn type_op_ascribe_user_type<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
+) -> Result<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, 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<T>(&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<T>(&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<T>(&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>>>,
index d82d36a1937bf4b5449249789643be1b5285e2e2..7773e2d570844b892d2157b0941d05580c7e7e26 100644 (file)
@@ -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::<Vec<_>>();
+                    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::<Vec<_>>();
-                err.span_suggestions_with_applicability(
-                     expr.span,
-                     "try using a variant of the expected type",
-                     suggestions,
-                     Applicability::MaybeIncorrect,
-                );
             }
         }
 
index 1c562859bb48d3edbca6b31bfbe3845271bf7225..77151351d08a1e5522ddd0b1ef88f9d1f30a7e1f 100644 (file)
@@ -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)
                         }
index ec773e384af38403d56929375c59c2052a72b4ec..9990d2ee2b6769d386f3e0b6a32ffc7ba69806c5 100644 (file)
@@ -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<T: Bar>: 'static;
                     // fn foo<U>() -> Foo<U> { .. *}
index f9aa0397257b8e63de1b1e5575723d8729598509..9d785dfb58ac18a59beb095990707b0ec258713a 100644 (file)
@@ -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;
         }
 
index c54d9e4b47578e205484d37f482a907f5f01a939..05a83dd307c38047e7bb2e76a6f7dab2603f6388 100644 (file)
@@ -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
index b6bc8d603d5ac2a2c9f6b14bf6f830a6fdcc5da3..57c7e2afd625e02c99cdfa530338327599c7f4e3 100644 (file)
@@ -50,6 +50,7 @@ pub fn get_blanket_impls<F>(
         name: Option<String>,
     ) -> Vec<Item>
     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<F>(
             }
             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<F>(
                         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<F>(
                             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
                         }
index db605e57735aa710d6781e46495df5971577256d..9b2720717c9b391aaa0e33eda84b84a11db520d3 100644 (file)
@@ -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::<Vec<String>>().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())
index 49f13df64d6ea15dade9a106083fb3ff3e0eaf4f..d6b0127e44d019e02faf3de39f5b359b9808b9c6 100644 (file)
@@ -186,6 +186,8 @@ pub fn get_real_ty<F>(&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()),
index 87b4527a2a73946629e53bd4ecf5e6b1f81d702b..6522261fe1e7c81a345f71783cdfcd1222202198 100644 (file)
 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, "<pre class=\"rust {}\">\n", class.unwrap_or(""))
+    write!(out, "<div class=\"example-wrap\"><pre class=\"rust {}\">\n", class.unwrap_or(""))
 }
 
 fn write_footer(out: &mut dyn Write) -> io::Result<()> {
-    write!(out, "</pre>\n")
+    write!(out, "</pre></div>\n")
 }
index dda0f37c3f95bfeffaaaf4e3c7e4d5616fd2f5ab..ea51c46a332cbc254ff39ed240a2ea09bb14d356 100644 (file)
@@ -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,
index 6307dda454da892b261ed71c8d2d40e908956df3..9d1a5c38378308f6a6ca4c1ccb096b003d2e70ab 100644 (file)
         return wrapper;
     }
 
+    var hideItemDeclarations = getCurrentValue('rustdoc-item-declarations') === "false";
     onEach(document.getElementsByClassName('docblock'), function(e) {
         if (hasClass(e, 'autohide')) {
             var wrap = e.previousElementSibling;
             }
         }
         if (e.parentNode.id === "main") {
-            var otherMessage;
+            var otherMessage = '';
             var fontSize;
             var extraClass;
-            var show = true;
 
             if (hasClass(e, "type-decl")) {
                 fontSize = "20px";
                 otherMessage = '&nbsp;Show&nbsp;declaration';
-                show = getCurrentValue('rustdoc-item-declarations') === "false";
-                if (!show) {
+                if (hideItemDeclarations === false) {
                     extraClass = 'collapsed';
                 }
             } else if (hasClass(e, "non-exhaustive")) {
                 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");
             }
         }
         });
     }
 
+    // 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) {
                 e.previousElementSibling.childNodes[0].style.color = '';
             });
         }
+        lineNumbersFunc(e);
     });
 
     function showModal(content) {
index 63740ea729131f887fec12ccba73224cf69d9244..c0951d9f8401e45a94db9a00d813a6bb213863e9 100644 (file)
@@ -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;
index 8e4890d905817722eb960c0e0732255944c2ce7c..4a8950b236c62da6175a83280fb122b3cb134bb0 100644 (file)
@@ -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);
 }
index 2742faab017bf13d95fff7aadbab3d91ba87ae46..b3b0b6b2ea9e869f1bb3a07c39f292611805ccaa 100644 (file)
@@ -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);
 }
index c3f225d1eb0136e72070a1f1555082b7da6b941d..7d17aaf2f261b24e723e9012c88390e62d6ad052 100644 (file)
@@ -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
     ///
index da062dda77a47a5496e76e671875545653f3d91a..ecaaf8323ab91a0b1105353a399af7182dca682a 100644 (file)
@@ -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
     ///
index d70cf132b3c3a83df35cf295df7bc68736429bd2..6c95854c66cbf096fa2b29daa7b5425f2e3ef92d 100644 (file)
 // 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<T: Clone>(x: T) -> (T, T, T) {
+///     (x.clone(), x.clone(), x.clone())
+/// }
+///
+/// fn generic_where<T>(x: T) -> T
+///     where T: std::ops::Add<Output=T> + 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::<i32>() {
+///     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::<i32>().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 { }
index 75c7a3d92809440c48817897331a5909bbf39b45..ad212a547579ba21df935237c4f8b16fa236e511 100644 (file)
 /// 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")]
index 3b432d05132095adc8206d36e022275c51ebb321..c2a16122a0dd1a2bb3383d351f8081b9276b2522 100644 (file)
@@ -323,8 +323,8 @@ mod prim_never { }
 /// let s = String::from("love: ❤️");
 /// let v: Vec<char> = s.chars().collect();
 ///
-/// assert_eq!(12, s.len() * std::mem::size_of::<u8>());
-/// assert_eq!(32, v.len() * std::mem::size_of::<char>());
+/// 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 { }
index 58ac4e944087ee7416e2ed36e4a832f9497545b2..a9219f75362db4dddb74cb879b98b305d05d5731 100644 (file)
@@ -1016,6 +1016,28 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 #[stable(feature = "stdio_from", since = "1.20.0")]
 impl From<ChildStdin> 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<ChildStdout> 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<ChildStderr> 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<fs::File> 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())
     }
index d69ebc17622720200a1db22eb5262621e99946ce..a7db372a0e20a86a42cf326c78d4949f4531fc2c 100644 (file)
@@ -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.
index 98845e457b25c8a25dd1ee5b9554cafbfa5269a8..cf9698cb2a9712b6a2439314503c0aef40e63ffd 100644 (file)
@@ -290,8 +290,8 @@ pub fn call_once_force<F>(&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
index 9ed628e2ed337d50e16e02073a342810f52cebbd..ee82b9860058a1fd1b68db5581aa84957d93871e 100644 (file)
@@ -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<A,B,C>` 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))
index e611eb86dc1b3214eb5637d5acb685f4a33881e2..d8fb20d425008e44fbec4d40019a0e77f9eb34a7 100644 (file)
@@ -96,7 +96,7 @@ pub fn process_cfg_attrs<T: HasAttrs>(&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<ast::Attribute> {
@@ -138,7 +138,7 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
         };
 
         // 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) => {
index 5bf1a7dd663cc228a0f556bc9e80fbac41d9b28f..1701c8da2c5bdc6283b491a97c45d3b516ca046f 100644 (file)
@@ -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<dyn MacResult+'cx>;
+    fn expand<'cx>(
+        &self,
+        ecx: &'cx mut ExtCtxt,
+        span: Span,
+        input: TokenStream,
+        def_span: Option<Span>,
+    ) -> Box<dyn MacResult+'cx>;
 }
 
 pub type MacroExpanderFn =
@@ -259,8 +264,13 @@ impl<F> TTMacroExpander for F
     where F: for<'cx> Fn(&'cx mut ExtCtxt, Span, &[tokenstream::TokenTree])
     -> Box<dyn MacResult+'cx>
 {
-    fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream)
-                   -> Box<dyn MacResult+'cx> {
+    fn expand<'cx>(
+        &self,
+        ecx: &'cx mut ExtCtxt,
+        span: Span,
+        input: TokenStream,
+        _def_span: Option<Span>,
+    ) -> Box<dyn MacResult+'cx> {
         struct AvoidInterpolatedIdents;
 
         impl Folder for AvoidInterpolatedIdents {
index 6210003a40da41d1e63fb64a5e4f41a94ee75253..7928ec1606b1d5b986db8f9a7df31474016d851d 100644 (file)
@@ -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,
index 9e06384f5a804e574124136419bba662902f37ac..33b651e1b385403b42f504d7b0ca65c4f255a493 100644 (file)
@@ -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();
         }
     }
 }
index 87ade278c685a7fadf4e9d8114861e6806c83725..f298d626cd833656b03aab1989e65c3558a92642 100644 (file)
@@ -50,7 +50,12 @@ pub struct ParserAnyMacro<'a> {
 impl<'a> ParserAnyMacro<'a> {
     pub fn make(mut self: Box<ParserAnyMacro<'a>>, 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<dyn MacResult+'cx> {
+    fn expand<'cx>(
+        &self,
+        cx: &'cx mut ExtCtxt,
+        sp: Span,
+        input: TokenStream,
+        def_span: Option<Span>,
+    ) -> Box<dyn MacResult+'cx> {
         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<Span>,
                           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::<Vec<_>>().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: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'static str)> {
+fn is_in_follow(tok: &quoted::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),
         }
     }
 }
index d0f407aa9243b84d8b410756c9a417eeb844e5d6..2cd4fd92bc81e97c9000d617217ce9219fb1575e 100644 (file)
@@ -501,6 +501,9 @@ pub fn walk_feature_fields<F>(&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! (
index 95a2298ca757db404c30d156b2e09e0e37db0cdd..bec193548e176389edb161ce37aad598fb831653 100644 (file)
@@ -468,8 +468,9 @@ pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
 
 pub fn noop_fold_path<T: Folder>(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<T: Folder>(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<T: Folder>(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))
                         }),
index 9c47589a0bd272f4899e0dc29421cee7abeb6044..589b3e30fcfbc41bbd24a258f4f70bd969e5a60a 100644 (file)
@@ -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)
index 45eaf1d3190f2f5ac4dc285d9b05b7f873b0629a..639155636edfa9ecf7f1e7375d9f3aaeaff79f34 100644 (file)
@@ -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 {
index 307650500de5b44dc1047dc9d15e449e09d92b57..431766a3fbcfb6dafb2d5a3866c1609bf44ee554 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 307650500de5b44dc1047dc9d15e449e09d92b57
+Subproject commit 431766a3fbcfb6dafb2d5a3866c1609bf44ee554
index 8469f0aa6645dcee14936f618a182ee5f6eecee6..85d1f3df05b1d2a1c49f0ea50eab1f11c05bd637 100644 (file)
@@ -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;
index 23c00c3bce1d836fd9b76ce7c1a1174ff4f6d0a7..dd1c2bd51260b066f2942a2f519165f6722b3caf 100644 (file)
@@ -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;
index 08de5320a2b324074840330f1dd90882aa9cf02f..6b0a28b8110073c9eac5bd5a7e48a2b4dd31973d 100644 (file)
@@ -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;
index 189154332b85a8c4f6464fa8ea759b6f1ff05adb..d8d48358e53fc27fb98a708dbeae316a480d7f5c 100644 (file)
@@ -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;
 //     }
index d5701669d2bddc6c891bd370f3052bfd0d4801d4..359ed07a9c0953466257eb38bfef40fd4818f624 100644 (file)
@@ -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: {
index 7a5d71ee21b93e16961a60171ba94d80cba525dd..3b632e198cd669dbef85b63062c888eee7a31b9d 100644 (file)
@@ -33,16 +33,16 @@ fn foo<F>(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: 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: 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
index b9162f85fa71ea3e376c19e52e7c3051b86226da..03c7de02ec11166236399cd1626c60b6329c5103 100644 (file)
@@ -33,16 +33,16 @@ fn foo<F>(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: 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: 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;
 //     }
index 4deea75e56b046ea556b7cf576149f1a36307230..56e3e0aa6f7a9a6ff195389ecb53682035817d3b 100644 (file)
@@ -33,13 +33,13 @@ fn foo<F>(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: 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];
 //     }
index 6f899a0db15d918f39cd62ca2c0fb9806fad3ec5..0a54dcaa0d33fa31f574df55d0f02868b4c69119 100644 (file)
@@ -31,37 +31,37 @@ fn foo<F>(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: 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;
 //     }
 // }
index b43f25e6f548c6c439494ee6ac76d19ecbf75ca9..ef2d949d3074eb4c990c8c06636c5d190abb9f1c 100644 (file)
@@ -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;
index 75cfb5c2f6239feac7efcc69c11008a84e4c62b6..3dbc73caf65d87e6d396fa5975f73adf0bf93094 100644 (file)
@@ -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<std::option::Option<&'36_0rs S<'36_0rs>>>;
-//     let mut _4: std::option::Option<&'36_0rs S<'36_0rs>>;
+//     let mut _3: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>;
+//     let mut _4: std::option::Option<&'49_0rs S<'49_0rs>>;
 //     let mut _5: ();
-//     let mut _6: &'17s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>;
-//     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<std::option::Option<&'49_0rs S<'49_0rs>>>;
+//     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<std::option::Option<&'36_0rs S<'36_0rs>>>;
-//     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<std::option::Option<&'49_0rs S<'49_0rs>>>;
+//     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 <std::cell::Cell<T>>::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<std::option::Option<&'36_0rs S<'36_0rs>>>);
+//         _6 = &'25s (_2.0: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>);
 //         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 <std::cell::Cell<T>>::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<std::option::Option<&'36_0rs S<'36_0rs>>>);
+//         _14 = &'47s (_2.0: std::cell::Cell<std::option::Option<&'49_0rs S<'49_0rs>>>);
 //         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 <std::cell::Cell<T>>::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;
 //     }
index 16e2fe046fb699f9cdf162cafd3b58306b8fbde9..a5107d304386f6b56b0caeaa1edfd4f9ce588982 100644 (file)
@@ -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;
 //     }
index aab432ddc8700159e7fa5dcb2bc252f0b611f1e3..ba1712f4ca39884985f47da40fcbc758fbefc180 100644 (file)
@@ -30,7 +30,7 @@ fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
 // ...
 // bb0: {
 //     ...
-//     _3 = [closure@NodeId(39)];
+//     _3 = [closure@NodeId(53)];
 //     ...
 //     _4 = &_3;
 //     ...
index 22e7de31e90cf2c95a5a527faf70422e6305fd99..9cb0a4dc2bfacf7c4df8d5cce916d6d75b169486 100644 (file)
@@ -26,7 +26,7 @@ fn foo<T: Copy>(_t: T, q: i32) -> i32 {
 // ...
 // bb0: {
 //     ...
-//     _3 = [closure@NodeId(28)];
+//     _3 = [closure@NodeId(39)];
 //     ...
 //     _4 = &_3;
 //     ...
index 882579c571086ab8e48566a942abece6c3dcbdc4..f1544968adb6a2135afe4b3486db2191fb787d44 100644 (file)
@@ -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;
 //     }
index 07f5b2aa84b7dda57e8dbb2958867272ac44981d..ce840397713ad6031063f69b97a21552734f301c 100644 (file)
@@ -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;
index 24a4ebd8429dfb559d887d928c824be17f46699b..542ac8a42411f1d852565b6be9f87f31f00e7646 100644 (file)
@@ -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;
index b4d4479bab94a62eeed89817efd827950a8b72ce..955de0c3bad043e45d8d46c2722e6bc5199e87dc 100644 (file)
@@ -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]);
index ac39118c5f1e01e0b96295e2207f319f5ae67ddd..27169299c8a69e4e4b883de9c98fc6f7552087f1 100644 (file)
@@ -38,7 +38,8 @@ impl TTMacroExpander for Expander {
     fn expand<'cx>(&self,
                    ecx: &'cx mut ExtCtxt,
                    sp: Span,
-                   _: TokenStream) -> Box<MacResult+'cx> {
+                   _: TokenStream,
+                   _: Option<Span>) -> Box<MacResult+'cx> {
         let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i))
             .collect::<Vec<_>>().join(", ");
         MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args)))
index a3a5337077cc694dab31a27b4d0e4ead09eedb3c..2abcd4b7ba99c49eb2ad6b4c1c88e228de7818ac 100644 (file)
@@ -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 (file)
index 0000000..e81b2c7
--- /dev/null
@@ -0,0 +1,16 @@
+macro_rules! test {
+    (
+        fn fun() -> Option<Box<$t:ty>>;
+    ) => {
+        fn fun(x: $t) -> Option<Box<$t>>
+        { Some(Box::new(x)) }
+    }
+}
+
+test! {
+    fn fun() -> Option<Box<i32>>;
+}
+
+fn main() {
+    println!("{}", fun(0).unwrap());
+}
index 62e495288cb9bca13cdb2dfd9239159b4e6588be..932fe1c8eb0b2a400f28aae56be0a25837670e6d 100644 (file)
@@ -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
 /// ```
index cf417f8d412eeb93232039968efe2b9a74ef3c44..876f6c0a80b1da7485360a9f62dbb118f3759c08 100644 (file)
@@ -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
 
index bcf0645766b30993f996a3c547c6013272c29ae0..3fb83bff916048214df8cd87b507d81e9c7a4a66 100644 (file)
@@ -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 (file)
index 0000000..1392c62
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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";
index 3748313593fc22bd37c5226da6fe76035c31f051..11a027a13f7e317f442d5ae5c91332ebbcc01ac6 100644 (file)
@@ -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 (file)
index 4594eb9..0000000
+++ /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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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"]' '"<script>"'
-pub const CONST_S: &'static str = "<script>";
index 18f5f086cd1a4ea85ad386c2c6831daf26bfa25e..aea5f44e2a72370d044fd9f100576ac669a2a2be 100644 (file)
@@ -28,12 +28,12 @@ fn this_should_be_hidden() {}
 
 // @has foo/struct.Foo.html
 // @!has - 'Methods'
-// @!has - 'impl Foo'
+// @!has - '//code' 'impl Foo'
 // @!has - 'this_should_be_hidden'
 pub use hidden::Foo;
 
 // @has foo/struct.Bar.html
 // @!has - 'Methods'
-// @!has - 'impl Bar'
+// @!has - '//code' 'impl Bar'
 // @!has - 'this_should_be_hidden'
 pub use hidden::Bar;
index cf9b30a0fe9873a46f96eade6c92126fea358e79..b0efee511bc7d034ed6dc3e4d1b1a8e040c03595 100644 (file)
@@ -22,5 +22,5 @@ pub trait Bar {
     fn bar(&self) {}
 }
 
-// @!has issue_13698/struct.Foo.html '//*[@id="method.foo"]' 'fn bar'
+// @!has issue_13698/struct.Foo.html '//*[@id="method.bar"]' 'fn bar'
 impl Bar for Foo {}
index 855de150b0a3707832b78bc39f06d0b99a4c234d..1e6b697cd5fd9b2429c8c917c2f57d31bb7933cb 100644 (file)
@@ -15,4 +15,5 @@ pub enum Enum{Variant}
 }
 pub use self::private::Enum::*;
 
-// @!has foo/index.html '//a/@href' './private/index.html'
+// @!has-dir foo/private
+// @!has foo/index.html '//a/@href' 'private/index.html'
diff --git a/src/test/rustdoc/issue-54478-demo-allocator.rs b/src/test/rustdoc/issue-54478-demo-allocator.rs
new file mode 100644 (file)
index 0000000..4811f36
--- /dev/null
@@ -0,0 +1,42 @@
+// Issue #54478: regression test showing that we can demonstrate
+// `#[global_allocator]` in code blocks built by `rustdoc`.
+//
+// ## Background
+//
+// Changes in lang-item visibility injected failures that were only
+// exposed when compiling with `-C prefer-dynamic`. But `rustdoc` used
+// `-C prefer-dynamic` (and had done so for years, for reasons we did
+// not document at that time).
+//
+// Rather than try to revise the visbility semanics, we instead
+// decided to change `rustdoc` to behave more like the compiler's
+// default setting, by leaving off `-C prefer-dynamic`.
+
+// compile-flags:--test
+
+//! This is a doc comment
+//!
+//! ```rust
+//! use std::alloc::*;
+//!
+//! #[global_allocator]
+//! static ALLOC: A = A;
+//!
+//! static mut HIT: bool = false;
+//!
+//! struct A;
+//!
+//! unsafe impl GlobalAlloc for A {
+//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+//!         HIT = true;
+//!         System.alloc(layout)
+//!     }
+//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+//!         System.dealloc(ptr, layout);
+//!     }
+//! }
+//!
+//! fn main() {
+//!     assert!(unsafe { HIT });
+//! }
+//! ```
diff --git a/src/test/rustdoc/issue-55001.rs b/src/test/rustdoc/issue-55001.rs
new file mode 100644 (file)
index 0000000..f6c7f9a
--- /dev/null
@@ -0,0 +1,31 @@
+// Regression test for issue #55001. Previously, we would incorrectly
+// cache certain trait selection results when checking for blanket impls,
+// resulting in an ICE when we tried to confirm the cached ParamCandidate
+// against an obligation.
+
+pub struct DefaultAllocator;
+pub struct Standard;
+pub struct Inner;
+
+pub trait Rand {}
+
+pub trait Distribution<T> {}
+pub trait Allocator<N> {}
+
+impl<T> Rand for T where Standard: Distribution<T> {}
+
+impl<A> Distribution<Point<A>> for Standard
+where
+DefaultAllocator: Allocator<A>,
+Standard: Distribution<A> {}
+
+impl Distribution<Inner> for Standard {}
+
+
+pub struct Point<N>
+where DefaultAllocator: Allocator<N>
+{
+    field: N
+}
+
+fn main() {}
index 54a8a7648334187dc606be45ed3fc1ffa9ff3e4d..db48a6525230cb8e9cf9a0ff3f4df63801274bee 100644 (file)
@@ -35,7 +35,6 @@ fn c_method(&self) -> usize {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
 // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
 // @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.'
 // @has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.'
 // @!has - '//*[@class="docblock"]' 'There is another line'
 // @has - '//*[@class="docblock"]' 'Read more'
index 00881a62dd0a8cc3a9ea550bbd428149c88900a9..2b3120fa5b4a15e166824a78eecef3ee222d8ffb 100644 (file)
@@ -12,6 +12,8 @@
 
 #![doc(html_playground_url = "")]
 
+// compile-flags:-Z unstable-options --playground-url https://play.rust-lang.org/
+
 //! module docs
 //!
 //! ```
index 98e66e8c024bd3a49d48e574aa265db506cdba6b..c20dd815d8ce7cac3bb1b472a8d077a993657f7f 100644 (file)
@@ -43,6 +43,7 @@ impl ::Foo for Qux {}
 
 // @has redirect/index.html
 // @has - '//code' 'pub use private_no_inline::Qux'
-// @!has - '//code/a' 'Qux'
+// @!has - '//a' 'Qux'
+// @!has redirect/struct.Qux.html
 #[doc(no_inline)]
 pub use private_no_inline::Qux;
index 2c074179e32b57105eda433b32bdd94bc39ff9b7..c87b533b9d47453084382e40ca2f60e5e3dc92e7 100644 (file)
@@ -12,4 +12,4 @@
 
 pub struct Bar;
 
-// @!has foo/struct.Bar.html '//*[@id="implementations"]'
+// @count foo/struct.Bar.html '//*[@id="implementations"]' 0
diff --git a/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs b/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs
new file mode 100644 (file)
index 0000000..e320ad9
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-pass
+// edition:2018
+
+#![feature(extern_crate_item_prelude)]
+
+extern crate proc_macro;
+use proc_macro::TokenStream; // OK
+
+fn main() {}
index 278409c688ab9dcfa581b523f3578aa17ed13062..59ca668d4852553736fd0879fa9f54394204748c 100644 (file)
@@ -20,7 +20,7 @@ error: cannot find derive macro `attr_proc_macra` in this scope
   --> $DIR/resolve-error.rs:54:10
    |
 LL | #[derive(attr_proc_macra)]
-   |          ^^^^^^^^^^^^^^^
+   |          ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro`
 
 error: cannot find macro `FooWithLongNama!` in this scope
   --> $DIR/resolve-error.rs:59:5
index 0a12aa76a785b3861baa13f76800f8326aaade18..6b9d4ebb2987dd3f53376c99909d0c3e09041e7c 100644 (file)
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
   --> $DIR/bound-lifetime-in-binding-only.rs:62:23
    |
 LL | fn elision<T: Fn() -> &i32>() {
-   |                       ^ expected lifetime parameter
+   |                       ^ help: consider giving it a 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = help: consider giving it a 'static lifetime
 
 error: aborting due to previous error
 
index 8fefdfd4d19efe621e843061d23ff0dd938a2899..7906f0a30e4eb33a33306e9db4b2a1b9c0f6a303 100644 (file)
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
   --> $DIR/bound-lifetime-in-return-only.rs:44:23
    |
 LL | fn elision(_: fn() -> &i32) {
-   |                       ^ expected lifetime parameter
+   |                       ^ help: consider giving it a 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = help: consider giving it a 'static lifetime
 
 error: aborting due to previous error
 
index 3cf76365c77b1079da97ac643413c20618a58309..b116888d63c1008c627dc772f585260ff4a396b1 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Test that we do some basic error correcton in the tokeniser (and don't spew
+// Test that we do some basic error correction in the tokeniser (and don't spew
 // too many bogus errors).
 
 fn foo() -> usize {
index 84bd33fc0e7d3ce5541f4252bd64328891a18137..ec4ee80b498a57c6d8a31ff9bff4833a1106eec0 100644 (file)
@@ -1,5 +1,5 @@
 // Test that cfg_attr doesn't emit any attributes when the
-// configuation variable is false. This mirrors `cfg-attr-multi-true.rs`
+// configuration variable is false. This mirrors `cfg-attr-multi-true.rs`
 
 // compile-pass
 
diff --git a/src/test/ui/consts/const-eval/double_promotion.rs b/src/test/ui/consts/const-eval/double_promotion.rs
new file mode 100644 (file)
index 0000000..0e75ea8
--- /dev/null
@@ -0,0 +1,17 @@
+// compile-pass
+
+#![feature(const_fn, rustc_attrs)]
+
+#[rustc_args_required_const(0)]
+pub const fn a(value: u8) -> u8 {
+    value
+}
+
+#[rustc_args_required_const(0)]
+pub fn b(_: u8) {
+    unimplemented!()
+}
+
+fn main() {
+    let _ = b(a(0));
+}
index 15139e4e8ae36a986fe131be1bf80895df3d9ca0..fca29c9a9f64437b4b806e182997b5e4a8e362af 100644 (file)
@@ -7,8 +7,20 @@ LL |         (&mut self).bar(); //~ ERROR cannot borrow
    |         cannot borrow as mutable
    |         try removing `&mut` here
 
+warning: function cannot return without recursing
+  --> $DIR/issue-31424.rs:22:5
+   |
+LL |     fn bar(self: &mut Self) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |         //~^ WARN function cannot return without recursing
+LL |         (&mut self).bar(); //~ ERROR cannot borrow
+   |         ----------------- recursive call site
+   |
+   = note: #[warn(unconditional_recursion)] on by default
+   = help: a `loop` may express intention better if this is on purpose
+
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-31424.rs:23:9
+  --> $DIR/issue-31424.rs:24:9
    |
 LL |         (&mut self).bar(); //~ ERROR cannot borrow
    |         ^^^^^^^^^^^
index 1b31e064337e25bd27ed968a63d964830860ea84..903a76a8243382301001e0c65e4d84f2ac6d59c3 100644 (file)
@@ -20,6 +20,7 @@ fn foo(&mut self) {
     // In this case we could keep the suggestion, but to distinguish the
     // two cases is pretty hard. It's an obscure case anyway.
     fn bar(self: &mut Self) {
+        //~^ WARN function cannot return without recursing
         (&mut self).bar(); //~ ERROR cannot borrow
     }
 }
index 9d0ab21ffaf0e3259157dab6b3acf1a8dc995ca7..2e4bcc7f95947e31811a5d2baf549cfc9e52d491 100644 (file)
@@ -7,8 +7,20 @@ LL |         (&mut self).bar(); //~ ERROR cannot borrow
    |               cannot reborrow mutably
    |               try removing `&mut` here
 
+warning: function cannot return without recursing
+  --> $DIR/issue-31424.rs:22:5
+   |
+LL |     fn bar(self: &mut Self) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |         //~^ WARN function cannot return without recursing
+LL |         (&mut self).bar(); //~ ERROR cannot borrow
+   |         ----------------- recursive call site
+   |
+   = note: #[warn(unconditional_recursion)] on by default
+   = help: a `loop` may express intention better if this is on purpose
+
 error[E0596]: cannot borrow immutable argument `self` as mutable
-  --> $DIR/issue-31424.rs:23:15
+  --> $DIR/issue-31424.rs:24:15
    |
 LL |         (&mut self).bar(); //~ ERROR cannot borrow
    |               ^^^^ cannot borrow mutably
index ff4bb428d5f5f73794d55b3bd6444b8bd551bea1..1c79499ba590276610c31e1b179e6dcc5dc35bb7 100644 (file)
@@ -20,4 +20,20 @@ fn main() {
     let n: usize = 42;
     this_function_expects_a_double_option(n);
     //~^ ERROR mismatched types
+    //~| HELP try using a variant of the expected type
+}
+
+
+// But don't issue the "try using a variant" help if the one-"variant" ADT is
+// actually a one-field struct.
+
+struct Payload;
+
+struct Wrapper { payload: Payload }
+
+struct Context { wrapper: Wrapper }
+
+fn overton() {
+    let _c = Context { wrapper: Payload{} };
+    //~^ ERROR mismatched types
 }
index f1da920872d7c7321997eed83e7c96bf100eb52b..e256a436affbad2bc4ad8bfe793d39bf835979ec 100644 (file)
@@ -13,6 +13,15 @@ LL |     this_function_expects_a_double_option(DoubleOption::FirstSome(n));
 LL |     this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/issue-42764.rs:37:33
+   |
+LL |     let _c = Context { wrapper: Payload{} };
+   |                                 ^^^^^^^^^ expected struct `Wrapper`, found struct `Payload`
+   |
+   = note: expected type `Wrapper`
+              found type `Payload`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index a629d13e6c31bd72526a5e4c64b4c62868344f70..e8f05cbb0ef70a069f26c96db3d6b665c4251368 100644 (file)
@@ -2,13 +2,13 @@ error: no rules expected the token `r#async`
   --> $DIR/edition-keywords-2015-2015-parsing.rs:22:31
    |
 LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-   |                               ^^^^^^^
+   |                               ^^^^^^^ no rules expected the token `r#async`
 
 error: no rules expected the token `async`
   --> $DIR/edition-keywords-2015-2015-parsing.rs:23:35
    |
 LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
-   |                                   ^^^^^
+   |                                   ^^^^^ no rules expected the token `async`
 
 error: aborting due to 2 previous errors
 
index ab8a34a4a9e3dabee4decdcbcfe8fe50a533d8fe..3f5e1137383dda5f8350b7c04fe200ddee4b9a41 100644 (file)
@@ -2,13 +2,13 @@ error: no rules expected the token `r#async`
   --> $DIR/edition-keywords-2015-2018-parsing.rs:22:31
    |
 LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-   |                               ^^^^^^^
+   |                               ^^^^^^^ no rules expected the token `r#async`
 
 error: no rules expected the token `async`
   --> $DIR/edition-keywords-2015-2018-parsing.rs:23:35
    |
 LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
-   |                                   ^^^^^
+   |                                   ^^^^^ no rules expected the token `async`
 
 error: aborting due to 2 previous errors
 
index 5955410aa106b15582ac56b85c2e04d29e5a31f0..b6ff60f1492ea99b62eb78a3ec342fcff3a45dc6 100644 (file)
@@ -14,13 +14,13 @@ error: no rules expected the token `r#async`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:22:31
    |
 LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-   |                               ^^^^^^^
+   |                               ^^^^^^^ no rules expected the token `r#async`
 
 error: no rules expected the token `async`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:23:35
    |
 LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
-   |                                   ^^^^^
+   |                                   ^^^^^ no rules expected the token `async`
 
 error: expected one of `move`, `|`, or `||`, found `<eof>`
   --> <::edition_kw_macro_2015::passes_ident macros>:1:22
index 6ea736828f9078e95716a36760032b4b3d3b50fe..ffe666a7e6442875ba5f491426a13ed0ea1dca3e 100644 (file)
@@ -14,13 +14,13 @@ error: no rules expected the token `r#async`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:22:31
    |
 LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-   |                               ^^^^^^^
+   |                               ^^^^^^^ no rules expected the token `r#async`
 
 error: no rules expected the token `async`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:23:35
    |
 LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
-   |                                   ^^^^^
+   |                                   ^^^^^ no rules expected the token `async`
 
 error: expected one of `move`, `|`, or `||`, found `<eof>`
   --> <::edition_kw_macro_2018::passes_ident macros>:1:22
index d6990c4eaeb8f2f40ebb394c7a01c564431e60a8..de826102081e77ef10fd0fcc3b3a18669a6f5fa7 100644 (file)
@@ -1,8 +1,11 @@
 error: unexpected end of macro invocation
   --> $DIR/empty-comment.rs:20:5
    |
+LL | macro_rules! one_arg_macro {
+   | -------------------------- when calling this macro
+...
 LL |     one_arg_macro!(/**/); //~ ERROR unexpected end
-   |     ^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^ unexpected end of macro invocation
 
 error: aborting due to previous error
 
index 764f2c464bcb8c90be51025f7f3be1fd9e5f17a1..4a4aec5b6ac570e24c1d6c7a2f93f5caed26dbbc 100644 (file)
@@ -2,7 +2,7 @@ error: no rules expected the token `@`
   --> $DIR/fail-simple.rs:12:12
    |
 LL |     panic!(@); //~ ERROR no rules expected the token `@`
-   |            ^
+   |            ^ no rules expected the token `@`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs
new file mode 100644 (file)
index 0000000..a043b6c
--- /dev/null
@@ -0,0 +1,46 @@
+// edition:2018
+
+#![feature(alloc)]
+
+extern crate alloc;
+
+mod in_scope {
+    fn check() {
+        let v = alloc::vec![0];
+        //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+        type A = alloc::boxed::Box<u8>;
+        //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+    }
+}
+
+mod absolute {
+    fn check() {
+        let v = ::alloc::vec![0];
+        //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+        type A = ::alloc::boxed::Box<u8>;
+        //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+    }
+}
+
+mod import_in_scope {
+    use alloc;
+    //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+    use alloc::boxed;
+    //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+}
+
+mod import_absolute {
+    use ::alloc;
+    //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+    use ::alloc::boxed;
+    //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+}
+
+extern crate alloc as core;
+
+mod unrelated_crate_renamed {
+    type A = core::boxed::Box<u8>;
+    //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr
new file mode 100644 (file)
index 0000000..cabfb56
--- /dev/null
@@ -0,0 +1,75 @@
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:26:9
+   |
+LL |     use alloc;
+   |         ^^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:28:9
+   |
+LL |     use alloc::boxed;
+   |         ^^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:33:11
+   |
+LL |     use ::alloc;
+   |           ^^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:35:11
+   |
+LL |     use ::alloc::boxed;
+   |           ^^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:9:17
+   |
+LL |         let v = alloc::vec![0];
+   |                 ^^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:11:18
+   |
+LL |         type A = alloc::boxed::Box<u8>;
+   |                  ^^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:18:19
+   |
+LL |         let v = ::alloc::vec![0];
+   |                   ^^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:20:20
+   |
+LL |         type A = ::alloc::boxed::Box<u8>;
+   |                    ^^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+  --> $DIR/feature-gate-extern_crate_item_prelude.rs:42:14
+   |
+LL |     type A = core::boxed::Box<u8>;
+   |              ^^^^
+   |
+   = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/foreign-fn-return-lifetime.fixed b/src/test/ui/foreign-fn-return-lifetime.fixed
new file mode 100644 (file)
index 0000000..9fc35ea
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2017 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-rustfix
+
+extern "C" {
+    pub fn g(_: &u8) -> &u8; // OK
+    pub fn f() -> &'static u8; //~ ERROR missing lifetime specifier
+}
+
+fn main() {}
index da77066150cc72d0929057cf26eee0f6c3ee4c7c..941e7e05a3635f47d4f7d381fa42e8e3abc12a0a 100644 (file)
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// run-rustfix
+
 extern "C" {
-    fn g(_: &u8) -> &u8; // OK
-    fn f() -> &u8; //~ ERROR missing lifetime specifier
+    pub fn g(_: &u8) -> &u8; // OK
+    pub fn f() -> &u8; //~ ERROR missing lifetime specifier
 }
 
 fn main() {}
index ea15897b3d69499eeee7d66de1de05b532c8663d..583487656f24d714fa9f2bdcd6f85b5acb80e4b1 100644 (file)
@@ -1,11 +1,10 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/foreign-fn-return-lifetime.rs:13:15
+  --> $DIR/foreign-fn-return-lifetime.rs:15:19
    |
-LL |     fn f() -> &u8; //~ ERROR missing lifetime specifier
-   |               ^ expected lifetime parameter
+LL |     pub fn f() -> &u8; //~ ERROR missing lifetime specifier
+   |                   ^ help: consider giving it a 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = help: consider giving it a 'static lifetime
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs b/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs
new file mode 100644 (file)
index 0000000..c48a657
--- /dev/null
@@ -0,0 +1,17 @@
+// compile-pass
+// compile-flags:--cfg my_feature
+
+#![feature(extern_crate_item_prelude)]
+#![no_std]
+
+#[cfg(my_feature)]
+extern crate std;
+
+mod m {
+    #[cfg(my_feature)]
+    fn conditional() {
+        std::vec::Vec::<u8>::new(); // OK
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs
new file mode 100644 (file)
index 0000000..57b097c
--- /dev/null
@@ -0,0 +1,22 @@
+// aux-build:two_macros.rs
+// compile-flags:--extern non_existent
+
+mod n {
+    extern crate two_macros;
+}
+
+mod m {
+    fn check() {
+        two_macros::m!(); //~ ERROR failed to resolve. Use of undeclared type or module `two_macros`
+    }
+}
+
+macro_rules! define_std_as_non_existent {
+    () => {
+        extern crate std as non_existent;
+        //~^ ERROR `extern crate` items cannot shadow names passed with `--extern`
+    }
+}
+define_std_as_non_existent!();
+
+fn main() {}
diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr
new file mode 100644 (file)
index 0000000..8f68d2a
--- /dev/null
@@ -0,0 +1,18 @@
+error: macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+  --> $DIR/extern-prelude-extern-crate-fail.rs:16:9
+   |
+LL |         extern crate std as non_existent;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | define_std_as_non_existent!();
+   | ------------------------------ in this macro invocation
+
+error[E0433]: failed to resolve. Use of undeclared type or module `two_macros`
+  --> $DIR/extern-prelude-extern-crate-fail.rs:10:9
+   |
+LL |         two_macros::m!(); //~ ERROR failed to resolve. Use of undeclared type or module `two_macros`
+   |         ^^^^^^^^^^ Use of undeclared type or module `two_macros`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/imports/extern-prelude-extern-crate-pass.rs b/src/test/ui/imports/extern-prelude-extern-crate-pass.rs
new file mode 100644 (file)
index 0000000..8c147df
--- /dev/null
@@ -0,0 +1,14 @@
+// compile-pass
+// aux-build:two_macros.rs
+
+#![feature(extern_crate_item_prelude)]
+
+extern crate two_macros;
+
+mod m {
+    fn check() {
+        two_macros::m!(); // OK
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs
new file mode 100644 (file)
index 0000000..732f1c4
--- /dev/null
@@ -0,0 +1,19 @@
+// aux-build:two_macros.rs
+
+#![feature(extern_crate_item_prelude)]
+
+macro_rules! define_vec {
+    () => {
+        extern crate std as Vec;
+    }
+}
+
+define_vec!();
+
+mod m {
+    fn check() {
+        Vec::panic!(); //~ ERROR `Vec` is ambiguous
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr
new file mode 100644 (file)
index 0000000..6c832e7
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0659]: `Vec` is ambiguous
+  --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:15:9
+   |
+LL |         Vec::panic!(); //~ ERROR `Vec` is ambiguous
+   |         ^^^ ambiguous name
+   |
+note: `Vec` could refer to the name defined here
+  --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:7:9
+   |
+LL |         extern crate std as Vec;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | define_vec!();
+   | -------------- in this macro invocation
+note: `Vec` could also refer to the name defined here
+   = note: macro-expanded items do not shadow when used in a macro invocation path
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
index ab6d041bd48d731ac747a3019be44e452da776e6..e592452b899444676d4825e976716455949fa724 100644 (file)
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
   --> $DIR/issue-13497.rs:12:5
    |
 LL |     &str //~ ERROR missing lifetime specifier
-   |     ^ expected lifetime parameter
+   |     ^ help: consider giving it a 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = help: consider giving it a 'static lifetime
 
 error: aborting due to previous error
 
index cf6fcd9f01cc868357a4f624e5a67d7d554f0ccf..0ac6316f0dcf8da9a96d6930cb0f7a4385d25e32 100644 (file)
@@ -10,19 +10,17 @@ error[E0106]: missing lifetime specifier
   --> $DIR/issue-26638.rs:14:40
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
-   |                                        ^ expected lifetime parameter
+   |                                        ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-   = help: consider giving it an explicit bounded or 'static lifetime
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-26638.rs:17:22
    |
 LL | fn parse_type_3() -> &str { unimplemented!() }
-   |                      ^ expected lifetime parameter
+   |                      ^ help: consider giving it a 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = help: consider giving it a 'static lifetime
 
 error: aborting due to 3 previous errors
 
index a467ff6dd0a1ada7050fb7f0842a2256967bd44b..028ed048d6525c768d29334178b0f0fcc2fd4401 100644 (file)
@@ -3,12 +3,11 @@ error: macro expansion ignores token `;` and any following
    |
 LL |     () => ( String ; );     //~ ERROR macro expansion ignores token `;`
    |                    ^
-   |
-note: caused by the macro expansion here; the usage of `t!` is likely invalid in type context
-  --> $DIR/issue-30007.rs:16:16
-   |
+...
 LL |     let i: Vec<t!()>;
-   |                ^^^^
+   |                ---- caused by the macro expansion here
+   |
+   = note: the usage of `t!` is likely invalid in type context
 
 error: aborting due to previous error
 
index 7ad95717185b80bef1a7de78e72e0734d81eb34d..96fb374b58c6c7a4e2b918e66a3097c279845b0f 100644 (file)
@@ -1,8 +1,11 @@
 error: unexpected end of macro invocation
   --> $DIR/issue-7970a.rs:16:5
    |
+LL | macro_rules! one_arg_macro {
+   | -------------------------- when calling this macro
+...
 LL |     one_arg_macro!();
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^ unexpected end of macro invocation
 
 error: aborting due to previous error
 
index 30cff86ed1d4047fd3e3db4c24fac946e03b6d9c..4c7a1b5ea9ff046c5b3168e8c9ee57a308890c1f 100644 (file)
@@ -2,10 +2,9 @@ error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:12:11
    |
 LL | fn f() -> &isize {    //~ ERROR missing lifetime specifier
-   |           ^ expected lifetime parameter
+   |           ^ help: consider giving it a 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = help: consider giving it a 'static lifetime
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:17:33
@@ -27,28 +26,25 @@ error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:31:20
    |
 LL | fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier
-   |                    ^ expected lifetime parameter
+   |                    ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-   = help: consider giving it an explicit bounded or 'static lifetime
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:44:24
    |
 LL | fn j(_x: StaticStr) -> &isize { //~ ERROR missing lifetime specifier
-   |                        ^ expected lifetime parameter
+   |                        ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-   = help: consider giving it an explicit bounded or 'static lifetime
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:50:49
    |
 LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
-   |                                                 ^ expected lifetime parameter
+   |                                                 ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static`
    |
    = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-   = help: consider giving it an explicit bounded or 'static lifetime
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.rs
new file mode 100644 (file)
index 0000000..eb959bf
--- /dev/null
@@ -0,0 +1,12 @@
+trait Future {
+    type Item;
+    type Error;
+}
+
+use std::error::Error;
+
+fn foo() -> impl Future<Item=(), Error=Box<Error>> {
+    Ok(())
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr b/src/test/ui/lifetimes/lifetime-elision-return-type-trait.stderr
new file mode 100644 (file)
index 0000000..b2a3d9a
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/lifetime-elision-return-type-trait.rs:8:44
+   |
+LL | fn foo() -> impl Future<Item=(), Error=Box<Error>> {
+   |                                            ^^^^^ help: consider giving it a 'static lifetime: `Error + 'static`
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0106`.
index ff50b3b1ab68f6dd21d17d02a39c0c8914de4aee..77d546a00ecd47fd8b2df908227a8191f475f68d 100644 (file)
@@ -56,7 +56,7 @@ fn main() {
     while true {
     //~^ WARN denote infinite loops
     //~| HELP use `loop`
-        let mut a = (1);
+        let mut registry_no = (format!("NX-{}", 74205));
         //~^ WARN does not need to be mutable
         //~| HELP remove this `mut`
         //~| WARN unnecessary parentheses
@@ -72,6 +72,6 @@ fn main() {
             //~^ WARN this pattern is redundant
             //~| HELP remove this
         }
-        println!("{} {}", a, b);
+        println!("{} {}", registry_no, b);
     }
 }
index 340a4a48512e2e0bd88fc6686c455da8b730b7b3..73704614815bed69407bed2750f4603dc042b3d1 100644 (file)
@@ -1,8 +1,8 @@
 warning: unnecessary parentheses around assigned value
-  --> $DIR/suggestions.rs:59:21
+  --> $DIR/suggestions.rs:59:31
    |
-LL |         let mut a = (1);
-   |                     ^^^ help: remove these parentheses
+LL |         let mut registry_no = (format!("NX-{}", 74205));
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses
    |
 note: lint level defined here
   --> $DIR/suggestions.rs:13:21
@@ -21,8 +21,8 @@ LL | #[no_debug] // should suggest removal of deprecated attribute
 warning: variable does not need to be mutable
   --> $DIR/suggestions.rs:59:13
    |
-LL |         let mut a = (1);
-   |             ----^
+LL |         let mut registry_no = (format!("NX-{}", 74205));
+   |             ----^^^^^^^^^^^
    |             |
    |             help: remove this `mut`
    |
index 22f1c94fced6f3cbf02d63c49ae579e252d128c8..7705ba3b11ed58f9adc0905224f3018f11ed7d6a 100644 (file)
@@ -51,20 +51,29 @@ LL |     ($(a)?*) => {}
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018-feature-gate.rs:41:11
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a?); //~ ERROR no rules expected the token `?`
-   |           ^
+   |           ^ no rules expected the token `?`
 
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018-feature-gate.rs:42:11
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a?a); //~ ERROR no rules expected the token `?`
-   |           ^
+   |           ^ no rules expected the token `?`
 
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018-feature-gate.rs:43:11
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a?a?a); //~ ERROR no rules expected the token `?`
-   |           ^
+   |           ^ no rules expected the token `?`
 
 error: aborting due to 10 previous errors
 
index 0a15bdb10686d9e01fef808ca474af1a4d4c6b1f..25dd66b81f567f0e86494d08d459e730bcadbf29 100644 (file)
@@ -7,68 +7,101 @@ LL |     ($(a),?) => {} //~ERROR the `?` macro repetition operator
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:36:11
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a?); //~ ERROR no rules expected the token `?`
-   |           ^
+   |           ^ no rules expected the token `?`
 
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:37:11
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a?a); //~ ERROR no rules expected the token `?`
-   |           ^
+   |           ^ no rules expected the token `?`
 
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:38:11
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a?a?a); //~ ERROR no rules expected the token `?`
-   |           ^
+   |           ^ no rules expected the token `?`
 
 error: unexpected end of macro invocation
   --> $DIR/macro-at-most-once-rep-2018.rs:40:5
    |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
 LL |     barplus!(); //~ERROR unexpected end of macro invocation
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ unexpected end of macro invocation
 
 error: unexpected end of macro invocation
   --> $DIR/macro-at-most-once-rep-2018.rs:41:14
    |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
 LL |     barplus!(a); //~ERROR unexpected end of macro invocation
-   |              ^
+   |              ^ unexpected end of macro invocation
 
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:42:15
    |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
 LL |     barplus!(a?); //~ ERROR no rules expected the token `?`
-   |               ^
+   |               ^ no rules expected the token `?`
 
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:43:15
    |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
 LL |     barplus!(a?a); //~ ERROR no rules expected the token `?`
-   |               ^
+   |               ^ no rules expected the token `?`
 
 error: unexpected end of macro invocation
   --> $DIR/macro-at-most-once-rep-2018.rs:47:5
    |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
 LL |     barstar!(); //~ERROR unexpected end of macro invocation
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ unexpected end of macro invocation
 
 error: unexpected end of macro invocation
   --> $DIR/macro-at-most-once-rep-2018.rs:48:14
    |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
 LL |     barstar!(a); //~ERROR unexpected end of macro invocation
-   |              ^
+   |              ^ unexpected end of macro invocation
 
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:49:15
    |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
 LL |     barstar!(a?); //~ ERROR no rules expected the token `?`
-   |               ^
+   |               ^ no rules expected the token `?`
 
 error: no rules expected the token `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:50:15
    |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
 LL |     barstar!(a?a); //~ ERROR no rules expected the token `?`
-   |               ^
+   |               ^ no rules expected the token `?`
 
 error: aborting due to 12 previous errors
 
index b3e67fb2607cdb568a2110e907076e46fb62337d..005e1d1c8e7cf95679894b7dfd197f52ab0ea5dd 100644 (file)
@@ -3,36 +3,33 @@ error: macro expansion ignores token `;` and any following
    |
 LL |     () => ( i ; typeof );   //~ ERROR expected expression, found reserved keyword `typeof`
    |               ^
-   |
-note: caused by the macro expansion here; the usage of `m!` is likely invalid in type context
-  --> $DIR/macro-context.rs:20:12
-   |
+...
 LL |     let a: m!();
-   |            ^^^^
+   |            ---- caused by the macro expansion here
+   |
+   = note: the usage of `m!` is likely invalid in type context
 
 error: macro expansion ignores token `typeof` and any following
   --> $DIR/macro-context.rs:13:17
    |
 LL |     () => ( i ; typeof );   //~ ERROR expected expression, found reserved keyword `typeof`
    |                 ^^^^^^
-   |
-note: caused by the macro expansion here; the usage of `m!` is likely invalid in expression context
-  --> $DIR/macro-context.rs:21:13
-   |
+...
 LL |     let i = m!();
-   |             ^^^^
+   |             ---- caused by the macro expansion here
+   |
+   = note: the usage of `m!` is likely invalid in expression context
 
 error: macro expansion ignores token `;` and any following
   --> $DIR/macro-context.rs:13:15
    |
 LL |     () => ( i ; typeof );   //~ ERROR expected expression, found reserved keyword `typeof`
    |               ^
-   |
-note: caused by the macro expansion here; the usage of `m!` is likely invalid in pattern context
-  --> $DIR/macro-context.rs:23:9
-   |
+...
 LL |         m!() => {}
-   |         ^^^^
+   |         ---- caused by the macro expansion here
+   |
+   = note: the usage of `m!` is likely invalid in pattern context
 
 error: expected expression, found reserved keyword `typeof`
   --> $DIR/macro-context.rs:13:17
index ccd658af89fbb1abbcaae78dfb55dd30fa5e575d..8760f6eb572e38973410f6e08dc07706c07da62e 100644 (file)
@@ -2,511 +2,681 @@ error: `$p:pat` is followed by `(`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:17:14
    |
 LL |     ($p:pat ()) => {};       //~ERROR  `$p:pat` is followed by `(`
-   |              ^
+   |              ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:18:14
    |
 LL |     ($p:pat []) => {};       //~ERROR  `$p:pat` is followed by `[`
-   |              ^
+   |              ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:19:14
    |
 LL |     ($p:pat {}) => {};       //~ERROR  `$p:pat` is followed by `{`
-   |              ^
+   |              ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:20:13
    |
 LL |     ($p:pat :) => {};        //~ERROR `$p:pat` is followed by `:`
-   |             ^
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:21:13
    |
 LL |     ($p:pat >) => {};        //~ERROR `$p:pat` is followed by `>`
-   |             ^
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:22:13
    |
 LL |     ($p:pat +) => {};        //~ERROR `$p:pat` is followed by `+`
-   |             ^
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:23:13
    |
 LL |     ($p:pat ident) => {};    //~ERROR `$p:pat` is followed by `ident`
-   |             ^^^^^
+   |             ^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$p:pat`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:24:13
    |
 LL |     ($p:pat $p:pat) => {};   //~ERROR `$p:pat` is followed by `$p:pat`
-   |             ^^^^^^
+   |             ^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:25:13
    |
 LL |     ($p:pat $e:expr) => {};  //~ERROR `$p:pat` is followed by `$e:expr`
-   |             ^^^^^^^
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:26:13
    |
 LL |     ($p:pat $t:ty) => {};    //~ERROR `$p:pat` is followed by `$t:ty`
-   |             ^^^^^
+   |             ^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:27:13
    |
 LL |     ($p:pat $s:stmt) => {};  //~ERROR `$p:pat` is followed by `$s:stmt`
-   |             ^^^^^^^
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$p:path`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:28:13
    |
 LL |     ($p:pat $p:path) => {};  //~ERROR `$p:pat` is followed by `$p:path`
-   |             ^^^^^^^
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:29:13
    |
 LL |     ($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block`
-   |             ^^^^^^^^
+   |             ^^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:30:13
    |
 LL |     ($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident`
-   |             ^^^^^^^^
+   |             ^^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:31:13
    |
 LL |     ($p:pat $t:tt) => {};    //~ERROR `$p:pat` is followed by `$t:tt`
-   |             ^^^^^
+   |             ^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:32:13
    |
 LL |     ($p:pat $i:item) => {};  //~ERROR `$p:pat` is followed by `$i:item`
-   |             ^^^^^^^
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments
   --> $DIR/macro-follow.rs:33:13
    |
 LL |     ($p:pat $m:meta) => {};  //~ERROR `$p:pat` is followed by `$m:meta`
-   |             ^^^^^^^
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:37:15
    |
 LL |     ($e:expr ()) => {};       //~ERROR  `$e:expr` is followed by `(`
-   |               ^
+   |               ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:38:15
    |
 LL |     ($e:expr []) => {};       //~ERROR  `$e:expr` is followed by `[`
-   |               ^
+   |               ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:39:15
    |
 LL |     ($e:expr {}) => {};       //~ERROR  `$e:expr` is followed by `{`
-   |               ^
+   |               ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:40:14
    |
 LL |     ($e:expr =) => {};        //~ERROR `$e:expr` is followed by `=`
-   |              ^
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:41:14
    |
 LL |     ($e:expr |) => {};        //~ERROR `$e:expr` is followed by `|`
-   |              ^
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:42:14
    |
 LL |     ($e:expr :) => {};        //~ERROR `$e:expr` is followed by `:`
-   |              ^
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:43:14
    |
 LL |     ($e:expr >) => {};        //~ERROR `$e:expr` is followed by `>`
-   |              ^
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:44:14
    |
 LL |     ($e:expr +) => {};        //~ERROR `$e:expr` is followed by `+`
-   |              ^
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:45:14
    |
 LL |     ($e:expr ident) => {};    //~ERROR `$e:expr` is followed by `ident`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:46:14
    |
 LL |     ($e:expr if) => {};       //~ERROR `$e:expr` is followed by `if`
-   |              ^^
+   |              ^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:47:14
    |
 LL |     ($e:expr in) => {};       //~ERROR `$e:expr` is followed by `in`
-   |              ^^
+   |              ^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:48:14
    |
 LL |     ($e:expr $p:pat) => {};   //~ERROR `$e:expr` is followed by `$p:pat`
-   |              ^^^^^^
+   |              ^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$e:expr`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:49:14
    |
 LL |     ($e:expr $e:expr) => {};  //~ERROR `$e:expr` is followed by `$e:expr`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:50:14
    |
 LL |     ($e:expr $t:ty) => {};    //~ERROR `$e:expr` is followed by `$t:ty`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:51:14
    |
 LL |     ($e:expr $s:stmt) => {};  //~ERROR `$e:expr` is followed by `$s:stmt`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:52:14
    |
 LL |     ($e:expr $p:path) => {};  //~ERROR `$e:expr` is followed by `$p:path`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:53:14
    |
 LL |     ($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block`
-   |              ^^^^^^^^
+   |              ^^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:54:14
    |
 LL |     ($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident`
-   |              ^^^^^^^^
+   |              ^^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:55:14
    |
 LL |     ($e:expr $t:tt) => {};    //~ERROR `$e:expr` is followed by `$t:tt`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:56:14
    |
 LL |     ($e:expr $i:item) => {};  //~ERROR `$e:expr` is followed by `$i:item`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments
   --> $DIR/macro-follow.rs:57:14
    |
 LL |     ($e:expr $m:meta) => {};  //~ERROR `$e:expr` is followed by `$m:meta`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:62:13
    |
 LL |     ($t:ty ()) => {};       //~ERROR  `$t:ty` is followed by `(`
-   |             ^
+   |             ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:64:12
    |
 LL |     ($t:ty +) => {};        //~ERROR `$t:ty` is followed by `+`
-   |            ^
+   |            ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:65:12
    |
 LL |     ($t:ty ident) => {};    //~ERROR `$t:ty` is followed by `ident`
-   |            ^^^^^
+   |            ^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:66:12
    |
 LL |     ($t:ty if) => {};       //~ERROR `$t:ty` is followed by `if`
-   |            ^^
+   |            ^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:67:12
    |
 LL |     ($t:ty $p:pat) => {};   //~ERROR `$t:ty` is followed by `$p:pat`
-   |            ^^^^^^
+   |            ^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:68:12
    |
 LL |     ($t:ty $e:expr) => {};  //~ERROR `$t:ty` is followed by `$e:expr`
-   |            ^^^^^^^
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$t:ty`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:69:12
    |
 LL |     ($t:ty $t:ty) => {};    //~ERROR `$t:ty` is followed by `$t:ty`
-   |            ^^^^^
+   |            ^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:70:12
    |
 LL |     ($t:ty $s:stmt) => {};  //~ERROR `$t:ty` is followed by `$s:stmt`
-   |            ^^^^^^^
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:71:12
    |
 LL |     ($t:ty $p:path) => {};  //~ERROR `$t:ty` is followed by `$p:path`
-   |            ^^^^^^^
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:73:12
    |
 LL |     ($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident`
-   |            ^^^^^^^^
+   |            ^^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$t:tt`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:74:12
    |
 LL |     ($t:ty $t:tt) => {};    //~ERROR `$t:ty` is followed by `$t:tt`
-   |            ^^^^^
+   |            ^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:75:12
    |
 LL |     ($t:ty $i:item) => {};  //~ERROR `$t:ty` is followed by `$i:item`
-   |            ^^^^^^^
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments
   --> $DIR/macro-follow.rs:76:12
    |
 LL |     ($t:ty $m:meta) => {};  //~ERROR `$t:ty` is followed by `$m:meta`
-   |            ^^^^^^^
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:80:15
    |
 LL |     ($s:stmt ()) => {};       //~ERROR  `$s:stmt` is followed by `(`
-   |               ^
+   |               ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:81:15
    |
 LL |     ($s:stmt []) => {};       //~ERROR  `$s:stmt` is followed by `[`
-   |               ^
+   |               ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:82:15
    |
 LL |     ($s:stmt {}) => {};       //~ERROR  `$s:stmt` is followed by `{`
-   |               ^
+   |               ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:83:14
    |
 LL |     ($s:stmt =) => {};        //~ERROR `$s:stmt` is followed by `=`
-   |              ^
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:84:14
    |
 LL |     ($s:stmt |) => {};        //~ERROR `$s:stmt` is followed by `|`
-   |              ^
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:85:14
    |
 LL |     ($s:stmt :) => {};        //~ERROR `$s:stmt` is followed by `:`
-   |              ^
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:86:14
    |
 LL |     ($s:stmt >) => {};        //~ERROR `$s:stmt` is followed by `>`
-   |              ^
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:87:14
    |
 LL |     ($s:stmt +) => {};        //~ERROR `$s:stmt` is followed by `+`
-   |              ^
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:88:14
    |
 LL |     ($s:stmt ident) => {};    //~ERROR `$s:stmt` is followed by `ident`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:89:14
    |
 LL |     ($s:stmt if) => {};       //~ERROR `$s:stmt` is followed by `if`
-   |              ^^
+   |              ^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:90:14
    |
 LL |     ($s:stmt in) => {};       //~ERROR `$s:stmt` is followed by `in`
-   |              ^^
+   |              ^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:91:14
    |
 LL |     ($s:stmt $p:pat) => {};   //~ERROR `$s:stmt` is followed by `$p:pat`
-   |              ^^^^^^
+   |              ^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:92:14
    |
 LL |     ($s:stmt $e:expr) => {};  //~ERROR `$s:stmt` is followed by `$e:expr`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:93:14
    |
 LL |     ($s:stmt $t:ty) => {};    //~ERROR `$s:stmt` is followed by `$t:ty`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$s:stmt`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:94:14
    |
 LL |     ($s:stmt $s:stmt) => {};  //~ERROR `$s:stmt` is followed by `$s:stmt`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:95:14
    |
 LL |     ($s:stmt $p:path) => {};  //~ERROR `$s:stmt` is followed by `$p:path`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:96:14
    |
 LL |     ($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block`
-   |              ^^^^^^^^
+   |              ^^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:97:14
    |
 LL |     ($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident`
-   |              ^^^^^^^^
+   |              ^^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:98:14
    |
 LL |     ($s:stmt $t:tt) => {};    //~ERROR `$s:stmt` is followed by `$t:tt`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:99:14
    |
 LL |     ($s:stmt $i:item) => {};  //~ERROR `$s:stmt` is followed by `$i:item`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments
   --> $DIR/macro-follow.rs:100:14
    |
 LL |     ($s:stmt $m:meta) => {};  //~ERROR `$s:stmt` is followed by `$m:meta`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$p:path` is followed by `(`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:104:15
    |
 LL |     ($p:path ()) => {};       //~ERROR  `$p:path` is followed by `(`
-   |               ^
+   |               ^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `+`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:106:14
    |
 LL |     ($p:path +) => {};        //~ERROR `$p:path` is followed by `+`
-   |              ^
+   |              ^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:107:14
    |
 LL |     ($p:path ident) => {};    //~ERROR `$p:path` is followed by `ident`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `if`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:108:14
    |
 LL |     ($p:path if) => {};       //~ERROR `$p:path` is followed by `if`
-   |              ^^
+   |              ^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$p:pat`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:109:14
    |
 LL |     ($p:path $p:pat) => {};   //~ERROR `$p:path` is followed by `$p:pat`
-   |              ^^^^^^
+   |              ^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:110:14
    |
 LL |     ($p:path $e:expr) => {};  //~ERROR `$p:path` is followed by `$e:expr`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:111:14
    |
 LL |     ($p:path $t:ty) => {};    //~ERROR `$p:path` is followed by `$t:ty`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:112:14
    |
 LL |     ($p:path $s:stmt) => {};  //~ERROR `$p:path` is followed by `$s:stmt`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$p:path`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:113:14
    |
 LL |     ($p:path $p:path) => {};  //~ERROR `$p:path` is followed by `$p:path`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:115:14
    |
 LL |     ($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident`
-   |              ^^^^^^^^
+   |              ^^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:116:14
    |
 LL |     ($p:path $t:tt) => {};    //~ERROR `$p:path` is followed by `$t:tt`
-   |              ^^^^^
+   |              ^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:117:14
    |
 LL |     ($p:path $i:item) => {};  //~ERROR `$p:path` is followed by `$i:item`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments
   --> $DIR/macro-follow.rs:118:14
    |
 LL |     ($p:path $m:meta) => {};  //~ERROR `$p:path` is followed by `$m:meta`
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: aborting due to 85 previous errors
 
index bb070334d36e94471f89f02df59f9a0ebd13cc36..2ad8990e1156f85f33648d45c8eaf95f19a43ae0 100644 (file)
@@ -2,13 +2,17 @@ error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragmen
   --> $DIR/macro-followed-by-seq-bad.rs:17:15
    |
 LL |   ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments
-   |               ^^^^^
+   |               ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: `$a:ty` is followed by `$b:tt`, which is not allowed for `ty` fragments
   --> $DIR/macro-followed-by-seq-bad.rs:18:13
    |
 LL |   ( $a:ty $($b:tt)* ) => { };   //~ ERROR not allowed for `ty` fragments
-   |             ^^^^^
+   |             ^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/macros/macro-in-expression-context-2.rs b/src/test/ui/macros/macro-in-expression-context-2.rs
new file mode 100644 (file)
index 0000000..cf8572a
--- /dev/null
@@ -0,0 +1,7 @@
+macro_rules! empty { () => () }
+
+fn main() {
+    match 42 {
+        _ => { empty!() }
+    };
+}
diff --git a/src/test/ui/macros/macro-in-expression-context-2.stderr b/src/test/ui/macros/macro-in-expression-context-2.stderr
new file mode 100644 (file)
index 0000000..80d5dbd
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected expression, found `<eof>`
+  --> $DIR/macro-in-expression-context-2.rs:5:16
+   |
+LL |         _ => { empty!() }
+   |                ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/macro-in-expression-context.fixed b/src/test/ui/macros/macro-in-expression-context.fixed
new file mode 100644 (file)
index 0000000..df36db0
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+
+macro_rules! foo {
+    () => {
+        assert_eq!("A", "A");
+        assert_eq!("B", "B");
+    }
+    //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+    //~| NOTE the usage of `foo!` is likely invalid in expression context
+}
+
+fn main() {
+    foo!();
+    //~^ NOTE caused by the macro expansion here
+}
diff --git a/src/test/ui/macros/macro-in-expression-context.rs b/src/test/ui/macros/macro-in-expression-context.rs
new file mode 100644 (file)
index 0000000..b3f5e56
--- /dev/null
@@ -0,0 +1,15 @@
+// run-rustfix
+
+macro_rules! foo {
+    () => {
+        assert_eq!("A", "A");
+        assert_eq!("B", "B");
+    }
+    //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+    //~| NOTE the usage of `foo!` is likely invalid in expression context
+}
+
+fn main() {
+    foo!()
+    //~^ NOTE caused by the macro expansion here
+}
diff --git a/src/test/ui/macros/macro-in-expression-context.stderr b/src/test/ui/macros/macro-in-expression-context.stderr
new file mode 100644 (file)
index 0000000..d27d6fb
--- /dev/null
@@ -0,0 +1,15 @@
+error: macro expansion ignores token `assert_eq` and any following
+  --> $DIR/macro-in-expression-context.rs:6:9
+   |
+LL |         assert_eq!("B", "B");
+   |         ^^^^^^^^^
+...
+LL |     foo!()
+   |     ------- help: you might be missing a semicolon here: `;`
+   |     |
+   |     caused by the macro expansion here
+   |
+   = note: the usage of `foo!` is likely invalid in expression context
+
+error: aborting due to previous error
+
index aed7a8a119ced21ef2bd411578de79d618f05ec1..4bb46e39562cbf3207e9d25f1ef11c72a1bbda5d 100644 (file)
@@ -2,55 +2,73 @@ error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments
   --> $DIR/macro-input-future-proofing.rs:14:13
    |
 LL |     ($ty:ty <) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty`
-   |             ^
+   |             ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments
   --> $DIR/macro-input-future-proofing.rs:15:13
    |
 LL |     ($ty:ty < foo ,) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty`
-   |             ^
+   |             ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$pa:pat` is followed by `>`, which is not allowed for `pat` fragments
   --> $DIR/macro-input-future-proofing.rs:21:14
    |
 LL |     ($pa:pat >) => (); //~ ERROR `$pa:pat` is followed by `>`, which is not allowed for `pat`
-   |              ^
+   |              ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragments
   --> $DIR/macro-input-future-proofing.rs:23:14
    |
 LL |     ($pa:pat $pb:pat $ty:ty ,) => ();
-   |              ^^^^^^^
+   |              ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragments
   --> $DIR/macro-input-future-proofing.rs:23:22
    |
 LL |     ($pa:pat $pb:pat $ty:ty ,) => ();
-   |                      ^^^^^^
+   |                      ^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
 
 error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments
   --> $DIR/macro-input-future-proofing.rs:26:17
    |
 LL |     ($($ty:ty)* -) => (); //~ ERROR `$ty:ty` is followed by `-`
-   |                 ^
+   |                 ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$b:ty` is followed by `-`, which is not allowed for `ty` fragments
   --> $DIR/macro-input-future-proofing.rs:27:23
    |
 LL |     ($($a:ty, $b:ty)* -) => (); //~ ERROR `$b:ty` is followed by `-`
-   |                       ^
+   |                       ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments
   --> $DIR/macro-input-future-proofing.rs:28:7
    |
 LL |     ($($ty:ty)-+) => (); //~ ERROR `$ty:ty` is followed by `-`, which is not allowed for `ty`
-   |       ^^^^^^^^
+   |       ^^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
 
 error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments
   --> $DIR/macro-input-future-proofing.rs:29:21
    |
 LL |     ( $($a:expr)* $($b:tt)* ) => { };
-   |                     ^^^^^
+   |                     ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: aborting due to 9 previous errors
 
index 93b7f481842ac6c7574596fb0c3f4f30d08234de..d526023d441b101cba73aa38247059532a8bc673 100644 (file)
@@ -1,8 +1,11 @@
 error: no rules expected the token `a`
   --> $DIR/macro-non-lifetime.rs:18:8
    |
+LL | macro_rules! m { ($x:lifetime) => { } }
+   | -------------- when calling this macro
+...
 LL |     m!(a);
-   |        ^
+   |        ^ no rules expected the token `a`
 
 error: aborting due to previous error
 
index 607d3e100aa25cb64993429a4b32eb3f99e50542..688b9dc2797d05032cf8415e625c0bb65b1f417e 100644 (file)
@@ -10,10 +10,6 @@ note: `std` could refer to the name imported here
 LL |     use m2::*; // glob-import user-defined `std`
    |         ^^^^^
 note: `std` could also refer to the name defined here
-  --> $DIR/macro-path-prelude-shadowing.rs:39:9
-   |
-LL |         std::panic!(); //~ ERROR `std` is ambiguous
-   |         ^^^
    = note: consider adding an explicit import of `std` to disambiguate
 
 error: aborting due to previous error
index 9d8de87e5bb7f154237d97be5c51e0bf5d91c7ca..1d6af44bd08a5237bda698064c91c29173b41121 100644 (file)
@@ -7,32 +7,44 @@ LL |     println!("{}" a);
 error: no rules expected the token `b`
   --> $DIR/missing-comma.rs:22:12
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a b);
-   |           -^
+   |           -^ no rules expected the token `b`
    |           |
    |           help: missing comma here
 
 error: no rules expected the token `e`
   --> $DIR/missing-comma.rs:24:21
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a, b, c, d e);
-   |                    -^
+   |                    -^ no rules expected the token `e`
    |                    |
    |                    help: missing comma here
 
 error: no rules expected the token `d`
   --> $DIR/missing-comma.rs:26:18
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a, b, c d, e);
-   |                 -^
+   |                 -^ no rules expected the token `d`
    |                 |
    |                 help: missing comma here
 
 error: no rules expected the token `d`
   --> $DIR/missing-comma.rs:28:18
    |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
 LL |     foo!(a, b, c d e);
-   |                  ^
+   |                  ^ no rules expected the token `d`
 
 error: aborting due to 5 previous errors
 
index bf2221d52a4920dbce37818a24f653cc120a0b1d..23853978d371bcfe83083e267768aa30fe5efeff 100644 (file)
@@ -2,7 +2,7 @@ error: no rules expected the token `enum E { }`
   --> $DIR/nonterminal-matching.rs:29:10
    |
 LL |     n!(a $nt_item b); //~ ERROR no rules expected the token `enum E { }`
-   |          ^^^^^^^^
+   |          ^^^^^^^^ no rules expected the token `enum E { }`
 ...
 LL | complex_nonterminal!(enum E {});
    | -------------------------------- in this macro invocation
index a9ffef8ef80907d596238b804b765e21639bb7e8..853eb5847c0cdfe543a68ea29bca50e7803fa598 100644 (file)
@@ -1,8 +1,11 @@
 error: no rules expected the token `bcd`
   --> $DIR/trace_faulty_macros.rs:17:26
    |
+LL | macro_rules! my_faulty_macro {
+   | ---------------------------- when calling this macro
+LL |     () => {
 LL |         my_faulty_macro!(bcd); //~ ERROR no rules
-   |                          ^^^
+   |                          ^^^ no rules expected the token `bcd`
 ...
 LL |     my_faulty_macro!();
    |     ------------------- in this macro invocation
index e3ae4c0dcbe5725afec62e49a7e3049e2920f2ba..186ecc54827208e0634c7edbbd6c3b02efa784de 100644 (file)
@@ -66,7 +66,7 @@ impl<F> R<F> { fn new(f: F) -> Self { R { w: 0, f } } }
 // It got pretty monotonous writing the same code over and over, and I
 // feared I would forget details. So I abstracted some desiderata into
 // macros. But I left the initialization code inline, because that's
-// where the errors for #54986 will be emited.
+// where the errors for #54986 will be emitted.
 
 macro_rules! use_fully {
     (struct $s:expr) => { {
index 87ec3e5df0b81b7b9ade8464a296934d28559158..0f8372e094d6adeed53f41f5878f6f1bef4c552a 100644 (file)
@@ -14,6 +14,7 @@
 
 impl Struct {
     fn bar(self: &mut Self) {
+        //~^ WARN function cannot return without recursing
         (&mut self).bar();
         //~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
     }
index c5b5218f173ac1634eb365698f88558c23c710fb..88c653effb405d7a6f50907a13517c24b537bcdb 100644 (file)
@@ -1,5 +1,17 @@
+warning: function cannot return without recursing
+  --> $DIR/issue-51191.rs:16:5
+   |
+LL |     fn bar(self: &mut Self) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |         //~^ WARN function cannot return without recursing
+LL |         (&mut self).bar();
+   |         ----------------- recursive call site
+   |
+   = note: #[warn(unconditional_recursion)] on by default
+   = help: a `loop` may express intention better if this is on purpose
+
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-51191.rs:17:9
+  --> $DIR/issue-51191.rs:18:9
    |
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^
@@ -8,7 +20,7 @@ LL |         (&mut self).bar();
    |         try removing `&mut` here
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-51191.rs:22:9
+  --> $DIR/issue-51191.rs:23:9
    |
 LL |     fn imm(self) {
    |            ---- help: consider changing this to be mutable: `mut self`
@@ -16,19 +28,19 @@ LL |         (&mut self).bar();
    |         ^^^^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-51191.rs:31:9
+  --> $DIR/issue-51191.rs:32:9
    |
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow data in a `&` reference as mutable
-  --> $DIR/issue-51191.rs:31:9
+  --> $DIR/issue-51191.rs:32:9
    |
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
-  --> $DIR/issue-51191.rs:37:9
+  --> $DIR/issue-51191.rs:38:9
    |
 LL |         (&mut self).bar();
    |         ^^^^^^^^^^^
index fff73c6d0fa9c360e975388b7d2abd9fb61563e9..eaa809d2b37069da325023851cbc788138b237aa 100644 (file)
@@ -1,5 +1,5 @@
 // rust-lang/rust#52059: Regardless of whether you are moving out of a
-// Drop type or just introducing an inadvertant alias via a borrow of
+// Drop type or just introducing an inadvertent alias via a borrow of
 // one of its fields, it is useful to be reminded of the significance
 // of the fact that the type implements Drop.
 
diff --git a/src/test/ui/nll/user-annotations/issue-55219.rs b/src/test/ui/nll/user-annotations/issue-55219.rs
new file mode 100644 (file)
index 0000000..7daa5a5
--- /dev/null
@@ -0,0 +1,20 @@
+// Regression test for #55219:
+//
+// The `Self::HASH_LEN` here expands to a "self-type" where `T` is not
+// known. This unbound inference variable was causing an ICE.
+//
+// run-pass
+
+#![feature(nll)]
+
+pub struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    const HASH_LEN: usize = 20;
+
+    fn stuff() {
+        let _ = Self::HASH_LEN;
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/issue-55241.rs b/src/test/ui/nll/user-annotations/issue-55241.rs
new file mode 100644 (file)
index 0000000..e560080
--- /dev/null
@@ -0,0 +1,28 @@
+// Regression test for #55241:
+//
+// The reference to `C::HASHED_NULL_NODE` resulted in a type like `<C
+// as NodeCodec<_>>::Out`; normalizing this type requires knowing the
+// value of `_`; solving that requires having normalized, so we can
+// test against `C: NodeCodec<H>` in the environment.
+//
+// run-pass
+
+#![feature(nll)]
+
+pub trait Hasher {
+    type Out: Eq;
+}
+
+pub trait NodeCodec<H: Hasher> {
+    const HASHED_NULL_NODE: H::Out;
+}
+
+pub trait Trie<H: Hasher, C: NodeCodec<H>> {
+    /// Return the root of the trie.
+    fn root(&self) -> &H::Out;
+
+    /// Is the trie empty?
+    fn is_empty(&self) -> bool { *self.root() == C::HASHED_NULL_NODE }
+}
+
+fn main() { }
index a7fdd28b0cab89164a09c9f2a45a9ca48aac3c77..1e765dcde4f68b52a27572bf30ad992ef30dba65 100644 (file)
@@ -1,8 +1,11 @@
 error: no rules expected the token `!`
   --> $DIR/macro-doc-comments-1.rs:16:5
    |
+LL | macro_rules! outer {
+   | ------------------ when calling this macro
+...
 LL |     //! Inner
-   |     ^^^^^^^^^
+   |     ^^^^^^^^^ no rules expected the token `!`
 
 error: aborting due to previous error
 
index bae9823b9b2fa0e44d8c6c3a758b29ae966b5359..0ab8a3cafb55f63e1caeb07b80b6eae065fa87a4 100644 (file)
@@ -1,8 +1,11 @@
 error: no rules expected the token `[`
   --> $DIR/macro-doc-comments-2.rs:16:5
    |
+LL | macro_rules! inner {
+   | ------------------ when calling this macro
+...
 LL |     /// Outer
-   |     ^
+   |     ^ no rules expected the token `[`
 
 error: aborting due to previous error
 
index 198730dc07a99bc89e8d71c2b54ea60727064366..806aca511d0ae9483b79a6258421b903a65b85f7 100644 (file)
@@ -3,12 +3,11 @@ error: macro expansion ignores token `,` and any following
    |
 LL |         , //~ ERROR macro expansion ignores token `,`
    |         ^
-   |
-note: caused by the macro expansion here; the usage of `ignored_item!` is likely invalid in item context
-  --> $DIR/macro-incomplete-parse.rs:31:1
-   |
+...
 LL | ignored_item!();
-   | ^^^^^^^^^^^^^^^^
+   | ---------------- caused by the macro expansion here
+   |
+   = note: the usage of `ignored_item!` is likely invalid in item context
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
   --> $DIR/macro-incomplete-parse.rs:22:14
@@ -24,12 +23,11 @@ error: macro expansion ignores token `,` and any following
    |
 LL |     () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,`
    |              ^
-   |
-note: caused by the macro expansion here; the usage of `ignored_pat!` is likely invalid in pattern context
-  --> $DIR/macro-incomplete-parse.rs:36:9
-   |
+...
 LL |         ignored_pat!() => (),
-   |         ^^^^^^^^^^^^^^
+   |         -------------- caused by the macro expansion here
+   |
+   = note: the usage of `ignored_pat!` is likely invalid in pattern context
 
 error: aborting due to 3 previous errors
 
index f11cc77bbeaa12d871f7b3f957cbe8d1343262e6..f94da326883bd3f95081ab7a4dea1743e107e19d 100644 (file)
@@ -1,5 +1,17 @@
+warning: function cannot return without recursing
+  --> $DIR/region-bound-on-closure-outlives-call.rs:11:1
+   |
+LL | fn call_rec<F>(mut f: F) -> usize where F: FnMut(usize) -> usize {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |     //~^ WARN function cannot return without recursing
+LL |     (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
+   |                ----------- recursive call site
+   |
+   = note: #[warn(unconditional_recursion)] on by default
+   = help: a `loop` may express intention better if this is on purpose
+
 error[E0505]: cannot move out of `f` because it is borrowed
-  --> $DIR/region-bound-on-closure-outlives-call.rs:12:25
+  --> $DIR/region-bound-on-closure-outlives-call.rs:13:25
    |
 LL |     (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
    |     ----------          ^ move out of `f` occurs here
index b73c283fa515e3527f1a745893876a2d2f5d49be..f931e281c83fc54da1c97b608c5ae0da1322d9a8 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 fn call_rec<F>(mut f: F) -> usize where F: FnMut(usize) -> usize {
+    //~^ WARN function cannot return without recursing
     (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
 }
 
index 7adf68ee9b6d160a9af206ba2e0be3672e079798..6465f1ccf334581d931666084c26acd36ad4a9db 100644 (file)
@@ -1,5 +1,17 @@
+warning: function cannot return without recursing
+  --> $DIR/region-bound-on-closure-outlives-call.rs:11:1
+   |
+LL | fn call_rec<F>(mut f: F) -> usize where F: FnMut(usize) -> usize {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |     //~^ WARN function cannot return without recursing
+LL |     (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
+   |                ----------- recursive call site
+   |
+   = note: #[warn(unconditional_recursion)] on by default
+   = help: a `loop` may express intention better if this is on purpose
+
 error[E0505]: cannot move out of `f` because it is borrowed
-  --> $DIR/region-bound-on-closure-outlives-call.rs:12:25
+  --> $DIR/region-bound-on-closure-outlives-call.rs:13:25
    |
 LL |     (|x| f(x))(call_rec(f)) //~ ERROR cannot move out of `f`
    |      ---                ^ move out of `f` occurs here
index c6bd5b7fa0d2492554a924205a7db6f93cfde8fa..39f193c55f77aab8e43e336dfd95c196c2f96569 100644 (file)
@@ -12,21 +12,6 @@ LL |     let z: &'a & usize = &(&y);
 LL | }
    | - temporary value is freed at the end of this statement
 
-error[E0597]: `y` does not live long enough
-  --> $DIR/regions-free-region-ordering-caller1.rs:19:27
-   |
-LL | fn call1<'a>(x: &'a usize) {
-   |          -- lifetime `'a` defined here
-...
-LL |     let z: &'a & usize = &(&y);
-   |            -----------    ^^^^ borrowed value does not live long enough
-   |            |
-   |            type annotation requires that `y` is borrowed for `'a`
-...
-LL | }
-   | - `y` dropped here while still borrowed
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors occurred: E0597, E0716.
-For more information about an error, try `rustc --explain E0597`.
+For more information about this error, try `rustc --explain E0716`.
index e49374f9ce6493fe6213ce2fc554daffb4047f8a..55803e4034bf4b69d2aefded16cf82ecd4049092 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Test that we do some basic error correcton in the tokeniser (and don't ICE).
+// Test that we do some basic error correction in the tokeniser (and don't ICE).
 
 fn main() {
     if foo {
index 8881b965f9480207a2cc74b26e0f662b79c260b9..fd4bbde28660e5823dd1bcca012918a8651c19ab 100644 (file)
@@ -10,7 +10,7 @@
 
 // ignore-cloudabi no std::fs support
 
-// Test that we do some basic error correcton in the tokeniser (and don't spew
+// Test that we do some basic error correction in the tokeniser (and don't spew
 // too many bogus errors).
 
 pub mod raw {
index 39c664e270c4515c62d7e5953a917fd46d6932cb..099ead93beb0679b15b198d77d94d7e748f2fb8f 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Test that we do some basic error correcton in the tokeniser.
+// Test that we do some basic error correction in the tokeniser.
 
 fn main() {
     foo(bar(;
index 339d49104b021f266c3cebce5e4b4d4b4b35d42d..31a34a9e6fbbb528eb0d7a64138701d30c4236cb 100644 (file)
@@ -19,22 +19,22 @@ fn main() {
     use std::ops::Range;
 
     if let Range { start: _, end: _ } = true..true && false { }
-    //~^ ERROR ambigious use of `&&`
+    //~^ ERROR ambiguous use of `&&`
 
     if let Range { start: _, end: _ } = true..true || false { }
-    //~^ ERROR ambigious use of `||`
+    //~^ ERROR ambiguous use of `||`
 
     while let Range { start: _, end: _ } = true..true && false { }
-    //~^ ERROR ambigious use of `&&`
+    //~^ ERROR ambiguous use of `&&`
 
     while let Range { start: _, end: _ } = true..true || false { }
-    //~^ ERROR ambigious use of `||`
+    //~^ ERROR ambiguous use of `||`
 
     if let true = false && false { }
-    //~^ ERROR ambigious use of `&&`
+    //~^ ERROR ambiguous use of `&&`
 
     while let true = (1 == 2) && false { }
-    //~^ ERROR ambigious use of `&&`
+    //~^ ERROR ambiguous use of `&&`
 
     // The following cases are not an error as parenthesis are used to
     // clarify intent:
index 8597294913f2754fa92bb582bcff6e49522c6592..411cb99fbca19ae57c1f8c4bc635f9651095a684 100644 (file)
@@ -1,4 +1,4 @@
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
   --> $DIR/syntax-ambiguity-2015.rs:21:47
    |
 LL |     if let Range { start: _, end: _ } = true..true && false { }
@@ -7,7 +7,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `||`
+error: ambiguous use of `||`
   --> $DIR/syntax-ambiguity-2015.rs:24:47
    |
 LL |     if let Range { start: _, end: _ } = true..true || false { }
@@ -16,7 +16,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
   --> $DIR/syntax-ambiguity-2015.rs:27:50
    |
 LL |     while let Range { start: _, end: _ } = true..true && false { }
@@ -25,7 +25,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `||`
+error: ambiguous use of `||`
   --> $DIR/syntax-ambiguity-2015.rs:30:50
    |
 LL |     while let Range { start: _, end: _ } = true..true || false { }
@@ -34,7 +34,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
   --> $DIR/syntax-ambiguity-2015.rs:33:19
    |
 LL |     if let true = false && false { }
@@ -43,7 +43,7 @@ LL |     if let true = false && false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
   --> $DIR/syntax-ambiguity-2015.rs:36:22
    |
 LL |     while let true = (1 == 2) && false { }
index baa90bcf8e97102faca8042f9f09b30a485b580a..99495717c3a896d7213a03d1164a0d49a11f1392 100644 (file)
@@ -19,22 +19,22 @@ fn main() {
     use std::ops::Range;
 
     if let Range { start: _, end: _ } = true..true && false { }
-    //~^ ERROR ambigious use of `&&`
+    //~^ ERROR ambiguous use of `&&`
 
     if let Range { start: _, end: _ } = true..true || false { }
-    //~^ ERROR ambigious use of `||`
+    //~^ ERROR ambiguous use of `||`
 
     while let Range { start: _, end: _ } = true..true && false { }
-    //~^ ERROR ambigious use of `&&`
+    //~^ ERROR ambiguous use of `&&`
 
     while let Range { start: _, end: _ } = true..true || false { }
-    //~^ ERROR ambigious use of `||`
+    //~^ ERROR ambiguous use of `||`
 
     if let true = false && false { }
-    //~^ ERROR ambigious use of `&&`
+    //~^ ERROR ambiguous use of `&&`
 
     while let true = (1 == 2) && false { }
-    //~^ ERROR ambigious use of `&&`
+    //~^ ERROR ambiguous use of `&&`
 
     // The following cases are not an error as parenthesis are used to
     // clarify intent:
index 86ee04747b29dbc80bf75287831923f8ed314df3..bd49abeb7b247c3950bdbbc7a7d0fc3cdbdcc237 100644 (file)
@@ -1,4 +1,4 @@
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
   --> $DIR/syntax-ambiguity-2018.rs:21:47
    |
 LL |     if let Range { start: _, end: _ } = true..true && false { }
@@ -7,7 +7,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `||`
+error: ambiguous use of `||`
   --> $DIR/syntax-ambiguity-2018.rs:24:47
    |
 LL |     if let Range { start: _, end: _ } = true..true || false { }
@@ -16,7 +16,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
   --> $DIR/syntax-ambiguity-2018.rs:27:50
    |
 LL |     while let Range { start: _, end: _ } = true..true && false { }
@@ -25,7 +25,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `||`
+error: ambiguous use of `||`
   --> $DIR/syntax-ambiguity-2018.rs:30:50
    |
 LL |     while let Range { start: _, end: _ } = true..true || false { }
@@ -34,7 +34,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
   --> $DIR/syntax-ambiguity-2018.rs:33:19
    |
 LL |     if let true = false && false { }
@@ -43,7 +43,7 @@ LL |     if let true = false && false { }
    = note: this will be a error until the `let_chains` feature is stabilized
    = note: see rust-lang/rust#53668 for more information
 
-error: ambigious use of `&&`
+error: ambiguous use of `&&`
   --> $DIR/syntax-ambiguity-2018.rs:36:22
    |
 LL |     while let true = (1 == 2) && false { }
index d70c847e9fe6826d37837ad61664e284c9fecf1d..f13f8ef2bb4cf55edefa5354553ce872704eb4ed 100644 (file)
@@ -24,7 +24,7 @@ use std::fmt::{Debug, Display};
 // • one generic parameter (T) bound inline
 // • one parameter (T) with a where clause
 // • two parameters (T and U), both bound inline
-// • two paramters (T and U), one bound inline, one with a where clause
+// • two parameters (T and U), one bound inline, one with a where clause
 // • two parameters (T and U), both with where clauses
 //
 // —and for every permutation of 0, 1, or 2 lifetimes to outlive and 0 or 1
index 0e4436fe1632f7742458f8afdbcfa9b15fb3593b..f47b3fcb9be9a3dde601ae5bac30f6d3a7673f7d 100644 (file)
@@ -24,7 +24,7 @@
 // • one generic parameter (T) bound inline
 // • one parameter (T) with a where clause
 // • two parameters (T and U), both bound inline
-// • two paramters (T and U), one bound inline, one with a where clause
+// • two parameters (T and U), one bound inline, one with a where clause
 // • two parameters (T and U), both with where clauses
 //
 // —and for every permutation of 0, 1, or 2 lifetimes to outlive and 0 or 1
index 70cdb4899c421dea7515e3d5fba720356b5541cf..00d8d126e0573d6011e6259ebb72198066751952 100644 (file)
@@ -12,7 +12,7 @@
 
 // Regression test for #52050: when inserting the blanket impl `I`
 // into the tree, we had to replace the child node for `Foo`, which
-// led to the struture of the tree being messed up.
+// led to the structure of the tree being messed up.
 
 use std::iter::Iterator;
 
index 7f2b6ac30b0dae46ec14f42c6cb60ab14d9aa316..e148c48ed13142ce234ab5b8bce47fb142163d45 100644 (file)
@@ -1,8 +1,11 @@
 error: no rules expected the token `_`
   --> $DIR/underscore-ident-matcher.rs:18:19
    |
+LL | macro_rules! identity {
+   | --------------------- when calling this macro
+...
 LL |     let identity!(_) = 10; //~ ERROR no rules expected the token `_`
-   |                   ^
+   |                   ^ no rules expected the token `_`
 
 error: aborting due to previous error
 
index bccecd60e1c9e39f38d85466c6e408bc54a68996..e56d008d2665f9e6a06b442ea89839584d026569 100644 (file)
@@ -20,10 +20,9 @@ error[E0106]: missing lifetime specifier
   --> $DIR/underscore-lifetime-binders.rs:20:29
    |
 LL | fn meh() -> Box<for<'_> Meh<'_>> //~ ERROR cannot be used here
-   |                             ^^ expected lifetime parameter
+   |                             ^^ help: consider giving it a 'static lifetime: `'static`
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = help: consider giving it a 'static lifetime
 
 error[E0106]: missing lifetime specifier
   --> $DIR/underscore-lifetime-binders.rs:26:35
index 8efb191c7c645ad0b800b08e2c9abc078064c349..78362fcb05a8ca46732bc3ca666439a2523eeaf8 100644 (file)
@@ -2,7 +2,9 @@ error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments
   --> $DIR/unused-macro-with-follow-violation.rs:14:14
    |
 LL |     ($e:expr +) => () //~ ERROR not allowed for `expr` fragments
-   |              ^
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
 
 error: aborting due to previous error
 
index f5341ccc312861062f918cd70dc20f215059f788..856d85ef5cdaac6deb269675d2c86b45fa88f46d 100644 (file)
@@ -2,7 +2,7 @@ error: no rules expected the token `,`
   --> $DIR/vec-macro-with-comma-only.rs:12:10
    |
 LL |     vec![,]; //~ ERROR no rules expected the token `,`
-   |          ^
+   |          ^ no rules expected the token `,`
 
 error: aborting due to previous error
 
index 5afdf8b78507ddf015d192858aef56e72c17de16..b1d0343749bdc87e5cbbe7f1aeaa9d2a2c9dbc5b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 5afdf8b78507ddf015d192858aef56e72c17de16
+Subproject commit b1d0343749bdc87e5cbbe7f1aeaa9d2a2c9dbc5b
index 69a4c09c2285dc759b2f38e93a9ad0b79a689893..3d5e18e37b070c1aeaa93a693639bbf4bce68cf9 100644 (file)
@@ -163,7 +163,7 @@ fn check_cfgs(contents: &mut String, file: &Path,
 
 fn find_test_mod(contents: &str) -> usize {
     if let Some(mod_tests_idx) = contents.find("mod tests") {
-        // Also capture a previos line indicating "mod tests" in cfg-ed out
+        // Also capture a previous line indicating "mod tests" in cfg-ed out
         let prev_newline_idx = contents[..mod_tests_idx].rfind('\n').unwrap_or(mod_tests_idx);
         let prev_newline_idx = contents[..prev_newline_idx].rfind('\n');
         if let Some(nl) = prev_newline_idx {