]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #96144 - c410-f3r:z-errors, r=petrochenkov
authorbors <bors@rust-lang.org>
Fri, 22 Apr 2022 05:15:47 +0000 (05:15 +0000)
committerbors <bors@rust-lang.org>
Fri, 22 Apr 2022 05:15:47 +0000 (05:15 +0000)
Move some tests to more reasonable places

cc #73494
r? `@petrochenkov`

354 files changed:
Cargo.lock
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/attr/mod.rs
compiler/rustc_ast/src/tokenstream.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_lowering/src/path.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_borrowck/src/constraints/graph.rs
compiler/rustc_borrowck/src/constraints/mod.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/region_infer/dump_mir.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/input_output.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/type_check/relate_tys.rs
compiler/rustc_codegen_gcc/src/asm.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/symbol_export.rs
compiler/rustc_const_eval/src/const_eval/mod.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/memory.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/json.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/definitions.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/hir_id.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/equate.rs
compiler/rustc_lint/Cargo.toml
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_macros/src/session_diagnostic.rs
compiler/rustc_metadata/src/creader.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_metadata/src/rmeta/table.rs
compiler/rustc_middle/src/dep_graph/dep_node.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/interpret/allocation.rs
compiler/rustc_middle/src/mir/interpret/pointer.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_monomorphize/src/partitioning/default.rs
compiler/rustc_parse/src/parser/attr_wrapper.rs
compiler/rustc_parse/src/parser/mod.rs
compiler/rustc_parse/src/parser/nonterminal.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_passes/src/hir_id_validator.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_query_impl/src/profiling_support.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/def_collector.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/ident.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/search_paths.rs
compiler/rustc_session/src/utils.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/asm/mod.rs
compiler/rustc_target/src/asm/x86.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_typeck/src/astconv/errors.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/errors.rs
compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
config.toml.example
library/alloc/src/macros.rs
library/core/src/intrinsics.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/ptr/non_null.rs
library/core/src/slice/iter.rs
library/core/tests/hash/sip.rs
library/core/tests/lib.rs
library/core/tests/slice.rs
library/proc_macro/Cargo.toml
library/std/src/net/parser.rs
library/std/src/sys/hermit/mutex.rs
library/std/src/sys/itron/mutex.rs
library/std/src/sys/sgx/mutex.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/futex.rs
library/std/src/sys/unix/locks/futex.rs
library/std/src/sys/unix/locks/mod.rs
library/std/src/sys/unix/locks/pthread_remutex.rs [deleted file]
library/std/src/sys/unix/os.rs
library/std/src/sys/unix/process/process_common/tests.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/weak.rs
library/std/src/sys/unsupported/locks/mod.rs
library/std/src/sys/unsupported/locks/mutex.rs
library/std/src/sys/wasm/atomics/condvar.rs [deleted file]
library/std/src/sys/wasm/atomics/futex.rs
library/std/src/sys/wasm/atomics/mutex.rs [deleted file]
library/std/src/sys/wasm/atomics/rwlock.rs [deleted file]
library/std/src/sys/wasm/atomics/thread.rs
library/std/src/sys/wasm/mod.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/locks/mod.rs
library/std/src/sys/windows/locks/mutex.rs
library/std/src/sys_common/remutex.rs
library/std/src/thread/local.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/cc_detect.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/flags.rs
src/bootstrap/install.rs
src/bootstrap/native.rs
src/bootstrap/test.rs
src/bootstrap/toolstate.rs
src/doc/book
src/doc/embedded-book
src/doc/nomicon
src/doc/reference
src/doc/rust-by-example
src/doc/rustc-dev-guide
src/doc/unstable-book/src/compiler-flags/extern-location.md [deleted file]
src/etc/htmldocck.py
src/librustdoc/Cargo.toml
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/types/tests.rs [new file with mode: 0644]
src/librustdoc/core.rs
src/librustdoc/doctest.rs
src/librustdoc/formats/cache.rs
src/librustdoc/formats/mod.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/static/js/externs.js
src/librustdoc/html/static/js/search.js
src/librustdoc/json/conversions.rs
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/mod.rs
src/librustdoc/passes/unindent_comments.rs [deleted file]
src/librustdoc/passes/unindent_comments/tests.rs [deleted file]
src/librustdoc/visit_lib.rs
src/llvm-project
src/test/codegen/asm-clobber_abi.rs
src/test/codegen/set-discriminant-invalid.rs
src/test/codegen/vec-in-place.rs
src/test/mir-opt/inline/inline_diverging.h.Inline.diff
src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
src/test/mir-opt/storage_ranges.main.nll.0.mir
src/test/rustdoc-js-std/filter-crate.js
src/test/rustdoc-js-std/parser-errors.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-filter.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-generics.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-literal.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-paths.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-quote.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-returned.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-separators.js [new file with mode: 0644]
src/test/rustdoc-js-std/parser-weird-queries.js [new file with mode: 0644]
src/test/rustdoc-js-std/quoted.js
src/test/rustdoc-js-std/struct-vec.js
src/test/rustdoc-js-std/typed-query.js
src/test/rustdoc-js-std/vec-new.js
src/test/rustdoc-js/doc-alias-filter.js
src/test/rustdoc-js/doc-alias.js
src/test/rustdoc-js/generics.js
src/test/rustdoc-js/generics.rs
src/test/rustdoc-ui/intra-doc/email-address-localhost.rs
src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr [deleted file]
src/test/rustdoc-ui/issue-91713.stdout
src/test/rustdoc/duplicated_impl.rs [new file with mode: 0644]
src/test/rustdoc/early-unindent.rs [new file with mode: 0644]
src/test/rustdoc/where.SWhere_Simd_item-decl.html [new file with mode: 0644]
src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html [new file with mode: 0644]
src/test/rustdoc/where.rs
src/test/ui/asm/x86_64/bad-reg.rs
src/test/ui/asm/x86_64/bad-reg.stderr
src/test/ui/async-await/async-fn-path-elision.stderr
src/test/ui/async-await/issues/issue-67893.rs
src/test/ui/async-await/issues/issue-67893.stderr
src/test/ui/const-generics/issues/issue-87493.stderr
src/test/ui/consts/const-eval/ub-enum.32bit.stderr
src/test/ui/consts/const-eval/ub-enum.64bit.stderr
src/test/ui/consts/const-eval/ub-enum.rs
src/test/ui/consts/const-eval/validate_uninhabited_zsts.32bit.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.64bit.stderr
src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
src/test/ui/error-codes/E0107.rs
src/test/ui/error-codes/E0107.stderr
src/test/ui/generator/issue-93161.rs
src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr
src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr
src/test/ui/generic-associated-types/issue-67510.rs
src/test/ui/generic-associated-types/issue-67510.stderr
src/test/ui/generic-associated-types/issue-70304.rs
src/test/ui/generic-associated-types/issue-70304.stderr
src/test/ui/generics/generic-extern-lifetime.stderr
src/test/ui/impl-header-lifetime-elision/path-elided.stderr
src/test/ui/impl-header-lifetime-elision/trait-elided.rs
src/test/ui/impl-header-lifetime-elision/trait-elided.stderr
src/test/ui/issues/issue-10412.rs
src/test/ui/issues/issue-10412.stderr
src/test/ui/lifetimes/issue-91763.stderr
src/test/ui/lifetimes/undeclared-lifetime-used-in-debug-macro-issue-70152.stderr
src/test/ui/lint/force-warn/allowed-by-default-lint.stderr
src/test/ui/lint/reasons.rs
src/test/ui/lint/reasons.stderr
src/test/ui/methods/method-call-lifetime-args-unresolved.rs
src/test/ui/methods/method-call-lifetime-args-unresolved.stderr
src/test/ui/regions/regions-name-static.rs
src/test/ui/regions/regions-name-undeclared.rs
src/test/ui/regions/regions-name-undeclared.stderr
src/test/ui/rfc1623.base.stderr
src/test/ui/rfc1623.nll.stderr
src/test/ui/rfc1623.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.base.stderr [new file with mode: 0644]
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr [deleted file]
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.base.stderr [new file with mode: 0644]
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr [deleted file]
src/test/ui/self/elision/lt-ref-self-async.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/lt-ref-self-async.nll.stderr
src/test/ui/self/elision/lt-ref-self-async.rs
src/test/ui/self/elision/lt-ref-self-async.stderr [deleted file]
src/test/ui/self/elision/lt-ref-self.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/lt-ref-self.nll.stderr
src/test/ui/self/elision/lt-ref-self.rs
src/test/ui/self/elision/lt-ref-self.stderr [deleted file]
src/test/ui/self/elision/ref-mut-self-async.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/ref-mut-self-async.nll.stderr
src/test/ui/self/elision/ref-mut-self-async.rs
src/test/ui/self/elision/ref-mut-self-async.stderr [deleted file]
src/test/ui/self/elision/ref-mut-self.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/ref-mut-self.nll.stderr
src/test/ui/self/elision/ref-mut-self.rs
src/test/ui/self/elision/ref-mut-self.stderr [deleted file]
src/test/ui/self/elision/ref-mut-struct-async.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/ref-mut-struct-async.nll.stderr
src/test/ui/self/elision/ref-mut-struct-async.rs
src/test/ui/self/elision/ref-mut-struct-async.stderr [deleted file]
src/test/ui/self/elision/ref-mut-struct.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/ref-mut-struct.nll.stderr
src/test/ui/self/elision/ref-mut-struct.rs
src/test/ui/self/elision/ref-mut-struct.stderr [deleted file]
src/test/ui/self/elision/ref-self-async.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/ref-self-async.nll.stderr
src/test/ui/self/elision/ref-self-async.rs
src/test/ui/self/elision/ref-self-async.stderr [deleted file]
src/test/ui/self/elision/ref-self.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/ref-self.nll.stderr
src/test/ui/self/elision/ref-self.rs
src/test/ui/self/elision/ref-self.stderr [deleted file]
src/test/ui/self/elision/ref-struct-async.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/ref-struct-async.nll.stderr
src/test/ui/self/elision/ref-struct-async.rs
src/test/ui/self/elision/ref-struct-async.stderr [deleted file]
src/test/ui/self/elision/ref-struct.base.stderr [new file with mode: 0644]
src/test/ui/self/elision/ref-struct.nll.stderr
src/test/ui/self/elision/ref-struct.rs
src/test/ui/self/elision/ref-struct.stderr [deleted file]
src/test/ui/statics/uninhabited-static.rs
src/test/ui/statics/uninhabited-static.stderr
src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr [new file with mode: 0644]
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs [new file with mode: 0644]
src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr [new file with mode: 0644]
src/test/ui/suggestions/use-type-argument-instead-of-assoc-type.stderr
src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
src/test/ui/underscore-lifetime/in-binder.rs
src/test/ui/uninhabited/privately-uninhabited-mir-call.rs [new file with mode: 0644]
src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr [new file with mode: 0644]
src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr
src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr
src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-defl-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw-json.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw.rs [deleted file]
src/test/ui/unused-crate-deps/extern-loc-raw.stderr [deleted file]
src/test/ui/unused-crate-deps/libfib.stderr
src/test/ui/unused-crate-deps/unused-aliases.stderr
src/test/ui/unused-crate-deps/warn-attr.stderr
src/test/ui/unused-crate-deps/warn-cmdline-static.stderr
src/test/ui/unused-crate-deps/warn-cmdline.stderr
src/test/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
src/test/ui/where-clauses/where-lifetime-resolution.stderr
src/tools/cargo
src/tools/clippy/clippy_lints/src/missing_doc.rs
src/tools/clippy/tests/ui/unused_unit.stderr
src/tools/miri
src/tools/rustdoc-js/tester.js
src/tools/rustfmt/src/items.rs
src/tools/rustfmt/src/visitor.rs
src/tools/tidy/src/deps.rs

index 73dc7f03236d173a520edb358d0e3df736c388d2..30175ae3561ab7b3ff6b9630855f1bc3b2e0759a 100644 (file)
@@ -337,6 +337,7 @@ dependencies = [
  "humantime 2.0.1",
  "ignore",
  "im-rc",
+ "indexmap",
  "itertools",
  "jobserver",
  "lazy_static",
@@ -358,6 +359,7 @@ dependencies = [
  "serde_ignored",
  "serde_json",
  "shell-escape",
+ "snapbox",
  "strip-ansi-escapes",
  "tar",
  "tempfile",
@@ -794,6 +796,32 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "concolor"
+version = "0.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af"
+dependencies = [
+ "atty",
+ "bitflags",
+ "concolor-query",
+]
+
+[[package]]
+name = "concolor-query"
+version = "0.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449"
+
+[[package]]
+name = "content_inspector"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "core"
 version = "0.0.0"
@@ -1088,6 +1116,12 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "dunce"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
+
 [[package]]
 name = "either"
 version = "1.6.0"
@@ -2417,6 +2451,12 @@ dependencies = [
  "version_check",
 ]
 
+[[package]]
+name = "normalize-line-endings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
+
 [[package]]
 name = "ntapi"
 version = "0.3.6"
@@ -2491,9 +2531,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.7.2"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
 
 [[package]]
 name = "opaque-debug"
@@ -2513,9 +2553,9 @@ dependencies = [
 
 [[package]]
 name = "openssl"
-version = "0.10.35"
+version = "0.10.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885"
+checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
 dependencies = [
  "bitflags",
  "cfg-if 1.0.0",
@@ -2542,9 +2582,9 @@ dependencies = [
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.65"
+version = "0.9.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d"
+checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
 dependencies = [
  "autocfg",
  "cc",
@@ -2894,6 +2934,7 @@ dependencies = [
 name = "proc_macro"
 version = "0.0.0"
 dependencies = [
+ "core",
  "std",
 ]
 
@@ -3934,7 +3975,6 @@ dependencies = [
  "rustc_infer",
  "rustc_middle",
  "rustc_parse_format",
- "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -4496,6 +4536,7 @@ dependencies = [
  "expect-test",
  "itertools",
  "minifier",
+ "once_cell",
  "pulldown-cmark",
  "rayon",
  "regex",
@@ -4790,6 +4831,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "similar"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
+
 [[package]]
 name = "siphasher"
 version = "0.3.3"
@@ -4824,6 +4871,30 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"
 
+[[package]]
+name = "snapbox"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1f212b806d6f56d19838e36a0aaa7e79a0bc9ca177e873fb87651ad92f983e2"
+dependencies = [
+ "concolor",
+ "content_inspector",
+ "dunce",
+ "filetime",
+ "normalize-line-endings",
+ "similar",
+ "snapbox-macros",
+ "tempfile",
+ "walkdir",
+ "yansi",
+]
+
+[[package]]
+name = "snapbox-macros"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c01dea7e04cbb27ef4c86e9922184608185f7cd95c1763bc30d727cda4a5e930"
+
 [[package]]
 name = "socket2"
 version = "0.4.1"
@@ -5668,9 +5739,9 @@ dependencies = [
 
 [[package]]
 name = "walkdir"
-version = "2.3.1"
+version = "2.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
 dependencies = [
  "same-file",
  "winapi",
@@ -5781,6 +5852,12 @@ dependencies = [
  "linked-hash-map",
 ]
 
+[[package]]
+name = "yansi"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+
 [[package]]
 name = "yansi-term"
 version = "0.1.2"
index 714f9383bb2100fee13f16ce64a0957f3300e29c..b7da276fc7e1dc431acd53a999524e3d4e05bb06 100644 (file)
@@ -107,11 +107,11 @@ fn eq(&self, symbol: &Symbol) -> bool {
     }
 }
 
-impl<CTX> HashStable<CTX> for Path {
+impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         self.segments.len().hash_stable(hcx, hasher);
         for segment in &self.segments {
-            segment.ident.name.hash_stable(hcx, hasher);
+            segment.ident.hash_stable(hcx, hasher);
         }
     }
 }
index 80caf37d7099d67ddea64e0912cc44be3099483e..9a6d12faa605d62bcdf7540aeb1adf28a9dbb8b1 100644 (file)
@@ -9,6 +9,7 @@
 use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
 use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing};
 use crate::tokenstream::{LazyTokenStream, TokenStream};
+use crate::util::comments;
 
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::source_map::BytePos;
@@ -262,6 +263,10 @@ pub fn doc_str(&self) -> Option<Symbol> {
         }
     }
 
+    pub fn may_have_doc_links(&self) -> bool {
+        self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
+    }
+
     pub fn get_normal_item(&self) -> &AttrItem {
         match self.kind {
             AttrKind::Normal(ref item, _) => item,
index affb4289cb1b5a4f229a79cdaba90b1d7008f7c3..d609fa6720502c5ca1b679ad2cd0b0c99c813be7 100644 (file)
@@ -94,16 +94,6 @@ pub fn token(kind: TokenKind, span: Span) -> TokenTree {
         TokenTree::Token(Token::new(kind, span))
     }
 
-    /// Returns the opening delimiter as a token tree.
-    pub fn open_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
-        TokenTree::token(token::OpenDelim(delim), span.open)
-    }
-
-    /// Returns the closing delimiter as a token tree.
-    pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
-        TokenTree::token(token::CloseDelim(delim), span.close)
-    }
-
     pub fn uninterpolate(self) -> TokenTree {
         match self {
             TokenTree::Token(token) => TokenTree::Token(token.uninterpolate().into_owned()),
@@ -585,13 +575,20 @@ fn new(stream: TokenStream) -> Self {
         Cursor { stream, index: 0 }
     }
 
+    #[inline]
     pub fn next_with_spacing(&mut self) -> Option<TreeAndSpacing> {
-        if self.index < self.stream.len() {
+        self.stream.0.get(self.index).map(|tree| {
             self.index += 1;
-            Some(self.stream.0[self.index - 1].clone())
-        } else {
-            None
-        }
+            tree.clone()
+        })
+    }
+
+    #[inline]
+    pub fn next_with_spacing_ref(&mut self) -> Option<&TreeAndSpacing> {
+        self.stream.0.get(self.index).map(|tree| {
+            self.index += 1;
+            tree
+        })
     }
 
     pub fn index(&self) -> usize {
index 8730aeb0f3bffdf182cef918a75c06a4a44bd391..b4fff0022e29547e2cd17c2994ac09f528258456 100644 (file)
@@ -24,6 +24,14 @@ pub struct Comment {
     pub pos: BytePos,
 }
 
+/// A fast conservative estimate on whether the string can contain documentation links.
+/// A pair of square brackets `[]` must exist in the string, but we only search for the
+/// opening bracket because brackets always go in pairs in practice.
+#[inline]
+pub fn may_have_doc_links(s: &str) -> bool {
+    s.contains('[')
+}
+
 /// Makes a doc string more presentable to users.
 /// Used by rustdoc and perhaps other tools, but not by rustc.
 pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
index 3183612597d137e68d7faee5730fc3db274cf04b..d925c6dd3549aa5da8b01d7a80858bd1dccaf8d1 100644 (file)
@@ -35,7 +35,7 @@ pub enum FnCtxt {
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
+    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
 
     /// E.g., `|x, y| body`.
     Closure(&'a FnDecl, &'a Expr),
@@ -44,7 +44,7 @@ pub enum FnKind<'a> {
 impl<'a> FnKind<'a> {
     pub fn header(&self) -> Option<&'a FnHeader> {
         match *self {
-            FnKind::Fn(_, _, sig, _, _) => Some(&sig.header),
+            FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
             FnKind::Closure(_, _) => None,
         }
     }
@@ -58,7 +58,7 @@ pub fn ident(&self) -> Option<&Ident> {
 
     pub fn decl(&self) -> &'a FnDecl {
         match self {
-            FnKind::Fn(_, _, sig, _, _) => &sig.decl,
+            FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
             FnKind::Closure(decl, _) => decl,
         }
     }
@@ -295,8 +295,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             walk_list!(visitor, visit_expr, expr);
         }
         ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
-            visitor.visit_generics(generics);
-            let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+            let kind =
+                FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
             visitor.visit_fn(kind, item.span, item.id)
         }
         ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind {
@@ -561,8 +561,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
             walk_list!(visitor, visit_expr, expr);
         }
         ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
-            visitor.visit_generics(generics);
-            let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
+            let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body.as_deref());
             visitor.visit_fn(kind, span, id);
         }
         ForeignItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
@@ -644,7 +643,8 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &
 
 pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
     match kind {
-        FnKind::Fn(_, _, sig, _, body) => {
+        FnKind::Fn(_, _, sig, _, generics, body) => {
+            visitor.visit_generics(generics);
             visitor.visit_fn_header(&sig.header);
             walk_fn_decl(visitor, &sig.decl);
             walk_list!(visitor, visit_block, body);
@@ -667,8 +667,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
             walk_list!(visitor, visit_expr, expr);
         }
         AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
-            visitor.visit_generics(generics);
-            let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
+            let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body.as_deref());
             visitor.visit_fn(kind, span, id);
         }
         AssocItemKind::TyAlias(box TyAlias { generics, bounds, ty, .. }) => {
index e7e82e651bb09ae0f7dd5518eb76d9530ed46cea..9cb205074e7eaf6b9a81413042c3127e991a14bd 100644 (file)
@@ -484,7 +484,7 @@ enum ParenthesizedGenericArgs {
 /// an "elided" or "underscore" lifetime name. In the future, we probably want to move
 /// everything into HIR lowering.
 #[derive(Copy, Clone, Debug)]
-enum AnonymousLifetimeMode {
+pub enum AnonymousLifetimeMode {
     /// For **Modern** cases, create a new anonymous region parameter
     /// and reference that.
     ///
@@ -1835,7 +1835,7 @@ fn lower_async_fn_ret_ty(
             // Output lifetime like `'_`:
             for (span, node_id) in lifetimes_to_define {
                 let param = this.fresh_lifetime_to_generic_param(span, node_id);
-                lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
+                lifetime_params.push((span, hir::LifetimeName::Implicit));
                 generic_params.push(param);
             }
             let generic_params = this.arena.alloc_from_iter(generic_params);
@@ -2017,16 +2017,16 @@ fn lower_generic_param(
                     });
                 let param_name = match lt.name {
                     hir::LifetimeName::Param(param_name) => param_name,
-                    hir::LifetimeName::Implicit(_)
-                    | hir::LifetimeName::Underscore
-                    | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()),
+                    hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+                        hir::ParamName::Plain(lt.name.ident())
+                    }
                     hir::LifetimeName::ImplicitObjectLifetimeDefault => {
                         self.sess.diagnostic().span_bug(
                             param.ident.span,
                             "object-lifetime-default should not occur here",
                         );
                     }
-                    hir::LifetimeName::Error => ParamName::Error,
+                    hir::LifetimeName::Static | hir::LifetimeName::Error => ParamName::Error,
                 };
 
                 let kind =
@@ -2397,27 +2397,14 @@ fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime {
 
             AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
 
-            AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span, false),
+            AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
         }
     }
 
     /// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
     /// return an "error lifetime".
     fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
-        let (id, msg, label) = match id {
-            Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
-
-            None => (
-                self.resolver.next_node_id(),
-                "`&` without an explicit lifetime name cannot be used here",
-                "explicit lifetime name needed here",
-            ),
-        };
-
-        let mut err = struct_span_err!(self.sess, span, E0637, "{}", msg,);
-        err.span_label(span, label);
-        err.emit();
-
+        let id = id.unwrap_or_else(|| self.resolver.next_node_id());
         self.new_named_lifetime(id, span, hir::LifetimeName::Error)
     }
 
@@ -2429,12 +2416,11 @@ fn elided_path_lifetimes<'s>(
         &'s mut self,
         span: Span,
         count: usize,
-        param_mode: ParamMode,
     ) -> impl Iterator<Item = hir::Lifetime> + Captures<'a> + Captures<'s> + Captures<'hir> {
-        (0..count).map(move |_| self.elided_path_lifetime(span, param_mode))
+        (0..count).map(move |_| self.elided_path_lifetime(span))
     }
 
-    fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Lifetime {
+    fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
         match self.anonymous_lifetime_mode {
             AnonymousLifetimeMode::CreateParameter => {
                 // We should have emitted E0726 when processing this path above
@@ -2450,7 +2436,7 @@ fn elided_path_lifetime(&mut self, span: Span, param_mode: ParamMode) -> hir::Li
             // lifetime. Instead, we simply create an implicit lifetime, which will be checked
             // later, at which point a suitable error will be emitted.
             AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
-                self.new_implicit_lifetime(span, param_mode == ParamMode::Explicit)
+                self.new_implicit_lifetime(span)
             }
         }
     }
@@ -2493,11 +2479,11 @@ fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
         r
     }
 
-    fn new_implicit_lifetime(&mut self, span: Span, missing: bool) -> hir::Lifetime {
+    fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
         hir::Lifetime {
             hir_id: self.next_id(),
             span: self.lower_span(span),
-            name: hir::LifetimeName::Implicit(missing),
+            name: hir::LifetimeName::Implicit,
         }
     }
 }
@@ -2600,7 +2586,7 @@ fn visit_generic_param(&mut self, param: &'v hir::GenericParam<'v>) {
 
         fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
             let name = match lifetime.name {
-                hir::LifetimeName::Implicit(_) | hir::LifetimeName::Underscore => {
+                hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
                     if self.collect_elided_lifetimes {
                         // Use `'_` for both implicit and underscore lifetimes in
                         // `type Foo<'_> = impl SomeTrait<'_>;`.
index b35e3a071619af307dfa7df01533a02d6c2487dd..8bf4b8fcc3975347c926a41373d56f359fb65b97 100644 (file)
@@ -290,47 +290,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
             };
             generic_args.args = self
-                .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes, param_mode)
+                .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes)
                 .map(GenericArg::Lifetime)
                 .chain(generic_args.args.into_iter())
                 .collect();
-            // In create-parameter mode we error here because we don't want to support
-            // deprecated impl elision in new features like impl elision and `async fn`,
-            // both of which work using the `CreateParameter` mode:
-            //
-            //     impl Foo for std::cell::Ref<u32> // note lack of '_
-            //     async fn foo(_: std::cell::Ref<u32>) { ... }
             if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) =
                 (param_mode, self.anonymous_lifetime_mode)
             {
-                let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
-                let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
-                let no_bindings = generic_args.bindings.is_empty();
-                let (incl_angl_brckt, suggestion) = if no_non_lt_args && no_bindings {
-                    // If there are no generic args, our suggestion can include the angle brackets.
-                    (true, format!("<{}>", anon_lt_suggestion))
-                } else {
-                    // Otherwise we'll insert a `'_, ` right after the opening bracket.
-                    (false, format!("{}, ", anon_lt_suggestion))
-                };
-                let insertion_sp = elided_lifetime_span.shrink_to_hi();
-                let mut err = struct_span_err!(
-                    self.sess,
-                    path_span,
-                    E0726,
-                    "implicit elided lifetime not allowed here"
-                );
-                rustc_errors::add_elided_lifetime_in_path_suggestion(
-                    &self.sess.source_map(),
-                    &mut err,
-                    expected_lifetimes,
-                    path_span,
-                    incl_angl_brckt,
-                    insertion_sp,
-                    suggestion,
-                );
-                err.note("assuming a `'static` lifetime...");
-                err.emit();
+                // Late resolver should have issued the error.
+                self.sess
+                    .delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here");
             }
         }
 
index 33727084ccf064f5d291934cc5bf062bcd0825fa..8d815e95528825a269a56f88619e9102631d5cc4 100644 (file)
@@ -91,16 +91,18 @@ fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
         self.is_impl_trait_banned = old;
     }
 
-    fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_tilde_const_allowed, true);
+    fn with_tilde_const(&mut self, allowed: bool, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.is_tilde_const_allowed, allowed);
         f(self);
         self.is_tilde_const_allowed = old;
     }
 
+    fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
+        self.with_tilde_const(true, f)
+    }
+
     fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_tilde_const_allowed, false);
-        f(self);
-        self.is_tilde_const_allowed = old;
+        self.with_tilde_const(false, f)
     }
 
     fn with_let_management(
@@ -1202,12 +1204,8 @@ fn visit_item(&mut self, item: &'a Item) {
                 }
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
-                if let Const::Yes(_) = sig.header.constness {
-                    self.with_tilde_const_allowed(|this| this.visit_generics(generics));
-                } else {
-                    self.visit_generics(generics);
-                }
-                let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+                let kind =
+                    FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, generics, body.as_deref());
                 self.visit_fn(kind, item.span, item.id);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
@@ -1555,13 +1553,14 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
             FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
             _,
             _,
+            _,
         ) = fk
         {
             self.maybe_lint_missing_abi(*sig_span, id);
         }
 
         // Functions without bodies cannot have patterns.
-        if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
+        if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
             Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
                 let (code, msg, label) = match ctxt {
                     FnCtxt::Foreign => (
@@ -1596,7 +1595,11 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
             });
         }
 
-        visit::walk_fn(self, fk, span);
+        let tilde_const_allowed =
+            matches!(fk.header(), Some(FnHeader { constness: Const::Yes(_), .. }))
+                || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)));
+
+        self.with_tilde_const(tilde_const_allowed, |this| visit::walk_fn(this, fk, span));
     }
 
     fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
@@ -1670,9 +1673,14 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
             {
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
-                self.with_tilde_const_allowed(|this| this.visit_generics(generics));
-                let kind =
-                    FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
+                let kind = FnKind::Fn(
+                    FnCtxt::Assoc(ctxt),
+                    item.ident,
+                    sig,
+                    &item.vis,
+                    generics,
+                    body.as_deref(),
+                );
                 self.visit_fn(kind, item.span, item.id);
             }
             _ => self
index cb9e0234c49ffa5a5a7edc3e653817563f93ee5e..4ceca60e23cee736bcbaebfc71f050ef4fe978e9 100644 (file)
@@ -156,6 +156,7 @@ fn next(&mut self) -> Option<Self::Item> {
                 sup: self.static_region,
                 sub: next_static_idx.into(),
                 locations: Locations::All(DUMMY_SP),
+                span: DUMMY_SP,
                 category: ConstraintCategory::Internal,
                 variance_info: VarianceDiagInfo::default(),
             })
index d41143ee763ad835709be88e3966595533913df5..14f0e5f620aeeab90d15b10d259eb735b64e5eb2 100644 (file)
@@ -2,6 +2,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
+use rustc_span::Span;
 use std::fmt;
 use std::ops::Index;
 
@@ -87,6 +88,12 @@ pub struct OutlivesConstraint<'tcx> {
     /// Where did this constraint arise?
     pub locations: Locations,
 
+    /// The `Span` associated with the creation of this constraint.
+    /// This should be used in preference to obtaining the span from
+    /// `locations`, since the `locations` may give a poor span
+    /// in some cases (e.g. converting a constraint from a promoted).
+    pub span: Span,
+
     /// What caused this constraint?
     pub category: ConstraintCategory,
 
index 9e5fb674772d5f0d7c9c525c40dbe886c13e784e..5de6adcfc79eb82ca5396d9e5637f74be3d19eaf 100644 (file)
@@ -1484,7 +1484,7 @@ fn try_report_cannot_return_reference_to_local(
                         err.span_suggestion_hidden(
                             return_span,
                             "use `.collect()` to allocate the iterator",
-                            format!("{}{}", snippet, ".collect::<Vec<_>>()"),
+                            format!("{snippet}.collect::<Vec<_>>()"),
                             Applicability::MaybeIncorrect,
                         );
                     }
index 7742813888e535848e185b5404e6d85992aec197..459d4a783e40f06042bbd4f5660e5e35c53622a7 100644 (file)
@@ -575,7 +575,7 @@ fn match_adt_and_segment<'hir>(
                 Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
             }
 
-            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit(_) => {
+            hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
                 // In this case, the user left off the lifetime; so
                 // they wrote something like:
                 //
index 97233b930c395f839abe07d86a4b64640fc5ded7..fe5193102f958de004aa6b1fbcbd59fa9d00bfab 100644 (file)
@@ -74,14 +74,18 @@ fn for_each_constraint(
         let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
         constraints.sort_by_key(|c| (c.sup, c.sub));
         for constraint in &constraints {
-            let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
+            let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } =
+                constraint;
             let (name, arg) = match locations {
                 Locations::All(span) => {
                     ("All", tcx.sess.source_map().span_to_embeddable_string(*span))
                 }
                 Locations::Single(loc) => ("Single", format!("{:?}", loc)),
             };
-            with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?;
+            with_msg(&format!(
+                "{:?}: {:?} due to {:?} at {}({}) ({:?}",
+                sup, sub, category, name, arg, span
+            ))?;
         }
 
         Ok(())
index dabf61715ce58fb78bb4239dd40ab501932c061e..cf03f34a4ec5fbb03b2a76e6e8434ea49dbdc832 100644 (file)
@@ -1733,7 +1733,7 @@ fn check_member_constraints(
 
     crate fn retrieve_closure_constraint_info(
         &self,
-        body: &Body<'tcx>,
+        _body: &Body<'tcx>,
         constraint: &OutlivesConstraint<'tcx>,
     ) -> BlameConstraint<'tcx> {
         let loc = match constraint.locations {
@@ -1760,7 +1760,7 @@ fn check_member_constraints(
             .unwrap_or(BlameConstraint {
                 category: constraint.category,
                 from_closure: false,
-                cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
+                cause: ObligationCause::dummy_with_span(constraint.span),
                 variance_info: constraint.variance_info,
             })
     }
@@ -1869,6 +1869,7 @@ fn check_member_constraints(
                     sup: r,
                     sub: constraint.min_choice,
                     locations: Locations::All(p_c.definition_span),
+                    span: p_c.definition_span,
                     category: ConstraintCategory::OpaqueType,
                     variance_info: ty::VarianceDiagInfo::default(),
                 };
@@ -2017,7 +2018,7 @@ fn check_member_constraints(
                         category: constraint.category,
                         from_closure: false,
                         cause: ObligationCause::new(
-                            constraint.locations.span(body),
+                            constraint.span,
                             CRATE_HIR_ID,
                             cause_code.clone(),
                         ),
index 5022cb98b821d0786565e1a81cbc76e60d0f6396..21190a850b7b1eb33d8129fa3c85022ca4c3e112 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
 
 use crate::{
     constraints::OutlivesConstraint,
@@ -26,6 +26,7 @@
     implicit_region_bound: Option<ty::Region<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
     locations: Locations,
+    span: Span,
     category: ConstraintCategory,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 }
@@ -38,6 +39,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         implicit_region_bound: Option<ty::Region<'tcx>>,
         param_env: ty::ParamEnv<'tcx>,
         locations: Locations,
+        span: Span,
         category: ConstraintCategory,
         constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     ) -> Self {
@@ -49,6 +51,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             implicit_region_bound,
             param_env,
             locations,
+            span,
             category,
             constraints,
         }
@@ -153,6 +156,7 @@ fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
         self.constraints.outlives_constraints.push(OutlivesConstraint {
             locations: self.locations,
             category: self.category,
+            span: self.span,
             sub,
             sup,
             variance_info: ty::VarianceDiagInfo::default(),
index f8439d2e163559f5c51faa2364f18c15b2dc1aed..f08f2e1b12da6439fc574adcafe272119e481c33 100644 (file)
@@ -316,6 +316,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 self.implicit_region_bound,
                 self.param_env,
                 Locations::All(DUMMY_SP),
+                DUMMY_SP,
                 ConstraintCategory::Internal,
                 &mut self.constraints,
             )
index 83c8ecba1f17aa78d86d2af0a8a8c76dbc69bf06..e6f996491a41b7031b2420d00fc2e9b4266c52e8 100644 (file)
@@ -235,6 +235,7 @@ pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<
                 Some(self.implicit_region_bound),
                 self.param_env,
                 Locations::All(DUMMY_SP),
+                DUMMY_SP,
                 ConstraintCategory::Internal,
                 &mut self.borrowck_context.constraints,
             )
index ece801716b2dbacc6715dc87e2d37113304fce63..6dcdd46816e0dbea5a284ec8a88ffa306cbde90a 100644 (file)
@@ -1141,6 +1141,7 @@ fn push_region_constraints(
             Some(self.implicit_region_bound),
             self.param_env,
             locations,
+            locations.span(self.body),
             category,
             &mut self.borrowck_context.constraints,
         )
@@ -2401,6 +2402,7 @@ fn add_reborrow_constraint(
                                 sup: ref_region.to_region_vid(),
                                 sub: borrow_region.to_region_vid(),
                                 locations: location.to_locations(),
+                                span: location.to_locations().span(body),
                                 category,
                                 variance_info: ty::VarianceDiagInfo::default(),
                             });
index f0106630797d33d91f4cf771d22759a272c80d77..f98d2c3128c524ed7f27c20ce13719c7284009db 100644 (file)
@@ -116,6 +116,7 @@ fn push_outlives(
                 sup,
                 sub,
                 locations: self.locations,
+                span: self.locations.span(self.type_checker.body),
                 category: self.category,
                 variance_info: info,
             },
index 2af050f0c7533282bd965bf3628936e1a9e682f4..2e8cd934eb2986fb22f6633618722ec912ab8f44 100644 (file)
@@ -589,6 +589,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(),
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
             InlineAsmRegClass::X86(
                 X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
@@ -654,6 +655,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => cx.type_i16(),
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
@@ -784,6 +786,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
             _ => unreachable!(),
         },
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => None,
         InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
             unreachable!("clobber-only")
         }
index dff3200791825adac4ad57ce0ebf272891d0affd..e994001f96fd9b47cd6fa2e3c550c9ee1351b04d 100644 (file)
@@ -602,7 +602,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
             InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
             InlineAsmRegClass::X86(
-                X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+                X86InlineAsmRegClass::x87_reg
+                | X86InlineAsmRegClass::mmx_reg
+                | X86InlineAsmRegClass::kreg0,
             ) => unreachable!("clobber-only"),
             InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
             InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
@@ -687,7 +689,11 @@ fn modifier_to_llvm(
             _ => unreachable!(),
         },
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
-        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+        InlineAsmRegClass::X86(
+            X86InlineAsmRegClass::x87_reg
+            | X86InlineAsmRegClass::mmx_reg
+            | X86InlineAsmRegClass::kreg0,
+        ) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
@@ -757,7 +763,11 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
         | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
         InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
-        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+        InlineAsmRegClass::X86(
+            X86InlineAsmRegClass::x87_reg
+            | X86InlineAsmRegClass::mmx_reg
+            | X86InlineAsmRegClass::kreg0,
+        ) => {
             unreachable!("clobber-only")
         }
         InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
index cf32d558d4a5190bd495cc15d7b894ece75fe712..4d20ed841d47c502bd0b17d39c9f557ac91904b2 100644 (file)
@@ -987,7 +987,7 @@ fn is_illegal_instruction(_status: &ExitStatus) -> bool {
 
         // On MSVC packed debug information is produced by the linker itself so
         // there's no need to do anything else here.
-        SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
+        SplitDebuginfo::Packed if sess.target.is_like_windows => {}
 
         // ... and otherwise we're processing a `*.dwp` packed dwarf file.
         //
index 765bd877db1697dfde390b89604cd455e83b4a29..7b7c676c26cd12b7f487a99982c8154930b4589b 100644 (file)
@@ -1,12 +1,10 @@
 use std::collections::hash_map::Entry::*;
 
 use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::Node;
-use rustc_index::vec::IndexVec;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
@@ -277,17 +275,6 @@ fn upstream_monomorphizations_provider(
 
     let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default();
 
-    let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = {
-        let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, cnums.len() + 1);
-
-        for &cnum in cnums.iter() {
-            cnum_stable_ids[cnum] =
-                tcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).0;
-        }
-
-        cnum_stable_ids
-    };
-
     let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn();
 
     for &cnum in cnums.iter() {
@@ -316,7 +303,7 @@ fn upstream_monomorphizations_provider(
                     // If there are multiple monomorphizations available,
                     // we select one deterministically.
                     let other_cnum = *e.get();
-                    if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
+                    if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) {
                         e.insert(cnum);
                     }
                 }
index 80270f825630f079c58ec55ea4b8560b1de8ccd7..68f9bee593f65ea0f8b04da55f60ef657b0670f8 100644 (file)
@@ -38,7 +38,7 @@ pub(crate) fn const_caller_location(
     if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
         bug!("intern_const_alloc_recursive should not error in this case")
     }
-    ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx))
+    ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
 }
 
 /// Convert an evaluated constant to a type level constant
index f0fff602fe4cfbf8a647c415035898a04eaa8e6f..827959113b90734ce321673ab5c56bbc359469d7 100644 (file)
@@ -679,7 +679,7 @@ pub fn push_stack_frame(
         return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
-        debug!("body: {:#?}", body);
+        trace!("body: {:#?}", body);
         // first push a stack frame so we have access to the local substs
         let pre_frame = Frame {
             body,
@@ -836,7 +836,7 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
             return Ok(());
         }
 
-        debug!("locals: {:#?}", frame.locals);
+        trace!("locals: {:#?}", frame.locals);
 
         // Cleanup: deallocate all locals that are backed by an allocation.
         for local in &frame.locals {
index ddfbcbdd22e162495e2621d8ab67184c11ed4d68..7721485771b3b0a121ea08e321b326889869d982 100644 (file)
@@ -88,6 +88,10 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
     type PointerTag: Provenance + Eq + Hash + 'static;
 
+    /// When getting the AllocId of a pointer, some extra data is also obtained from the tag
+    /// that is passed to memory access hooks so they can do things with it.
+    type TagExtra: Copy + 'static;
+
     /// Machines can define extra (non-instance) things that represent values of function pointers.
     /// For example, Miri uses this to return a function pointer from `dlsym`
     /// that can later be called to execute the right thing.
@@ -122,6 +126,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
 
     /// Whether, when checking alignment, we should `force_int` and thus support
     /// custom alignment logic based on whatever the integer address happens to be.
+    ///
+    /// Requires PointerTag::OFFSET_IS_ADDR to be true.
     fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
     /// Whether to enforce the validity invariant
@@ -285,11 +291,14 @@ fn ptr_from_addr(
         addr: u64,
     ) -> Pointer<Option<Self::PointerTag>>;
 
-    /// Convert a pointer with provenance into an allocation-offset pair.
+    /// Convert a pointer with provenance into an allocation-offset pair
+    /// and extra provenance info.
+    ///
+    /// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`.
     fn ptr_get_alloc(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         ptr: Pointer<Self::PointerTag>,
-    ) -> (AllocId, Size);
+    ) -> (AllocId, Size, Self::TagExtra);
 
     /// Called to initialize the "extra" state of an allocation and make the pointers
     /// it contains (in relocations) tagged.  The way we construct allocations is
@@ -321,7 +330,7 @@ fn memory_read(
         _tcx: TyCtxt<'tcx>,
         _machine: &Self,
         _alloc_extra: &Self::AllocExtra,
-        _tag: Self::PointerTag,
+        _tag: (AllocId, Self::TagExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -333,7 +342,7 @@ fn memory_written(
         _tcx: TyCtxt<'tcx>,
         _machine: &mut Self,
         _alloc_extra: &mut Self::AllocExtra,
-        _tag: Self::PointerTag,
+        _tag: (AllocId, Self::TagExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -345,7 +354,7 @@ fn memory_deallocated(
         _tcx: TyCtxt<'tcx>,
         _machine: &mut Self,
         _alloc_extra: &mut Self::AllocExtra,
-        _tag: Self::PointerTag,
+        _tag: (AllocId, Self::TagExtra),
         _range: AllocRange,
     ) -> InterpResult<'tcx> {
         Ok(())
@@ -397,6 +406,8 @@ fn after_stack_pop(
 // (CTFE and ConstProp) use the same instance.  Here, we share that code.
 pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     type PointerTag = AllocId;
+    type TagExtra = ();
+
     type ExtraFnVal = !;
 
     type MemoryMap =
@@ -474,9 +485,12 @@ fn ptr_from_addr(_ecx: &InterpCx<$mir, $tcx, Self>, addr: u64) -> Pointer<Option
     }
 
     #[inline(always)]
-    fn ptr_get_alloc(_ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer<AllocId>) -> (AllocId, Size) {
+    fn ptr_get_alloc(
+        _ecx: &InterpCx<$mir, $tcx, Self>,
+        ptr: Pointer<AllocId>,
+    ) -> (AllocId, Size, Self::TagExtra) {
         // We know `offset` is relative to the allocation, so we can use `into_parts`.
         let (alloc_id, offset) = ptr.into_parts();
-        (alloc_id, offset)
+        (alloc_id, offset, ())
     }
 }
index a165fa23f30acf5e40af7a2a4d4171ba84ada542..b1d7ab6a098beccc7954322739b348f6551678d1 100644 (file)
@@ -158,8 +158,7 @@ pub fn global_base_pointer(
         &self,
         ptr: Pointer<AllocId>,
     ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
-        // We know `offset` is relative to the allocation, so we can use `into_parts`.
-        let (alloc_id, offset) = ptr.into_parts();
+        let alloc_id = ptr.provenance;
         // We need to handle `extern static`.
         match self.tcx.get_global_alloc(alloc_id) {
             Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
@@ -171,7 +170,7 @@ pub fn global_base_pointer(
             _ => {}
         }
         // And we need to get the tag.
-        Ok(M::tag_alloc_base_pointer(self, Pointer::new(alloc_id, offset)))
+        Ok(M::tag_alloc_base_pointer(self, ptr))
     }
 
     pub fn create_fn_alloc_ptr(
@@ -238,7 +237,7 @@ pub fn reallocate_ptr(
         new_align: Align,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
-        let (alloc_id, offset, ptr) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
         if offset.bytes() != 0 {
             throw_ub_format!(
                 "reallocating {:?} which does not point to the beginning of an object",
@@ -255,14 +254,14 @@ pub fn reallocate_ptr(
         };
         // This will also call the access hooks.
         self.mem_copy(
-            ptr.into(),
+            ptr,
             Align::ONE,
             new_ptr.into(),
             Align::ONE,
             old_size.min(new_size),
             /*nonoverlapping*/ true,
         )?;
-        self.deallocate_ptr(ptr.into(), old_size_and_align, kind)?;
+        self.deallocate_ptr(ptr, old_size_and_align, kind)?;
 
         Ok(new_ptr)
     }
@@ -274,7 +273,7 @@ pub fn deallocate_ptr(
         old_size_and_align: Option<(Size, Align)>,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx> {
-        let (alloc_id, offset, ptr) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?;
         trace!("deallocating: {}", alloc_id);
 
         if offset.bytes() != 0 {
@@ -330,7 +329,7 @@ pub fn deallocate_ptr(
             *self.tcx,
             &mut self.machine,
             &mut alloc.extra,
-            ptr.provenance,
+            (alloc_id, tag),
             alloc_range(Size::ZERO, size),
         )?;
 
@@ -350,17 +349,17 @@ fn get_ptr_access(
         ptr: Pointer<Option<M::PointerTag>>,
         size: Size,
         align: Align,
-    ) -> InterpResult<'tcx, Option<(AllocId, Size, Pointer<M::PointerTag>)>> {
+    ) -> InterpResult<'tcx, Option<(AllocId, Size, M::TagExtra)>> {
         let align = M::enforce_alignment(&self).then_some(align);
         self.check_and_deref_ptr(
             ptr,
             size,
             align,
             CheckInAllocMsg::MemoryAccessTest,
-            |alloc_id, offset, ptr| {
+            |alloc_id, offset, tag| {
                 let (size, align) =
                     self.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?;
-                Ok((size, align, (alloc_id, offset, ptr)))
+                Ok((size, align, (alloc_id, offset, tag)))
             },
         )
     }
@@ -401,11 +400,7 @@ fn check_and_deref_ptr<T>(
         size: Size,
         align: Option<Align>,
         msg: CheckInAllocMsg,
-        alloc_size: impl FnOnce(
-            AllocId,
-            Size,
-            Pointer<M::PointerTag>,
-        ) -> InterpResult<'tcx, (Size, Align, T)>,
+        alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
         fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
             if offset % align.bytes() == 0 {
@@ -433,8 +428,8 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
                 }
                 None
             }
-            Ok((alloc_id, offset, ptr)) => {
-                let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, ptr)?;
+            Ok((alloc_id, offset, tag)) => {
+                let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, tag)?;
                 // Test bounds. This also ensures non-null.
                 // It is sufficient to check this for the end pointer. Also check for overflow!
                 if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) {
@@ -450,10 +445,8 @@ fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
                 // we want the error to be about the bounds.
                 if let Some(align) = align {
                     if M::force_int_for_alignment_check(self) {
-                        let addr = Scalar::from_pointer(ptr, &self.tcx)
-                            .to_machine_usize(&self.tcx)
-                            .expect("ptr-to-int cast for align check should never fail");
-                        check_offset_align(addr, align)?;
+                        // `force_int_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
+                        check_offset_align(ptr.addr().bytes(), align)?;
                     } else {
                         // Check allocation alignment and offset alignment.
                         if alloc_align.bytes() < align.bytes() {
@@ -569,14 +562,14 @@ pub fn get_ptr_alloc<'a>(
             size,
             align,
             CheckInAllocMsg::MemoryAccessTest,
-            |alloc_id, offset, ptr| {
+            |alloc_id, offset, tag| {
                 let alloc = self.get_alloc_raw(alloc_id)?;
-                Ok((alloc.size(), alloc.align, (alloc_id, offset, ptr, alloc)))
+                Ok((alloc.size(), alloc.align, (alloc_id, offset, tag, alloc)))
             },
         )?;
-        if let Some((alloc_id, offset, ptr, alloc)) = ptr_and_alloc {
+        if let Some((alloc_id, offset, tag, alloc)) = ptr_and_alloc {
             let range = alloc_range(offset, size);
-            M::memory_read(*self.tcx, &self.machine, &alloc.extra, ptr.provenance, range)?;
+            M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, tag), range)?;
             Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
         } else {
             // Even in this branch we have to be sure that we actually access the allocation, in
@@ -631,13 +624,13 @@ pub fn get_ptr_alloc_mut<'a>(
         align: Align,
     ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::PointerTag, M::AllocExtra>>> {
         let parts = self.get_ptr_access(ptr, size, align)?;
-        if let Some((alloc_id, offset, ptr)) = parts {
+        if let Some((alloc_id, offset, tag)) = parts {
             let tcx = *self.tcx;
             // FIXME: can we somehow avoid looking up the allocation twice here?
             // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
             let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
             let range = alloc_range(offset, size);
-            M::memory_written(tcx, machine, &mut alloc.extra, ptr.provenance, range)?;
+            M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, tag), range)?;
             Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
         } else {
             Ok(None)
@@ -732,7 +725,7 @@ pub fn get_ptr_fn(
         ptr: Pointer<Option<M::PointerTag>>,
     ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
         trace!("get_fn({:?})", ptr);
-        let (alloc_id, offset, _ptr) = self.ptr_get_alloc_id(ptr)?;
+        let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
         if offset.bytes() != 0 {
             throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
         }
@@ -877,9 +870,17 @@ pub fn write_scalar(
         range: AllocRange,
         val: ScalarMaybeUninit<Tag>,
     ) -> InterpResult<'tcx> {
+        let range = self.range.subrange(range);
+        debug!(
+            "write_scalar in {} at {:#x}, size {}: {:?}",
+            self.alloc_id,
+            range.start.bytes(),
+            range.size.bytes(),
+            val
+        );
         Ok(self
             .alloc
-            .write_scalar(&self.tcx, self.range.subrange(range), val)
+            .write_scalar(&self.tcx, range, val)
             .map_err(|e| e.to_interp_error(self.alloc_id))?)
     }
 
@@ -892,17 +893,29 @@ pub fn write_ptr_sized(
     }
 
     /// Mark the entire referenced range as uninitalized
-    pub fn write_uninit(&mut self) {
-        self.alloc.mark_init(self.range, false);
+    pub fn write_uninit(&mut self) -> InterpResult<'tcx> {
+        Ok(self
+            .alloc
+            .write_uninit(&self.tcx, self.range)
+            .map_err(|e| e.to_interp_error(self.alloc_id))?)
     }
 }
 
 impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
     pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
-        Ok(self
+        let range = self.range.subrange(range);
+        let res = self
             .alloc
-            .read_scalar(&self.tcx, self.range.subrange(range))
-            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+            .read_scalar(&self.tcx, range)
+            .map_err(|e| e.to_interp_error(self.alloc_id))?;
+        debug!(
+            "read_scalar in {} at {:#x}, size {}: {:?}",
+            self.alloc_id,
+            range.start.bytes(),
+            range.size.bytes(),
+            res
+        );
+        Ok(res)
     }
 
     pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
@@ -1009,16 +1022,16 @@ pub fn mem_copy_repeatedly(
         // and once below to get the underlying `&[mut] Allocation`.
 
         // Source alloc preparations and access hooks.
-        let Some((src_alloc_id, src_offset, src)) = src_parts else {
+        let Some((src_alloc_id, src_offset, src_tag)) = src_parts else {
             // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
             return Ok(());
         };
         let src_alloc = self.get_alloc_raw(src_alloc_id)?;
         let src_range = alloc_range(src_offset, size);
-        M::memory_read(*tcx, &self.machine, &src_alloc.extra, src.provenance, src_range)?;
+        M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_tag), src_range)?;
         // We need the `dest` ptr for the next operation, so we get it now.
         // We already did the source checks and called the hooks so we are good to return early.
-        let Some((dest_alloc_id, dest_offset, dest)) = dest_parts else {
+        let Some((dest_alloc_id, dest_offset, dest_tag)) = dest_parts else {
             // Zero-sized *destination*.
             return Ok(());
         };
@@ -1040,7 +1053,13 @@ pub fn mem_copy_repeatedly(
         // Destination alloc preparations and access hooks.
         let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
         let dest_range = alloc_range(dest_offset, size * num_copies);
-        M::memory_written(*tcx, extra, &mut dest_alloc.extra, dest.provenance, dest_range)?;
+        M::memory_written(
+            *tcx,
+            extra,
+            &mut dest_alloc.extra,
+            (dest_alloc_id, dest_tag),
+            dest_range,
+        )?;
         let dest_bytes = dest_alloc
             .get_bytes_mut_ptr(&tcx, dest_range)
             .map_err(|e| e.to_interp_error(dest_alloc_id))?
@@ -1053,8 +1072,10 @@ pub fn mem_copy_repeatedly(
             // This also avoids writing to the target bytes so that the backing allocation is never
             // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary
             // operating system this can avoid physically allocating the page.
-            dest_alloc.mark_init(dest_range, false); // `Size` multiplication
-            dest_alloc.mark_relocation_range(relocations);
+            dest_alloc
+                .write_uninit(&tcx, dest_range)
+                .map_err(|e| e.to_interp_error(dest_alloc_id))?;
+            // We can forget about the relocations, this is all not initialized anyway.
             return Ok(());
         }
 
@@ -1159,11 +1180,11 @@ pub fn scalar_may_be_null(&self, scalar: Scalar<M::PointerTag>) -> InterpResult<
     pub fn ptr_try_get_alloc_id(
         &self,
         ptr: Pointer<Option<M::PointerTag>>,
-    ) -> Result<(AllocId, Size, Pointer<M::PointerTag>), u64> {
+    ) -> Result<(AllocId, Size, M::TagExtra), u64> {
         match ptr.into_pointer_or_addr() {
             Ok(ptr) => {
-                let (alloc_id, offset) = M::ptr_get_alloc(self, ptr);
-                Ok((alloc_id, offset, ptr))
+                let (alloc_id, offset, extra) = M::ptr_get_alloc(self, ptr);
+                Ok((alloc_id, offset, extra))
             }
             Err(addr) => Err(addr.bytes()),
         }
@@ -1174,7 +1195,7 @@ pub fn ptr_try_get_alloc_id(
     pub fn ptr_get_alloc_id(
         &self,
         ptr: Pointer<Option<M::PointerTag>>,
-    ) -> InterpResult<'tcx, (AllocId, Size, Pointer<M::PointerTag>)> {
+    ) -> InterpResult<'tcx, (AllocId, Size, M::TagExtra)> {
         self.ptr_try_get_alloc_id(ptr).map_err(|offset| {
             err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into()
         })
index 31da4522a1fda38ff0554920315fa39c5111e597..e4660fe090ce5fb4900d9c350908103866906a1d 100644 (file)
@@ -823,7 +823,7 @@ pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpRes
             // Zero-sized access
             return Ok(());
         };
-        alloc.write_uninit();
+        alloc.write_uninit()?;
         Ok(())
     }
 
index 4a0aa41de739b3caa13f0ed80fa3170fc8c3d331..71d29be97d5ec38e99b544bee0532d2c58ad4400 100644 (file)
@@ -432,7 +432,7 @@ fn check_safe_pointer(
         if let Some(ref mut ref_tracking) = self.ref_tracking {
             // Proceed recursively even for ZST, no reason to skip them!
             // `!` is a ZST and we want to validate it.
-            if let Ok((alloc_id, _offset, _ptr)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
+            if let Ok((alloc_id, _offset, _tag)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
                 // Special handling for pointers to statics (irrespective of their type).
                 let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id);
                 if let Some(GlobalAlloc::Static(did)) = alloc_kind {
index 85ad0f2f7f5ce5aca99f2f8ddc601ce1f7f45f6b..25353290fd50c4943c018554102791388342163d 100644 (file)
@@ -207,9 +207,14 @@ pub trait ToStableHashKey<HCX> {
     fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
 }
 
-// Implement HashStable by just calling `Hash::hash()`. This works fine for
-// self-contained values that don't depend on the hashing context `CTX`.
-#[macro_export]
+/// Implement HashStable by just calling `Hash::hash()`.
+///
+/// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting.
+/// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013)
+/// for examples). Therefore this macro is not exported and should only be used in the limited cases
+/// here in this module.
+///
+/// Use `#[derive(HashStable_Generic)]` instead.
 macro_rules! impl_stable_hash_via_hash {
     ($t:ty) => {
         impl<CTX> $crate::stable_hasher::HashStable<CTX> for $t {
@@ -246,12 +251,14 @@ fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
 }
 
 impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
+    #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.get().hash_stable(ctx, hasher)
     }
 }
 
 impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize {
+    #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.get().hash_stable(ctx, hasher)
     }
@@ -272,12 +279,14 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
 }
 
 impl<CTX> HashStable<CTX> for ::std::cmp::Ordering {
+    #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         (*self as i8).hash_stable(ctx, hasher);
     }
 }
 
 impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) {
+    #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         let (ref _0,) = *self;
         _0.hash_stable(ctx, hasher);
index de0dd18cc6ec5402283997b1adcb2581aa34c343..e1e0ed7222d55fb39265197de0f449e32bf5d32d 100644 (file)
@@ -338,18 +338,12 @@ pub fn primary_spans(&self) -> &[Span] {
 
     /// Returns `true` if any of the primary spans are displayable.
     pub fn has_primary_spans(&self) -> bool {
-        self.primary_spans.iter().any(|sp| !sp.is_dummy())
+        !self.is_dummy()
     }
 
     /// 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
+        self.primary_spans.iter().all(|sp| sp.is_dummy())
     }
 
     /// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
index 9cd072c8b4cdf38af332c504b226cea1996edb3f..cd17726c78588dae3ac87503de5ba14dd192a8c1 100644 (file)
@@ -1,12 +1,11 @@
 use crate::snippet::Style;
 use crate::{
     CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart,
-    SuggestionStyle, ToolMetadata,
+    SuggestionStyle,
 };
 use rustc_data_structures::stable_map::FxHashMap;
 use rustc_error_messages::FluentValue;
 use rustc_lint_defs::{Applicability, LintExpectationId};
-use rustc_serialize::json::Json;
 use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -554,7 +553,6 @@ pub fn multipart_suggestion_with_style(
             msg: msg.into(),
             style,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -582,7 +580,6 @@ pub fn tool_only_multipart_suggestion(
             msg: msg.into(),
             style: SuggestionStyle::CompletelyHidden,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -637,7 +634,6 @@ pub fn span_suggestion_with_style(
             msg: msg.into(),
             style,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -680,7 +676,6 @@ pub fn span_suggestions(
             msg: msg.into(),
             style: SuggestionStyle::ShowCode,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -705,7 +700,6 @@ pub fn multipart_suggestions(
             msg: msg.into(),
             style: SuggestionStyle::ShowCode,
             applicability,
-            tool_metadata: Default::default(),
         });
         self
     }
@@ -774,23 +768,6 @@ pub fn tool_only_span_suggestion(
         self
     }
 
-    /// Adds a suggestion intended only for a tool. The intent is that the metadata encodes
-    /// the suggestion in a tool-specific way, as it may not even directly involve Rust code.
-    pub fn tool_only_suggestion_with_metadata(
-        &mut self,
-        msg: impl Into<DiagnosticMessage>,
-        applicability: Applicability,
-        tool_metadata: Json,
-    ) {
-        self.push_suggestion(CodeSuggestion {
-            substitutions: vec![],
-            msg: msg.into(),
-            style: SuggestionStyle::CompletelyHidden,
-            applicability,
-            tool_metadata: ToolMetadata::new(tool_metadata),
-        })
-    }
-
     pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
         self.span = sp.into();
         if let Some(span) = self.span.primary_span() {
index 0139007da4261222d7b565c72da23e59bca2b586..d680e7fab704763917a2361f2c67b2100b33e915 100644 (file)
@@ -14,7 +14,6 @@
 use crate::emitter::{Emitter, HumanReadableErrorType};
 use crate::registry::Registry;
 use crate::DiagnosticId;
-use crate::ToolMetadata;
 use crate::{
     CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
 };
@@ -30,7 +29,6 @@
 use std::vec;
 
 use rustc_serialize::json::{as_json, as_pretty_json};
-use rustc_serialize::{Encodable, Encoder};
 
 #[cfg(test)]
 mod tests;
@@ -205,8 +203,7 @@ fn should_show_explain(&self) -> bool {
 
 // The following data types are provided just for serialisation.
 
-// NOTE: this has a manual implementation of Encodable which needs to be updated in
-// parallel.
+#[derive(Encodable)]
 struct Diagnostic {
     /// The primary error message.
     message: String,
@@ -218,65 +215,6 @@ struct Diagnostic {
     children: Vec<Diagnostic>,
     /// The message as rustc would render it.
     rendered: Option<String>,
-    /// Extra tool metadata
-    tool_metadata: ToolMetadata,
-}
-
-macro_rules! encode_fields {
-    (
-        $enc:expr,                  // encoder
-        $idx:expr,                  // starting field index
-        $struct:expr,               // struct we're serializing
-        $struct_name:ident,         // struct name
-        [ $($name:ident),+$(,)? ],  // fields to encode
-        [ $($ignore:ident),+$(,)? ] // fields we're skipping
-    ) => {
-        {
-            // Pattern match to make sure all fields are accounted for
-            let $struct_name { $($name,)+ $($ignore: _,)+ } = $struct;
-            let mut idx = $idx;
-            $(
-                $enc.emit_struct_field(
-                    stringify!($name),
-                    idx == 0,
-                    |enc| $name.encode(enc),
-                )?;
-                idx += 1;
-            )+
-            idx
-        }
-    };
-}
-
-// Special-case encoder to skip tool_metadata if not set
-impl<E: Encoder> Encodable<E> for Diagnostic {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_struct(false, |s| {
-            let mut idx = 0;
-
-            idx = encode_fields!(
-                s,
-                idx,
-                self,
-                Self,
-                [message, code, level, spans, children, rendered],
-                [tool_metadata]
-            );
-            if self.tool_metadata.is_set() {
-                idx = encode_fields!(
-                    s,
-                    idx,
-                    self,
-                    Self,
-                    [tool_metadata],
-                    [message, code, level, spans, children, rendered]
-                );
-            }
-
-            let _ = idx;
-            Ok(())
-        })
-    }
 }
 
 #[derive(Encodable)]
@@ -380,7 +318,6 @@ fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnos
                 spans: DiagnosticSpan::from_suggestion(sugg, &args, je),
                 children: vec![],
                 rendered: None,
-                tool_metadata: sugg.tool_metadata.clone(),
             }
         });
 
@@ -428,7 +365,6 @@ fn flush(&mut self) -> io::Result<()> {
                 .chain(sugg)
                 .collect(),
             rendered: Some(output),
-            tool_metadata: ToolMetadata::default(),
         }
     }
 
@@ -449,7 +385,6 @@ fn from_sub_diagnostic(
                 .unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, args, je)),
             children: vec![],
             rendered: None,
-            tool_metadata: ToolMetadata::default(),
         }
     }
 }
index 416bc4e2e3bf2a518079585d9ce19236c670ea88..4e6ab0edf6666377c97b16e433619dd6c785f2c2 100644 (file)
     LazyFallbackBundle, MultiSpan, SpanLabel, DEFAULT_LOCALE_RESOURCES,
 };
 pub use rustc_lint_defs::{pluralize, Applicability};
-use rustc_serialize::json::Json;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::source_map::SourceMap;
+use rustc_span::HashStableContext;
 use rustc_span::{Loc, Span};
 
 use std::borrow::Cow;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
 use std::num::NonZeroUsize;
 use std::panic;
 use std::path::Path;
@@ -93,39 +92,6 @@ fn hide_inline(&self) -> bool {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Default)]
-pub struct ToolMetadata(pub Option<Json>);
-
-impl ToolMetadata {
-    fn new(json: Json) -> Self {
-        ToolMetadata(Some(json))
-    }
-
-    fn is_set(&self) -> bool {
-        self.0.is_some()
-    }
-}
-
-impl Hash for ToolMetadata {
-    fn hash<H: Hasher>(&self, _state: &mut H) {}
-}
-
-// Doesn't really need to round-trip
-impl<D: Decoder> Decodable<D> for ToolMetadata {
-    fn decode(_d: &mut D) -> Self {
-        ToolMetadata(None)
-    }
-}
-
-impl<S: Encoder> Encodable<S> for ToolMetadata {
-    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        match &self.0 {
-            None => e.emit_unit(),
-            Some(json) => json.encode(e),
-        }
-    }
-}
-
 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub struct CodeSuggestion {
     /// Each substitute can have multiple variants due to multiple
@@ -159,8 +125,6 @@ pub struct CodeSuggestion {
     /// which are useful for users but not useful for
     /// tools like rustfix
     pub applicability: Applicability,
-    /// Tool-specific metadata
-    pub tool_metadata: ToolMetadata,
 }
 
 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
@@ -1511,35 +1475,17 @@ pub fn add_elided_lifetime_in_path_suggestion(
     path_span: Span,
     incl_angl_brckt: bool,
     insertion_span: Span,
-    anon_lts: String,
 ) {
-    let (replace_span, suggestion) = if incl_angl_brckt {
-        (insertion_span, anon_lts)
-    } else {
-        // When possible, prefer a suggestion that replaces the whole
-        // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
-        // at a point (which makes for an ugly/confusing label)
-        if let Ok(snippet) = source_map.span_to_snippet(path_span) {
-            // But our spans can get out of whack due to macros; if the place we think
-            // we want to insert `'_` isn't even within the path expression's span, we
-            // should bail out of making any suggestion rather than panicking on a
-            // subtract-with-overflow or string-slice-out-out-bounds (!)
-            // FIXME: can we do better?
-            if insertion_span.lo().0 < path_span.lo().0 {
-                return;
-            }
-            let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
-            if insertion_index > snippet.len() {
-                return;
-            }
-            let (before, after) = snippet.split_at(insertion_index);
-            (path_span, format!("{}{}{}", before, anon_lts, after))
-        } else {
-            (insertion_span, anon_lts)
-        }
-    };
-    diag.span_suggestion(
-        replace_span,
+    diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
+    if source_map.span_to_snippet(insertion_span).is_err() {
+        // Do not try to suggest anything if generated by a proc-macro.
+        return;
+    }
+    let anon_lts = vec!["'_"; n].join(", ");
+    let suggestion =
+        if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
+    diag.span_suggestion_verbose(
+        insertion_span.shrink_to_hi(),
         &format!("indicate the anonymous lifetime{}", pluralize!(n)),
         suggestion,
         Applicability::MachineApplicable,
@@ -1549,6 +1495,7 @@ pub fn add_elided_lifetime_in_path_suggestion(
 /// Useful type to use with `Result<>` indicate that an error has already
 /// been reported to the user, so no need to continue checking.
 #[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable_Generic)]
 pub struct ErrorGuaranteed(());
 
 impl ErrorGuaranteed {
@@ -1558,5 +1505,3 @@ pub fn unchecked_claim_error_was_emitted() -> Self {
         ErrorGuaranteed(())
     }
 }
-
-rustc_data_structures::impl_stable_hash_via_hash!(ErrorGuaranteed);
index 53d60d280c001dcf3179d0488facd869e828a5dc..324e110005717ac6517f4f357e4b4dc7c08cc1a2 100644 (file)
@@ -1,4 +1,4 @@
-use crate::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_id::DefId;
 use crate::hir;
 
 use rustc_ast as ast;
@@ -124,9 +124,7 @@ impl DefKind {
     pub fn descr(self, def_id: DefId) -> &'static str {
         match self {
             DefKind::Fn => "function",
-            DefKind::Mod if def_id.index == CRATE_DEF_INDEX && def_id.krate != LOCAL_CRATE => {
-                "crate"
-            }
+            DefKind::Mod if def_id.is_crate_root() && !def_id.is_local() => "crate",
             DefKind::Mod => "module",
             DefKind::Static(..) => "static",
             DefKind::Enum => "enum",
index 4908992085a6e12de70bf3f25fc513d71c4f0ff2..bce9ba12ac0c424045e391a05f420f714307d4f7 100644 (file)
@@ -353,11 +353,6 @@ pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions {
         }
     }
 
-    /// Retrieves the root definition.
-    pub fn get_root_def(&self) -> LocalDefId {
-        LocalDefId { local_def_index: CRATE_DEF_INDEX }
-    }
-
     /// Adds a definition with a parent definition.
     pub fn create_def(
         &mut self,
index 83193746432e9678105bb3380401880d3bc59c5a..b3de86662eb09dc71da34f0f7187bab0bf975458 100644 (file)
@@ -95,7 +95,7 @@ pub enum LifetimeName {
     /// User wrote nothing (e.g., the lifetime in `&u32`).
     ///
     /// The bool indicates whether the user should have written something.
-    Implicit(bool),
+    Implicit,
 
     /// Implicit lifetime in a context like `dyn Foo`. This is
     /// distinguished from implicit lifetimes elsewhere because the
@@ -125,7 +125,7 @@ impl LifetimeName {
     pub fn ident(&self) -> Ident {
         match *self {
             LifetimeName::ImplicitObjectLifetimeDefault
-            | LifetimeName::Implicit(_)
+            | LifetimeName::Implicit
             | LifetimeName::Error => Ident::empty(),
             LifetimeName::Underscore => Ident::with_dummy_span(kw::UnderscoreLifetime),
             LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
@@ -136,7 +136,7 @@ pub fn ident(&self) -> Ident {
     pub fn is_elided(&self) -> bool {
         match self {
             LifetimeName::ImplicitObjectLifetimeDefault
-            | LifetimeName::Implicit(_)
+            | LifetimeName::Implicit
             | LifetimeName::Underscore => true,
 
             // It might seem surprising that `Fresh(_)` counts as
index 3b5e4dcf5e01188db28d3edfcab62cc43167b28f..346ac9e96440abfb1eae0ec9932bf40d5b6fdd91 100644 (file)
@@ -1,4 +1,4 @@
-use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
+use crate::def_id::{LocalDefId, CRATE_DEF_ID};
 use std::fmt;
 
 /// Uniquely identifies a node in the HIR of the current crate. It is
@@ -76,16 +76,14 @@ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
     /// integers starting at zero, so a mapping that maps all or most nodes within
     /// an "item-like" to something else can be implemented by a `Vec` instead of a
     /// tree or hash map.
+    #[derive(HashStable_Generic)]
     pub struct ItemLocalId { .. }
 }
-rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
+
 impl ItemLocalId {
     /// Signal local id which should never be used.
     pub const INVALID: ItemLocalId = ItemLocalId::MAX;
 }
 
-/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
-pub const CRATE_HIR_ID: HirId = HirId {
-    owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
-    local_id: ItemLocalId::from_u32(0),
-};
+/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
+pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::from_u32(0) };
index 445b856e513dc4a78f8e4feb4e91378e7d84eb32..8689e2c2afab36fd504eaf3c203bc09226bb8872 100644 (file)
@@ -528,7 +528,7 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
         | LifetimeName::Param(ParamName::Error)
         | LifetimeName::Static
         | LifetimeName::Error
-        | LifetimeName::Implicit(_)
+        | LifetimeName::Implicit
         | LifetimeName::ImplicitObjectLifetimeDefault
         | LifetimeName::Underscore => {}
     }
index 60b48e9bc8a0124d1b2fc793121ba42e901fb173..2d06c9d8ec92c60d8f6cb3d56820d56d7c0d29d7 100644 (file)
@@ -241,7 +241,7 @@ fn dump_graph(query: &DepGraphQuery) {
             let targets = node_set(&query, &edge_filter.target);
             filter_nodes(&query, &sources, &targets)
         }
-        Err(_) => query.nodes().into_iter().collect(),
+        Err(_) => query.nodes().into_iter().map(|n| n.kind).collect(),
     };
     let edges = filter_edges(&query, &nodes);
 
@@ -264,33 +264,33 @@ fn dump_graph(query: &DepGraphQuery) {
 }
 
 #[allow(missing_docs)]
-pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>, Vec<(&'q DepNode, &'q DepNode)>);
+pub struct GraphvizDepGraph(FxHashSet<DepKind>, Vec<(DepKind, DepKind)>);
 
-impl<'a, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> {
-    type Node = &'q DepNode;
-    type Edge = (&'q DepNode, &'q DepNode);
-    fn nodes(&self) -> dot::Nodes<'_, &'q DepNode> {
+impl<'a> dot::GraphWalk<'a> for GraphvizDepGraph {
+    type Node = DepKind;
+    type Edge = (DepKind, DepKind);
+    fn nodes(&self) -> dot::Nodes<'_, DepKind> {
         let nodes: Vec<_> = self.0.iter().cloned().collect();
         nodes.into()
     }
-    fn edges(&self) -> dot::Edges<'_, (&'q DepNode, &'q DepNode)> {
+    fn edges(&self) -> dot::Edges<'_, (DepKind, DepKind)> {
         self.1[..].into()
     }
-    fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
+    fn source(&self, edge: &(DepKind, DepKind)) -> DepKind {
         edge.0
     }
-    fn target(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode {
+    fn target(&self, edge: &(DepKind, DepKind)) -> DepKind {
         edge.1
     }
 }
 
-impl<'a, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> {
-    type Node = &'q DepNode;
-    type Edge = (&'q DepNode, &'q DepNode);
+impl<'a> dot::Labeller<'a> for GraphvizDepGraph {
+    type Node = DepKind;
+    type Edge = (DepKind, DepKind);
     fn graph_id(&self) -> dot::Id<'_> {
         dot::Id::new("DependencyGraph").unwrap()
     }
-    fn node_id(&self, n: &&'q DepNode) -> dot::Id<'_> {
+    fn node_id(&self, n: &DepKind) -> dot::Id<'_> {
         let s: String = format!("{:?}", n)
             .chars()
             .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' })
@@ -298,7 +298,7 @@ fn node_id(&self, n: &&'q DepNode) -> dot::Id<'_> {
         debug!("n={:?} s={:?}", n, s);
         dot::Id::new(s).unwrap()
     }
-    fn node_label(&self, n: &&'q DepNode) -> dot::LabelText<'_> {
+    fn node_label(&self, n: &DepKind) -> dot::LabelText<'_> {
         dot::LabelText::label(format!("{:?}", n))
     }
 }
@@ -323,7 +323,7 @@ fn filter_nodes<'q>(
     query: &'q DepGraphQuery,
     sources: &Option<FxHashSet<&'q DepNode>>,
     targets: &Option<FxHashSet<&'q DepNode>>,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
     if let Some(sources) = sources {
         if let Some(targets) = targets {
             walk_between(query, sources, targets)
@@ -333,7 +333,7 @@ fn filter_nodes<'q>(
     } else if let Some(targets) = targets {
         walk_nodes(query, targets, INCOMING)
     } else {
-        query.nodes().into_iter().collect()
+        query.nodes().into_iter().map(|n| n.kind).collect()
     }
 }
 
@@ -341,17 +341,17 @@ fn walk_nodes<'q>(
     query: &'q DepGraphQuery,
     starts: &FxHashSet<&'q DepNode>,
     direction: Direction,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
     let mut set = FxHashSet::default();
     for &start in starts {
         debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING);
-        if set.insert(start) {
+        if set.insert(start.kind) {
             let mut stack = vec![query.indices[start]];
             while let Some(index) = stack.pop() {
                 for (_, edge) in query.graph.adjacent_edges(index, direction) {
                     let neighbor_index = edge.source_or_target(direction);
                     let neighbor = query.graph.node_data(neighbor_index);
-                    if set.insert(neighbor) {
+                    if set.insert(neighbor.kind) {
                         stack.push(neighbor_index);
                     }
                 }
@@ -365,7 +365,7 @@ fn walk_between<'q>(
     query: &'q DepGraphQuery,
     sources: &FxHashSet<&'q DepNode>,
     targets: &FxHashSet<&'q DepNode>,
-) -> FxHashSet<&'q DepNode> {
+) -> FxHashSet<DepKind> {
     // This is a bit tricky. We want to include a node only if it is:
     // (a) reachable from a source and (b) will reach a target. And we
     // have to be careful about cycles etc.  Luckily efficiency is not
@@ -396,6 +396,7 @@ enum State {
             let index = query.indices[n];
             node_states[index.0] == State::Included
         })
+        .map(|n| n.kind)
         .collect();
 
     fn recurse(query: &DepGraphQuery, node_states: &mut [State], node: NodeIndex) -> bool {
@@ -433,11 +434,13 @@ fn recurse(query: &DepGraphQuery, node_states: &mut [State], node: NodeIndex) ->
 
 fn filter_edges<'q>(
     query: &'q DepGraphQuery,
-    nodes: &FxHashSet<&'q DepNode>,
-) -> Vec<(&'q DepNode, &'q DepNode)> {
-    query
+    nodes: &FxHashSet<DepKind>,
+) -> Vec<(DepKind, DepKind)> {
+    let uniq: FxHashSet<_> = query
         .edges()
         .into_iter()
-        .filter(|&(source, target)| nodes.contains(source) && nodes.contains(target))
-        .collect()
+        .map(|(s, t)| (s.kind, t.kind))
+        .filter(|(source, target)| nodes.contains(source) && nodes.contains(target))
+        .collect();
+    uniq.into_iter().collect()
 }
index 86229dbfad746a51b528e1de9fff6d256cf7baff..0ca0fe33614f826600589d69fd0edfcea9b14d9e 100644 (file)
@@ -567,11 +567,17 @@ fn relate_item_substs(
             // Avoid fetching the variance if we are in an invariant
             // context; no need, and it can induce dependency cycles
             // (e.g., #41849).
-            relate::relate_substs(self, None, a_subst, b_subst)
+            relate::relate_substs(self, a_subst, b_subst)
         } else {
             let tcx = self.tcx();
             let opt_variances = tcx.variances_of(item_def_id);
-            relate::relate_substs(self, Some((item_def_id, &opt_variances)), a_subst, b_subst)
+            relate::relate_substs_with_variances(
+                self,
+                item_def_id,
+                &opt_variances,
+                a_subst,
+                b_subst,
+            )
         }
     }
 
index 65c0eba4b3d5c791aa254269c389c3c26460e5f4..ef6d464d3c6f101bad711e81647aa88450a4857b 100644 (file)
@@ -53,7 +53,7 @@ fn relate_item_substs(
         // performing trait matching (which then performs equality
         // unification).
 
-        relate::relate_substs(self, None, a_subst, b_subst)
+        relate::relate_substs(self, a_subst, b_subst)
     }
 
     fn relate_with_variance<T: Relate<'tcx>>(
index 8ea47dda928f5f0cc8af8c4ab83299c95ee021e1..02f747eeccc3e1eb21f72d4f6395c4f0112bb58b 100644 (file)
@@ -18,7 +18,6 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_index = { path = "../rustc_index" }
 rustc_session = { path = "../rustc_session" }
-rustc_serialize = { path = "../rustc_serialize" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_infer = { path = "../rustc_infer" }
index e6f9246d73242f4b1c2ebe200a15075b2f30db0d..77fe76af2de21ce7d777168524540788f5145347 100644 (file)
@@ -441,6 +441,7 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast
             _,
             ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
             _,
+            _,
             body,
         ) = fk
         {
index 3600b6ad212036da44e05b0625f6e7859695b8b4..0ffa65b79b584a5070e06bc93b2bcd717a6f91cb 100644 (file)
@@ -21,7 +21,8 @@
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
-use rustc_errors::{struct_span_err, Applicability, MultiSpan, SuggestionStyle};
+use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err};
+use rustc_errors::{Applicability, MultiSpan, SuggestionStyle};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -32,8 +33,7 @@
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
-use rustc_serialize::json::Json;
-use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
+use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -665,6 +665,21 @@ fn lookup_with_diagnostics(
                 ) => {
                     db.span_note(span_def, "the macro is defined here");
                 }
+                BuiltinLintDiagnostics::ElidedLifetimesInPaths(
+                    n,
+                    path_span,
+                    incl_angl_brckt,
+                    insertion_span,
+                ) => {
+                    add_elided_lifetime_in_path_suggestion(
+                        sess.source_map(),
+                        &mut db,
+                        n,
+                        path_span,
+                        incl_angl_brckt,
+                        insertion_span,
+                    );
+                }
                 BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
                     db.span_suggestion(span, &note, sugg, Applicability::MaybeIncorrect);
                 }
@@ -712,30 +727,6 @@ fn lookup_with_diagnostics(
                 BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
                     db.span_label(span, "the attribute is introduced here");
                 }
-                BuiltinLintDiagnostics::ExternDepSpec(krate, loc) => {
-                    let json = match loc {
-                        ExternDepSpec::Json(json) => {
-                            db.help(&format!("remove unnecessary dependency `{}`", krate));
-                            json
-                        }
-                        ExternDepSpec::Raw(raw) => {
-                            db.help(&format!("remove unnecessary dependency `{}` at `{}`", krate, raw));
-                            db.span_suggestion_with_style(
-                                DUMMY_SP,
-                                "raw extern location",
-                                raw.clone(),
-                                Applicability::Unspecified,
-                                SuggestionStyle::CompletelyHidden,
-                            );
-                            Json::String(raw)
-                        }
-                    };
-                    db.tool_only_suggestion_with_metadata(
-                        "json extern location",
-                        Applicability::Unspecified,
-                        json
-                    );
-                }
                 BuiltinLintDiagnostics::ProcMacroBackCompat(note) => {
                     db.note(&note);
                 }
index 7447f9f64b7b100f9a8aec19c883ef6d0a2a2145..b4262f184c8c43bc294cdfab261af6dd83872976 100644 (file)
@@ -158,7 +158,7 @@ fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, span: Span, id: ast::NodeId) {
 
         // Explicitly check for lints associated with 'closure_id', since
         // it does not have a corresponding AST node
-        if let ast_visit::FnKind::Fn(_, _, sig, _, _) = fk {
+        if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
             if let ast::Async::Yes { closure_id, .. } = sig.header.asyncness {
                 self.check_id(closure_id);
             }
@@ -284,6 +284,11 @@ fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
         ast_visit::walk_path(self, p);
     }
 
+    fn visit_path_segment(&mut self, path_span: Span, s: &'a ast::PathSegment) {
+        self.check_id(s.id);
+        ast_visit::walk_path_segment(self, path_span, s);
+    }
+
     fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
         run_early_pass!(self, check_attribute, attr);
     }
index 031b01af5dd95e44056b25920d7d3e3b5960d67f..f590172af4f9ccf8c2b33e456b6be0fd4dec2ea6 100644 (file)
@@ -8,8 +8,8 @@
 use rustc_ast::{AttrId, Attribute};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_error_messages::MultiSpan;
+use rustc_hir::HashStableContext;
 use rustc_hir::HirId;
-use rustc_serialize::json::Json;
 use rustc_span::edition::Edition;
 use rustc_span::{sym, symbol::Ident, Span, Symbol};
 use rustc_target::spec::abi::Abi;
@@ -147,7 +147,7 @@ fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
 /// Setting for how to handle a lint.
 ///
 /// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
-#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
 pub enum Level {
     /// The `allow` level will not issue any message.
     Allow,
@@ -175,8 +175,6 @@ pub enum Level {
     Forbid,
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(Level);
-
 impl Level {
     /// Converts a level to a lower-case string.
     pub fn as_str(self) -> &'static str {
@@ -403,13 +401,6 @@ fn to_stable_hash_key(&self, _: &HCX) -> &'static str {
     }
 }
 
-// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency
-#[derive(PartialEq, Debug)]
-pub enum ExternDepSpec {
-    Json(Json),
-    Raw(String),
-}
-
 // This could be a closure, but then implementing derive trait
 // becomes hacky (and it gets allocated).
 #[derive(Debug)]
@@ -418,6 +409,7 @@ pub enum BuiltinLintDiagnostics {
     AbsPathWithModule(Span),
     ProcMacroDeriveResolutionFallback(Span),
     MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
+    ElidedLifetimesInPaths(usize, Span, bool, Span),
     UnknownCrateTypes(Span, String, String),
     UnusedImports(String, Vec<(Span, String)>, Option<Span>),
     RedundantImport(Vec<(Span, bool)>, Ident),
@@ -427,7 +419,6 @@ pub enum BuiltinLintDiagnostics {
     UnusedBuiltinAttribute { attr_name: Symbol, macro_name: String, invoc_span: Span },
     PatternsInFnsWithoutBody(Span, Ident),
     LegacyDeriveHelpers(Span),
-    ExternDepSpec(String, ExternDepSpec),
     ProcMacroBackCompat(String),
     OrPatternsBackCompat(Span, String),
     ReservedPrefix(Span),
index 46f698f6f9b819ef793934c319031b6e2bab8372..ff7506979fc3445c9ed78c834ebad5b35246aa34 100644 (file)
 /// # extern crate rust_middle;
 /// # use rustc_middle::ty::Ty;
 /// #[derive(SessionDiagnostic)]
-/// #[error(code = "E0505", slug = "move-out-of-borrow-error")]
+/// #[error(code = "E0505", slug = "borrowck-move-out-of-borrow")]
 /// pub struct MoveOutOfBorrowError<'tcx> {
 ///     pub name: Ident,
 ///     pub ty: Ty<'tcx>,
 ///     #[primary_span]
-///     #[label = "cannot move out of borrow"]
+///     #[label]
 ///     pub span: Span,
-///     #[label = "`{ty}` first borrowed here"]
-///     pub other_span: Span,
-///     #[suggestion(message = "consider cloning here", code = "{name}.clone()")]
-///     pub opt_sugg: Option<(Span, Applicability)>
+///     #[label = "first-borrow-label"]
+///     pub first_borrow_span: Span,
+///     #[suggestion(code = "{name}.clone()")]
+///     pub clone_sugg: Option<(Span, Applicability)>
 /// }
 /// ```
 ///
+/// ```fluent
+/// move-out-of-borrow = cannot move out of {$name} because it is borrowed
+///     .label = cannot move out of borrow
+///     .first-borrow-label = `{$ty}` first borrowed here
+///     .suggestion = consider cloning here
+/// ```
+///
 /// Then, later, to emit the error:
 ///
 /// ```ignore (pseudo-rust)
 ///     expected,
 ///     actual,
 ///     span,
-///     other_span,
-///     opt_sugg: Some(suggestion, Applicability::MachineApplicable),
+///     first_borrow_span,
+///     clone_sugg: Some(suggestion, Applicability::MachineApplicable),
 /// });
 /// ```
+///
+/// See rustc dev guide for more examples on using the `#[derive(SessionDiagnostic)]`:
+/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html>
 pub fn session_diagnostic_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
     // Names for the diagnostic we build and the session we build it from.
     let diag = format_ident!("diag");
index 566d27212d08dcbfee7b44a6f50553222b1b69d5..e5d0cd289255206ebc6d72dd7530a090f6058786 100644 (file)
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::TyCtxt;
-use rustc_serialize::json::ToJson;
 use rustc_session::config::{self, CrateType, ExternLocation};
 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate};
 use rustc_session::cstore::{ExternCrateSource, MetadataLoaderDyn};
-use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec};
+use rustc_session::lint;
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_session::Session;
@@ -27,7 +26,6 @@
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 
 use proc_macro::bridge::client::ProcMacro;
-use std::collections::BTreeMap;
 use std::ops::Fn;
 use std::path::Path;
 use std::{cmp, env};
@@ -920,20 +918,7 @@ fn report_unused_deps(&mut self, krate: &ast::Crate) {
                 continue;
             }
 
-            let diag = match self.sess.opts.extern_dep_specs.get(name) {
-                Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()),
-                None => {
-                    // If we don't have a specific location, provide a json encoding of the `--extern`
-                    // option.
-                    let meta: BTreeMap<String, String> =
-                        std::iter::once(("name".to_string(), name.to_string())).collect();
-                    BuiltinLintDiagnostics::ExternDepSpec(
-                        name.clone(),
-                        ExternDepSpec::Json(meta.to_json()),
-                    )
-                }
-            };
-            self.sess.parse_sess.buffer_lint_with_diagnostic(
+            self.sess.parse_sess.buffer_lint(
                     lint::builtin::UNUSED_CRATE_DEPENDENCIES,
                     span,
                     ast::CRATE_NODE_ID,
@@ -942,7 +927,6 @@ fn report_unused_deps(&mut self, krate: &ast::Crate) {
                         name,
                         self.local_crate_name,
                         name),
-                    diag,
                 );
         }
     }
index 611694a0d304201cb4fc3d734bee720fec66469c..77afa7b4a5cf0a7f1d94b90c17d47046c37caf97 100644 (file)
@@ -28,6 +28,7 @@
 use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::GeneratorDiagnosticData;
 use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
 use rustc_serialize::{opaque, Decodable, Decoder};
 use rustc_session::cstore::{
@@ -1725,6 +1726,28 @@ fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] {
                 .collect()
         })
     }
+
+    fn get_generator_diagnostic_data(
+        self,
+        tcx: TyCtxt<'tcx>,
+        id: DefIndex,
+    ) -> Option<GeneratorDiagnosticData<'tcx>> {
+        self.root
+            .tables
+            .generator_diagnostic_data
+            .get(self, id)
+            .map(|param| param.decode((self, tcx)))
+            .map(|generator_data| GeneratorDiagnosticData {
+                generator_interior_types: generator_data.generator_interior_types,
+                hir_owner: generator_data.hir_owner,
+                nodes_types: generator_data.nodes_types,
+                adjustments: generator_data.adjustments,
+            })
+    }
+
+    fn get_may_have_doc_links(self, index: DefIndex) -> bool {
+        self.root.tables.may_have_doc_links.get(self, index).is_some()
+    }
 }
 
 impl CrateMetadata {
index 63bf929fb86393a7bc4b102dcd54dca606bb9865..1156a78e8a94afb4adfd64de62744ad15ce0b3b7 100644 (file)
@@ -5,7 +5,7 @@
 
 use rustc_ast as ast;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
@@ -246,6 +246,7 @@ fn into_args(self) -> (DefId, SimplifiedType) {
 
     crate_extern_paths => { cdata.source().paths().cloned().collect() }
     expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
+    generator_diagnostic_data => { cdata.get_generator_diagnostic_data(tcx, def_id.index) }
 }
 
 pub(in crate::rmeta) fn provide(providers: &mut Providers) {
@@ -324,7 +325,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                     continue;
                 }
 
-                bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
+                bfs_queue.push_back(cnum.as_def_id());
             }
 
             let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
@@ -530,6 +531,18 @@ pub fn incoherent_impls_in_crate_untracked(
     ) -> impl Iterator<Item = DefId> + '_ {
         self.get_crate_data(cnum).get_all_incoherent_impls()
     }
+
+    pub fn associated_item_def_ids_untracked<'a>(
+        &'a self,
+        def_id: DefId,
+        sess: &'a Session,
+    ) -> impl Iterator<Item = DefId> + 'a {
+        self.get_crate_data(def_id.krate).get_associated_item_def_ids(def_id.index, sess)
+    }
+
+    pub fn may_have_doc_links_untracked(&self, def_id: DefId) -> bool {
+        self.get_crate_data(def_id.krate).get_may_have_doc_links(def_id.index)
+    }
 }
 
 impl CrateStore for CStore {
index 6a8d4e037544c6d8e77d1fe0aaa08c448b01e2f0..f485e09913e9d0d054179c1fab53db12167bd4e0 100644 (file)
@@ -977,6 +977,14 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    fn encode_attrs(&mut self, def_id: DefId) {
+        let attrs = self.tcx.get_attrs(def_id);
+        record!(self.tables.attributes[def_id] <- attrs);
+        if attrs.iter().any(|attr| attr.may_have_doc_links()) {
+            self.tables.may_have_doc_links.set(def_id.index, ());
+        }
+    }
+
     fn encode_def_ids(&mut self) {
         if self.is_proc_macro {
             return;
@@ -989,7 +997,7 @@ fn encode_def_ids(&mut self) {
             let Some(def_kind) = def_kind else { continue };
             self.tables.opt_def_kind.set(def_id.index, def_kind);
             record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
-            record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
+            self.encode_attrs(def_id);
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
             if should_encode_visibility(def_kind) {
                 record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
@@ -1556,16 +1564,17 @@ fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, enco
     fn encode_info_for_closure(&mut self, hir_id: hir::HirId) {
         let def_id = self.tcx.hir().local_def_id(hir_id);
         debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
-
         // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
         // including on the signature, which is inferred in `typeck.
-        let ty = self.tcx.typeck(def_id).node_type(hir_id);
-
+        let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id);
+        let ty = typeck_result.node_type(hir_id);
         match ty.kind() {
             ty::Generator(..) => {
                 let data = self.tcx.generator_kind(def_id).unwrap();
+                let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
                 record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator);
                 record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
+                record!(self.tables.generator_diagnostic_data[def_id.to_def_id()]  <- generator_diagnostic_data);
             }
 
             ty::Closure(..) => {
@@ -1639,7 +1648,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
             let hir = tcx.hir();
 
             let proc_macro_decls_static = tcx.proc_macro_decls_static(()).unwrap().local_def_index;
-            let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX));
+            let stability = tcx.lookup_stability(CRATE_DEF_ID);
             let macros =
                 self.lazy(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
             let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
@@ -1650,7 +1659,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
 
             self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
-            record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id()));
+            self.encode_attrs(LOCAL_CRATE.as_def_id());
             record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
             if let Some(stability) = stability {
                 record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
@@ -1691,7 +1700,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
                 let def_id = id.to_def_id();
                 self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
                 record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
-                record!(self.tables.attributes[def_id] <- attrs);
+                self.encode_attrs(def_id);
                 record!(self.tables.def_keys[def_id] <- def_key);
                 record!(self.tables.def_ident_span[def_id] <- span);
                 record!(self.tables.def_span[def_id] <- span);
index 43ccfc64e0563978adf8f7c7b6dfd7a083ff3c2a..f1498665ff3853bcf92b7dde96f58a46dce7905a 100644 (file)
@@ -19,6 +19,7 @@
 use rustc_middle::thir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::GeneratorDiagnosticData;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
@@ -358,6 +359,8 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     def_keys: Table<DefIndex, Lazy<DefKey>>,
     def_path_hashes: Table<DefIndex, DefPathHash>,
     proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
+    generator_diagnostic_data: Table<DefIndex, Lazy<GeneratorDiagnosticData<'tcx>>>,
+    may_have_doc_links: Table<DefIndex, ()>,
 }
 
 #[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
index 7a23cba536a0a18bfdfbc69b4fb3cda5333aacad..53fc2efe00bb79c230515dd319c9246ddca47c99 100644 (file)
@@ -186,6 +186,20 @@ impl FixedSizeEncoding for Option<RawDefId> {
     }
 }
 
+impl FixedSizeEncoding for Option<()> {
+    type ByteArray = [u8; 1];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 1]) -> Self {
+        (b[0] != 0).then(|| ())
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 1]) {
+        b[0] = self.is_some() as u8
+    }
+}
+
 // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
 // generic `Lazy<T>` impl, but in the general case we might not need / want to
 // fit every `usize` in `u32`.
index d20be0a34d2d5f525f456c9c604d3426678e8d2f..8402ca3028cce500665ac2091c230f8cdf91183d 100644 (file)
@@ -60,7 +60,7 @@
 use crate::ty::TyCtxt;
 
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::definitions::DefPathHash;
 use rustc_hir::HirId;
 use rustc_query_system::dep_graph::FingerprintStyle;
@@ -366,7 +366,7 @@ fn fingerprint_style() -> FingerprintStyle {
 
     #[inline(always)]
     fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
-        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
+        let def_id = self.as_def_id();
         def_id.to_fingerprint(tcx)
     }
 
index fd6e241346db8e9aeddada8789c59fac6736f03d..758658c3d8c941c8f07081001c9493590f28b955 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_feature::GateIssue;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self, HirId};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
@@ -370,8 +370,7 @@ pub fn eval_stability(
             };
         }
 
-        let is_staged_api =
-            self.lookup_stability(DefId { index: CRATE_DEF_INDEX, ..def_id }).is_some();
+        let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
         if !is_staged_api {
             return EvalResult::Allow;
         }
index 438f356f072c6d863e093668d022327785efb3d9..c628406064fb63e4703bf503d75519a680c07534 100644 (file)
@@ -269,7 +269,7 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
     /// `get_bytes_with_uninit_and_ptr` instead,
     ///
     /// This function also guarantees that the resulting pointer will remain stable
-    /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
+    /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies
     /// on that.
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
@@ -429,8 +429,7 @@ pub fn write_scalar(
         let val = match val {
             ScalarMaybeUninit::Scalar(scalar) => scalar,
             ScalarMaybeUninit::Uninit => {
-                self.mark_init(range, false);
-                return Ok(());
+                return self.write_uninit(cx, range);
             }
         };
 
@@ -455,6 +454,13 @@ pub fn write_scalar(
 
         Ok(())
     }
+
+    /// Write "uninit" to the given memory range.
+    pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
+        self.mark_init(range, false);
+        self.clear_relocations(cx, range)?;
+        return Ok(());
+    }
 }
 
 /// Relocations.
@@ -509,6 +515,9 @@ fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> A
             if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
                 return Err(AllocError::PartialPointerOverwrite(first));
             }
+            warn!(
+                "Partial pointer overwrite! De-initializing memory at offsets {first:?}..{start:?}."
+            );
             self.init_mask.set_range(first, start, false);
         }
         if last > end {
@@ -517,10 +526,15 @@ fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> A
                     last - cx.data_layout().pointer_size,
                 ));
             }
+            warn!(
+                "Partial pointer overwrite! De-initializing memory at offsets {end:?}..{last:?}."
+            );
             self.init_mask.set_range(end, last, false);
         }
 
         // Forget all the relocations.
+        // Since relocations do not overlap, we know that removing until `last` (exclusive) is fine,
+        // i.e., this will not remove any other relocations just after the ones we care about.
         self.relocations.0.remove_range(first..last);
 
         Ok(())
@@ -561,8 +575,10 @@ fn deref(&self) -> &Self::Target {
 }
 
 /// A partial, owned list of relocations to transfer into another allocation.
+///
+/// Offsets are already adjusted to the destination allocation.
 pub struct AllocationRelocations<Tag> {
-    relative_relocations: Vec<(Size, Tag)>,
+    dest_relocations: Vec<(Size, Tag)>,
 }
 
 impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
@@ -575,12 +591,17 @@ pub fn prepare_relocation_copy(
     ) -> AllocationRelocations<Tag> {
         let relocations = self.get_relocations(cx, src);
         if relocations.is_empty() {
-            return AllocationRelocations { relative_relocations: Vec::new() };
+            return AllocationRelocations { dest_relocations: Vec::new() };
         }
 
         let size = src.size;
         let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize));
 
+        // If `count` is large, this is rather wasteful -- we are allocating a big array here, which
+        // is mostly filled with redundant information since it's just N copies of the same `Tag`s
+        // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range`
+        // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces
+        // the right sequence of relocations for all N copies.
         for i in 0..count {
             new_relocations.extend(relocations.iter().map(|&(offset, reloc)| {
                 // compute offset for current repetition
@@ -593,14 +614,17 @@ pub fn prepare_relocation_copy(
             }));
         }
 
-        AllocationRelocations { relative_relocations: new_relocations }
+        AllocationRelocations { dest_relocations: new_relocations }
     }
 
     /// Applies a relocation copy.
     /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected
     /// to be clear of relocations.
+    ///
+    /// This is dangerous to use as it can violate internal `Allocation` invariants!
+    /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
     pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Tag>) {
-        self.relocations.0.insert_presorted(relocations.relative_relocations);
+        self.relocations.0.insert_presorted(relocations.dest_relocations);
     }
 }
 
@@ -1056,7 +1080,7 @@ fn check_init(&self, range: AllocRange) -> AllocResult {
         })
     }
 
-    pub fn mark_init(&mut self, range: AllocRange, is_init: bool) {
+    fn mark_init(&mut self, range: AllocRange, is_init: bool) {
         if range.size.bytes() == 0 {
             return;
         }
@@ -1118,6 +1142,9 @@ pub fn compress_uninit_range(&self, range: AllocRange) -> InitMaskCompressed {
     }
 
     /// Applies multiple instances of the run-length encoding to the initialization mask.
+    ///
+    /// This is dangerous to use as it can violate internal `Allocation` invariants!
+    /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
     pub fn mark_compressed_init_range(
         &mut self,
         defined: &InitMaskCompressed,
index 813c0912f539679db80f57d1ec455580c0ccb1de..c71aea417eca0143279c565a813ed0da9203dabc 100644 (file)
@@ -163,6 +163,9 @@ pub struct Pointer<Tag = AllocId> {
 }
 
 static_assert_size!(Pointer, 16);
+// `Option<Tag>` pointers are also passed around quite a bit
+// (but not stored in permanent machine state).
+static_assert_size!(Pointer<Option<AllocId>>, 16);
 
 // We want the `Debug` output to be readable as it is used by `derive(Debug)` for
 // all the Miri types.
@@ -198,12 +201,26 @@ fn from(ptr: Pointer<Tag>) -> Self {
 }
 
 impl<Tag> Pointer<Option<Tag>> {
+    /// Convert this pointer that *might* have a tag into a pointer that *definitely* has a tag, or
+    /// an absolute address.
+    ///
+    /// This is rarely what you want; call `ptr_try_get_alloc_id` instead.
     pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> {
         match self.provenance {
             Some(tag) => Ok(Pointer::new(tag, self.offset)),
             None => Err(self.offset),
         }
     }
+
+    /// Returns the absolute address the pointer points to.
+    /// Only works if Tag::OFFSET_IS_ADDR is true!
+    pub fn addr(self) -> Size
+    where
+        Tag: Provenance,
+    {
+        assert!(Tag::OFFSET_IS_ADDR);
+        self.offset
+    }
 }
 
 impl<Tag> Pointer<Option<Tag>> {
index 49769b7ae3d89cdbf58dfb875d8e0eda79cbb882..4f4b6cf704fa9d75e147c0a5462ef21dcfcab541 100644 (file)
@@ -15,7 +15,7 @@
 
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::{self, GeneratorKind};
 use rustc_hir::{self as hir, HirId};
 use rustc_session::Session;
@@ -385,7 +385,7 @@ pub fn new(
     pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
         let mut body = Body {
             phase: MirPhase::Built,
-            source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
+            source: MirSource::item(CRATE_DEF_ID.to_def_id()),
             basic_blocks,
             source_scopes: IndexVec::new(),
             generator: None,
index 69dac03883940de4d24ea32afa0a04f5bc3b9255..b7f695da544f1db26a260a1c26d2e3a63cf42b64 100644 (file)
@@ -851,6 +851,7 @@ fn write_allocation_bytes<'tcx, Tag: Provenance, Extra>(
         }
         if let Some(&tag) = alloc.relocations().get(&i) {
             // Memory with a relocation must be defined
+            assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok());
             let j = i.bytes_usize();
             let offset = alloc
                 .inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
index 999cb9f30b8aa642fbc8e17c80f6cc8c2fab0c97..78a3383243306b42187e2cf48fab7dea0867e254 100644 (file)
         eval_always
         desc { "computing the backend features for CLI flags" }
     }
+
+    query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> {
+        storage(ArenaCacheSelector<'tcx>)
+        desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
+        separate_provide_extern
+    }
 }
index 4b7c1d44cea29f6c6a531fd8519720e9e9eb836d..7af7eb4f5ecfd868ebf1408ac90aed3027c08b93 100644 (file)
@@ -44,10 +44,12 @@ pub struct ConstS<'tcx> {
 static_assert_size!(ConstS<'_>, 48);
 
 impl<'tcx> Const<'tcx> {
+    #[inline]
     pub fn ty(self) -> Ty<'tcx> {
         self.0.ty
     }
 
+    #[inline]
     pub fn val(self) -> ConstKind<'tcx> {
         self.0.val
     }
index 4e6be84ad7f8ff6f990a155de5be959c7d6d0772..30fe3ffa7e3c46c0b438269ebf430942b85397c8 100644 (file)
@@ -367,6 +367,16 @@ pub struct GeneratorInteriorTypeCause<'tcx> {
     pub expr: Option<hir::HirId>,
 }
 
+// This type holds diagnostic information on generators and async functions across crate boundaries
+// and is used to provide better error messages
+#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
+pub struct GeneratorDiagnosticData<'tcx> {
+    pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+    pub hir_owner: DefId,
+    pub nodes_types: ItemLocalMap<Ty<'tcx>>,
+    pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+}
+
 #[derive(TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct TypeckResults<'tcx> {
     /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
@@ -623,6 +633,28 @@ pub fn node_types_mut(&mut self) -> LocalTableInContextMut<'_, Ty<'tcx>> {
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
     }
 
+    pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
+        let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
+            vec.iter()
+                .map(|item| {
+                    GeneratorInteriorTypeCause {
+                        ty: item.ty,
+                        span: item.span,
+                        scope_span: item.scope_span,
+                        yield_span: item.yield_span,
+                        expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
+                    }
+                })
+                .collect::<Vec<_>>()
+        });
+        GeneratorDiagnosticData {
+            generator_interior_types: generator_interior_type,
+            hir_owner: self.hir_owner.to_def_id(),
+            nodes_types: self.node_types.clone(),
+            adjustments: self.adjustments.clone(),
+        }
+    }
+
     pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
         self.node_type_opt(id).unwrap_or_else(|| {
             bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
index c2accea11ba2aee2bb6604ba30d8b7e7e2f768ee..d59fdf47904f7939109376f398623796c0b66516 100644 (file)
@@ -36,7 +36,7 @@
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_ID};
 use rustc_hir::Node;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
@@ -67,8 +67,9 @@
 };
 pub use self::context::{
     tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-    CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt,
-    Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex,
+    CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+    GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
+    UserTypeAnnotationIndex,
 };
 pub use self::instance::{Instance, InstanceDef};
 pub use self::list::List;
@@ -319,7 +320,7 @@ impl Visibility {
     pub fn from_hir(visibility: &hir::Visibility<'_>, id: hir::HirId, tcx: TyCtxt<'_>) -> Self {
         match visibility.node {
             hir::VisibilityKind::Public => Visibility::Public,
-            hir::VisibilityKind::Crate(_) => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)),
+            hir::VisibilityKind::Crate(_) => Visibility::Restricted(CRATE_DEF_ID.to_def_id()),
             hir::VisibilityKind::Restricted { ref path, .. } => match path.res {
                 // If there is no resolution, `resolve` will have already reported an error, so
                 // assume that the visibility is public to avoid reporting more privacy errors.
@@ -1992,8 +1993,8 @@ pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'
     }
 
     fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
-        if def_id.index == CRATE_DEF_INDEX {
-            Some(self.crate_name(def_id.krate))
+        if let Some(cnum) = def_id.as_crate_root() {
+            Some(self.crate_name(cnum))
         } else {
             let def_key = self.def_key(def_id);
             match def_key.disambiguated_data.data {
index cac46ba25fe6bc3db7397e12a3e5bd7f5c07d4b0..38362a4cbb92529a8a164ba137096bd1cda4e70a 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
-use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
 use rustc_session::config::TrimmedDefPaths;
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
@@ -335,9 +335,7 @@ fn try_print_visible_def_path_recur(
 
         // If `def_id` is a direct or injected extern crate, return the
         // path to the crate followed by the path to the item within the crate.
-        if def_id.index == CRATE_DEF_INDEX {
-            let cnum = def_id.krate;
-
+        if let Some(cnum) = def_id.as_crate_root() {
             if cnum == LOCAL_CRATE {
                 return Ok((self.path_crate(cnum)?, true));
             }
@@ -2227,11 +2225,11 @@ fn name_by_region_index(index: usize) -> Symbol {
                     ty::BrNamed(_, _) => br.kind,
                     ty::BrAnon(i) => {
                         let name = region_map[&(i + 1)];
-                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                     }
                     ty::BrEnv => {
                         let name = region_map[&0];
-                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                     }
                 };
                 self.tcx.mk_region(ty::ReLateBound(
@@ -2257,7 +2255,7 @@ fn name_by_region_index(index: usize) -> Symbol {
                             }
                         };
                         do_continue(&mut self, name);
-                        ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+                        ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
                     }
                 };
                 tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
@@ -2697,7 +2695,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
     let mut seen_defs: DefIdSet = Default::default();
 
     for &cnum in tcx.crates(()).iter() {
-        let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+        let def_id = cnum.as_def_id();
 
         // Ignore crates that are not direct dependencies.
         match tcx.extern_crate(def_id) {
index 9e48c569c253a593f1bb0dd5dd1bd3003eb87578..7629d7a8259b8b841598e95c2c70519f186a04cc 100644 (file)
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
+use crate::ty::GeneratorDiagnosticData;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use rustc_ast as ast;
 use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Limits;
-use rustc_target::abi;
-use rustc_target::spec::PanicStrategy;
-
-use rustc_ast as ast;
-use rustc_attr as attr;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
+use rustc_target::spec::PanicStrategy;
 use std::ops::Deref;
 use std::path::PathBuf;
 use std::sync::Arc;
index d9b55563996bab580d050db2d2d9d4d517e244ed..4c1160e21fec2bf715d8257f46082faba65f2916 100644 (file)
@@ -61,7 +61,7 @@ fn relate_item_substs(
 
         let tcx = self.tcx();
         let opt_variances = tcx.variances_of(item_def_id);
-        relate_substs(self, Some((item_def_id, opt_variances)), a_subst, b_subst)
+        relate_substs_with_variances(self, item_def_id, opt_variances, a_subst, b_subst)
     }
 
     /// Switch variance for the purpose of relating `a` and `b`.
@@ -135,29 +135,34 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
     }
 }
 
+#[inline]
 pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
-    variances: Option<(DefId, &[ty::Variance])>,
+    a_subst: SubstsRef<'tcx>,
+    b_subst: SubstsRef<'tcx>,
+) -> RelateResult<'tcx, SubstsRef<'tcx>> {
+    relation.tcx().mk_substs(iter::zip(a_subst, b_subst).map(|(a, b)| {
+        relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)
+    }))
+}
+
+pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
+    relation: &mut R,
+    ty_def_id: DefId,
+    variances: &[ty::Variance],
     a_subst: SubstsRef<'tcx>,
     b_subst: SubstsRef<'tcx>,
 ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
     let tcx = relation.tcx();
-    let mut cached_ty = None;
 
+    let mut cached_ty = None;
     let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
-        let (variance, variance_info) = match variances {
-            Some((ty_def_id, variances)) => {
-                let variance = variances[i];
-                let variance_info = if variance == ty::Invariant {
-                    let ty = *cached_ty
-                        .get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
-                    ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
-                } else {
-                    ty::VarianceDiagInfo::default()
-                };
-                (variance, variance_info)
-            }
-            None => (ty::Invariant, ty::VarianceDiagInfo::default()),
+        let variance = variances[i];
+        let variance_info = if variance == ty::Invariant {
+            let ty = *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+            ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
+        } else {
+            ty::VarianceDiagInfo::default()
         };
         relation.relate_with_variance(variance, variance_info, a, b)
     });
@@ -318,7 +323,7 @@ fn relate<R: TypeRelation<'tcx>>(
         if a.def_id != b.def_id {
             Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
         } else {
-            let substs = relate_substs(relation, None, a.substs, b.substs)?;
+            let substs = relate_substs(relation, a.substs, b.substs)?;
             Ok(ty::TraitRef { def_id: a.def_id, substs })
         }
     }
@@ -334,7 +339,7 @@ fn relate<R: TypeRelation<'tcx>>(
         if a.def_id != b.def_id {
             Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
         } else {
-            let substs = relate_substs(relation, None, a.substs, b.substs)?;
+            let substs = relate_substs(relation, a.substs, b.substs)?;
             Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs })
         }
     }
@@ -554,7 +559,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
         (&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
             if a_def_id == b_def_id =>
         {
-            let substs = relate_substs(relation, None, a_substs, b_substs)?;
+            let substs = relate_substs(relation, a_substs, b_substs)?;
             Ok(tcx.mk_opaque(a_def_id, substs))
         }
 
@@ -742,7 +747,7 @@ fn relate<R: TypeRelation<'tcx>>(
         a: ty::ClosureSubsts<'tcx>,
         b: ty::ClosureSubsts<'tcx>,
     ) -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> {
-        let substs = relate_substs(relation, None, a.substs, b.substs)?;
+        let substs = relate_substs(relation, a.substs, b.substs)?;
         Ok(ty::ClosureSubsts { substs })
     }
 }
@@ -753,7 +758,7 @@ fn relate<R: TypeRelation<'tcx>>(
         a: ty::GeneratorSubsts<'tcx>,
         b: ty::GeneratorSubsts<'tcx>,
     ) -> RelateResult<'tcx, ty::GeneratorSubsts<'tcx>> {
-        let substs = relate_substs(relation, None, a.substs, b.substs)?;
+        let substs = relate_substs(relation, a.substs, b.substs)?;
         Ok(ty::GeneratorSubsts { substs })
     }
 }
@@ -764,7 +769,7 @@ fn relate<R: TypeRelation<'tcx>>(
         a: SubstsRef<'tcx>,
         b: SubstsRef<'tcx>,
     ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
-        relate_substs(relation, None, a, b)
+        relate_substs(relation, a, b)
     }
 }
 
index 5c7910db362d290c2257e04daf031bdebffb8436..4ef6ff1835ffd022ccddc0a098c3c2496aec2640 100644 (file)
@@ -10,7 +10,6 @@
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
-use rustc_hir::def_id::CRATE_DEF_INDEX;
 use rustc_index::vec::{Idx, IndexVec};
 
 use std::fmt;
@@ -71,7 +70,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
             ty::BrNamed(did, name) => {
-                if did.index == CRATE_DEF_INDEX {
+                if did.is_crate_root() {
                     write!(f, "BrNamed({})", name)
                 } else {
                     write!(f, "BrNamed({:?}, {})", did, name)
index a04ac33827424ab35fa1562077e3518c18103672..cee657e9da244fdc39f5358f463d5cf1f8fa024c 100644 (file)
@@ -255,10 +255,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         func: fun,
                         args,
                         cleanup: None,
-                        // FIXME(varkor): replace this with an uninhabitedness-based check.
-                        // This requires getting access to the current module to call
-                        // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
-                        destination: if expr.ty.is_never() {
+                        // The presence or absence of a return edge affects control-flow sensitive
+                        // MIR checks and ultimately whether code is accepted or not. We can only
+                        // omit the return edge if a return type is visibly uninhabited to a module
+                        // that makes the call.
+                        destination: if this.tcx.is_ty_uninhabited_from(
+                            this.parent_module,
+                            expr.ty,
+                            this.param_env,
+                        ) {
                             None
                         } else {
                             Some((destination, success))
index 901635dc488a7c42fa99f9c472a3b900fc0fd94d..3c51f7918627437bcd9b8f3d479941abed490f4c 100644 (file)
@@ -350,6 +350,7 @@ struct Builder<'a, 'tcx> {
 
     def_id: DefId,
     hir_id: hir::HirId,
+    parent_module: DefId,
     check_overflow: bool,
     fn_span: Span,
     arg_count: usize,
@@ -807,15 +808,17 @@ fn new(
         );
 
         let lint_level = LintLevel::Explicit(hir_id);
+        let param_env = tcx.param_env(def.did);
         let mut builder = Builder {
             thir,
             tcx,
             infcx,
             typeck_results: tcx.typeck_opt_const_arg(def),
             region_scope_tree: tcx.region_scope_tree(def.did),
-            param_env: tcx.param_env(def.did),
+            param_env,
             def_id: def.did.to_def_id(),
             hir_id,
+            parent_module: tcx.parent_module(hir_id).to_def_id(),
             check_overflow,
             cfg: CFG { basic_blocks: IndexVec::new() },
             fn_span: span,
index c4ffb19f87a91a6595a193c858b0c4fdbd47496b..167741988798862b79e05f008190fa65b38f46ae 100644 (file)
@@ -2,7 +2,7 @@
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathDataName;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::exported_symbols::SymbolExportLevel;
@@ -335,10 +335,10 @@ fn compute_codegen_unit_name(
     let mut cgu_def_id = None;
     // Walk backwards from the item we want to find the module for.
     loop {
-        if current_def_id.index == CRATE_DEF_INDEX {
+        if current_def_id.is_crate_root() {
             if cgu_def_id.is_none() {
                 // If we have not found a module yet, take the crate root.
-                cgu_def_id = Some(DefId { krate: def_id.krate, index: CRATE_DEF_INDEX });
+                cgu_def_id = Some(def_id.krate.as_def_id());
             }
             break;
         } else if tcx.def_kind(current_def_id) == DefKind::Mod {
index 5ee9c339bb7aa9067c5d24726f65110b2a78fd8b..02749088c3139e50e9745dee12243021de5a73ac 100644 (file)
@@ -100,21 +100,16 @@ struct LazyTokenStreamImpl {
 
 impl CreateTokenStream for LazyTokenStreamImpl {
     fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
-        // The token produced by the final call to `{,inlined_}next` or
-        // `{,inlined_}next_desugared` was not actually consumed by the
-        // callback. The combination of chaining the initial token and using
-        // `take` produces the desired result - we produce an empty
-        // `TokenStream` if no calls were made, and omit the final token
-        // otherwise.
+        // The token produced by the final call to `{,inlined_}next` was not
+        // actually consumed by the callback. The combination of chaining the
+        // initial token and using `take` produces the desired result - we
+        // produce an empty `TokenStream` if no calls were made, and omit the
+        // final token otherwise.
         let mut cursor_snapshot = self.cursor_snapshot.clone();
         let tokens =
             std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1))
                 .chain((0..self.num_calls).map(|_| {
-                    let token = if cursor_snapshot.desugar_doc_comments {
-                        cursor_snapshot.next_desugared()
-                    } else {
-                        cursor_snapshot.next()
-                    };
+                    let token = cursor_snapshot.next(cursor_snapshot.desugar_doc_comments);
                     (FlatToken::Token(token.0), token.1)
                 }))
                 .take(self.num_calls);
index cb6be8f412cf54cf7cd9d2ddb4deecae119f9f14..1686c5873e1833f4b5627fd627300aad055e950d 100644 (file)
@@ -123,8 +123,8 @@ pub struct Parser<'a> {
     pub capture_cfg: bool,
     restrictions: Restrictions,
     expected_tokens: Vec<TokenType>,
-    // Important: This must only be advanced from `next_tok`
-    // to ensure that `token_cursor.num_next_calls` is updated properly
+    // Important: This must only be advanced from `bump` to ensure that
+    // `token_cursor.num_next_calls` is updated properly.
     token_cursor: TokenCursor,
     desugar_doc_comments: bool,
     /// This field is used to keep track of how many left angle brackets we have seen. This is
@@ -150,6 +150,11 @@ pub struct Parser<'a> {
     pub current_closure: Option<ClosureSpans>,
 }
 
+// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
+// it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Parser<'_>, 328);
+
 /// Stores span information about a closure.
 #[derive(Clone)]
 pub struct ClosureSpans {
@@ -203,12 +208,15 @@ fn drop(&mut self) {
 
 #[derive(Clone)]
 struct TokenCursor {
+    // The current (innermost) frame. `frame` and `stack` could be combined,
+    // but it's faster to have them separately to access `frame` directly
+    // rather than via something like `stack.last().unwrap()` or
+    // `stack[stack.len() - 1]`.
     frame: TokenCursorFrame,
+    // Additional frames that enclose `frame`.
     stack: Vec<TokenCursorFrame>,
     desugar_doc_comments: bool,
-    // Counts the number of calls to `{,inlined_}next` or
-    // `{,inlined_}next_desugared`, depending on whether
-    // `desugar_doc_comments` is set.
+    // Counts the number of calls to `{,inlined_}next`.
     num_next_calls: usize,
     // During parsing, we may sometimes need to 'unglue' a
     // glued token into two component tokens
@@ -238,73 +246,60 @@ struct TokenCursor {
 struct TokenCursorFrame {
     delim: token::DelimToken,
     span: DelimSpan,
-    open_delim: bool,
     tree_cursor: tokenstream::Cursor,
-    close_delim: bool,
 }
 
 impl TokenCursorFrame {
     fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream) -> Self {
-        TokenCursorFrame {
-            delim,
-            span,
-            open_delim: false,
-            tree_cursor: tts.into_trees(),
-            close_delim: false,
-        }
+        TokenCursorFrame { delim, span, tree_cursor: tts.into_trees() }
     }
 }
 
 impl TokenCursor {
-    fn next(&mut self) -> (Token, Spacing) {
-        self.inlined_next()
+    fn next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
+        self.inlined_next(desugar_doc_comments)
     }
 
     /// This always-inlined version should only be used on hot code paths.
     #[inline(always)]
-    fn inlined_next(&mut self) -> (Token, Spacing) {
+    fn inlined_next(&mut self, desugar_doc_comments: bool) -> (Token, Spacing) {
         loop {
-            let (tree, spacing) = if !self.frame.open_delim {
-                self.frame.open_delim = true;
-                TokenTree::open_tt(self.frame.span, self.frame.delim).into()
-            } else if let Some(tree) = self.frame.tree_cursor.next_with_spacing() {
-                tree
-            } else if !self.frame.close_delim {
-                self.frame.close_delim = true;
-                TokenTree::close_tt(self.frame.span, self.frame.delim).into()
+            // FIXME: we currently don't return `NoDelim` open/close delims. To fix #67062 we will
+            // need to, whereupon the `delim != DelimToken::NoDelim` conditions below can be
+            // removed, as well as the loop.
+            if let Some((tree, spacing)) = self.frame.tree_cursor.next_with_spacing_ref() {
+                match tree {
+                    &TokenTree::Token(ref token) => match (desugar_doc_comments, token) {
+                        (true, &Token { kind: token::DocComment(_, attr_style, data), span }) => {
+                            return self.desugar(attr_style, data, span);
+                        }
+                        _ => return (token.clone(), *spacing),
+                    },
+                    &TokenTree::Delimited(sp, delim, ref tts) => {
+                        // Set `open_delim` to true here because we deal with it immediately.
+                        let frame = TokenCursorFrame::new(sp, delim, tts.clone());
+                        self.stack.push(mem::replace(&mut self.frame, frame));
+                        if delim != DelimToken::NoDelim {
+                            return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone);
+                        }
+                        // No open delimeter to return; continue on to the next iteration.
+                    }
+                };
             } else if let Some(frame) = self.stack.pop() {
+                let delim = self.frame.delim;
+                let span = self.frame.span;
                 self.frame = frame;
-                continue;
-            } else {
-                (TokenTree::Token(Token::new(token::Eof, DUMMY_SP)), Spacing::Alone)
-            };
-
-            match tree {
-                TokenTree::Token(token) => {
-                    return (token, spacing);
-                }
-                TokenTree::Delimited(sp, delim, tts) => {
-                    let frame = TokenCursorFrame::new(sp, delim, tts);
-                    self.stack.push(mem::replace(&mut self.frame, frame));
+                if delim != DelimToken::NoDelim {
+                    return (Token::new(token::CloseDelim(delim), span.close), Spacing::Alone);
                 }
+                // No close delimiter to return; continue on to the next iteration.
+            } else {
+                return (Token::new(token::Eof, DUMMY_SP), Spacing::Alone);
             }
         }
     }
 
-    fn next_desugared(&mut self) -> (Token, Spacing) {
-        self.inlined_next_desugared()
-    }
-
-    /// This always-inlined version should only be used on hot code paths.
-    #[inline(always)]
-    fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
-        let (data, attr_style, sp) = match self.inlined_next() {
-            (Token { kind: token::DocComment(_, attr_style, data), span }, _) => {
-                (data, attr_style, span)
-            }
-            tok => return tok,
-        };
-
+    fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) {
         // Searches for the occurrences of `"#*` and returns the minimum number of `#`s
         // required to wrap the text.
         let mut num_of_hashes = 0;
@@ -318,14 +313,14 @@ fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
             num_of_hashes = cmp::max(num_of_hashes, count);
         }
 
-        let delim_span = DelimSpan::from_single(sp);
+        let delim_span = DelimSpan::from_single(span);
         let body = TokenTree::Delimited(
             delim_span,
             token::Bracket,
             [
-                TokenTree::token(token::Ident(sym::doc, false), sp),
-                TokenTree::token(token::Eq, sp),
-                TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), sp),
+                TokenTree::token(token::Ident(sym::doc, false), span),
+                TokenTree::token(token::Eq, span),
+                TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), span),
             ]
             .iter()
             .cloned()
@@ -338,12 +333,12 @@ fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
                 delim_span,
                 token::NoDelim,
                 if attr_style == AttrStyle::Inner {
-                    [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body]
+                    [TokenTree::token(token::Pound, span), TokenTree::token(token::Not, span), body]
                         .iter()
                         .cloned()
                         .collect::<TokenStream>()
                 } else {
-                    [TokenTree::token(token::Pound, sp), body]
+                    [TokenTree::token(token::Pound, span), body]
                         .iter()
                         .cloned()
                         .collect::<TokenStream>()
@@ -351,7 +346,7 @@ fn inlined_next_desugared(&mut self) -> (Token, Spacing) {
             ),
         ));
 
-        self.next()
+        self.next(/* desugar_doc_comments */ false)
     }
 }
 
@@ -436,9 +431,9 @@ pub fn new(
         desugar_doc_comments: bool,
         subparser_name: Option<&'static str>,
     ) -> Self {
-        let mut start_frame = TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens);
-        start_frame.open_delim = true;
-        start_frame.close_delim = true;
+        // Note: because of the way `TokenCursor::inlined_next` is structured, the `span` and
+        // `delim` arguments here are never used.
+        let start_frame = TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens);
 
         let mut parser = Parser {
             sess,
@@ -476,33 +471,6 @@ pub fn new(
         parser
     }
 
-    #[inline]
-    fn next_tok(&mut self, fallback_span: Span) -> (Token, Spacing) {
-        loop {
-            let (mut next, spacing) = if self.desugar_doc_comments {
-                self.token_cursor.inlined_next_desugared()
-            } else {
-                self.token_cursor.inlined_next()
-            };
-            self.token_cursor.num_next_calls += 1;
-            // We've retrieved an token from the underlying
-            // cursor, so we no longer need to worry about
-            // an unglued token. See `break_and_eat` for more details
-            self.token_cursor.break_last_token = false;
-            if next.span.is_dummy() {
-                // Tweak the location for better diagnostics, but keep syntactic context intact.
-                next.span = fallback_span.with_ctxt(next.span.ctxt());
-            }
-            if matches!(
-                next.kind,
-                token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
-            ) {
-                continue;
-            }
-            return (next, spacing);
-        }
-    }
-
     pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
         match self.expect_one_of(&[], &[]) {
             Err(e) => Err(e),
@@ -697,7 +665,7 @@ fn break_and_eat(&mut self, expected: TokenKind) -> bool {
                 //
                 // If we consume any additional tokens, then this token
                 // is not needed (we'll capture the entire 'glued' token),
-                // and `next_tok` will set this field to `None`
+                // and `bump` will set this field to `None`
                 self.token_cursor.break_last_token = true;
                 // Use the spacing of the glued token as the spacing
                 // of the unglued second token.
@@ -1019,12 +987,6 @@ fn bump_with(&mut self, next: (Token, Spacing)) {
     /// This always-inlined version should only be used on hot code paths.
     #[inline(always)]
     fn inlined_bump_with(&mut self, (next_token, next_spacing): (Token, Spacing)) {
-        // Bumping after EOF is a bad sign, usually an infinite loop.
-        if self.prev_token.kind == TokenKind::Eof {
-            let msg = "attempted to bump the parser past EOF (may be stuck in a loop)";
-            self.span_bug(self.token.span, msg);
-        }
-
         // Update the current and previous tokens.
         self.prev_token = mem::replace(&mut self.token, next_token);
         self.token_spacing = next_spacing;
@@ -1035,8 +997,24 @@ fn inlined_bump_with(&mut self, (next_token, next_spacing): (Token, Spacing)) {
 
     /// Advance the parser by one token.
     pub fn bump(&mut self) {
-        let next_token = self.next_tok(self.token.span);
-        self.inlined_bump_with(next_token);
+        // Note: destructuring here would give nicer code, but it was found in #96210 to be slower
+        // than `.0`/`.1` access.
+        let mut next = self.token_cursor.inlined_next(self.desugar_doc_comments);
+        self.token_cursor.num_next_calls += 1;
+        // We've retrieved an token from the underlying
+        // cursor, so we no longer need to worry about
+        // an unglued token. See `break_and_eat` for more details
+        self.token_cursor.break_last_token = false;
+        if next.0.span.is_dummy() {
+            // Tweak the location for better diagnostics, but keep syntactic context intact.
+            let fallback_span = self.token.span;
+            next.0.span = fallback_span.with_ctxt(next.0.span.ctxt());
+        }
+        debug_assert!(!matches!(
+            next.0.kind,
+            token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
+        ));
+        self.inlined_bump_with(next)
     }
 
     /// Look-ahead `dist` tokens of `self.token` and get access to that token there.
@@ -1069,7 +1047,7 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
         let mut i = 0;
         let mut token = Token::dummy();
         while i < dist {
-            token = cursor.next().0;
+            token = cursor.next(/* desugar_doc_comments */ false).0;
             if matches!(
                 token.kind,
                 token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim)
@@ -1217,24 +1195,28 @@ fn parse_or_use_outer_attributes(
     pub(crate) fn parse_token_tree(&mut self) -> TokenTree {
         match self.token.kind {
             token::OpenDelim(..) => {
-                let depth = self.token_cursor.stack.len();
+                // Grab the tokens from this frame.
+                let frame = &self.token_cursor.frame;
+                let stream = frame.tree_cursor.stream.clone();
+                let span = frame.span;
+                let delim = frame.delim;
 
-                // We keep advancing the token cursor until we hit
-                // the matching `CloseDelim` token.
-                while !(depth == self.token_cursor.stack.len()
-                    && matches!(self.token.kind, token::CloseDelim(_)))
-                {
+                // Advance the token cursor through the entire delimited
+                // sequence. After getting the `OpenDelim` we are *within* the
+                // delimited sequence, i.e. at depth `d`. After getting the
+                // matching `CloseDelim` we are *after* the delimited sequence,
+                // i.e. at depth `d - 1`.
+                let target_depth = self.token_cursor.stack.len() - 1;
+                loop {
                     // Advance one token at a time, so `TokenCursor::next()`
                     // can capture these tokens if necessary.
                     self.bump();
+                    if self.token_cursor.stack.len() == target_depth {
+                        debug_assert!(matches!(self.token.kind, token::CloseDelim(_)));
+                        break;
+                    }
                 }
-                // We are still inside the frame corresponding
-                // to the delimited stream we captured, so grab
-                // the tokens from this frame.
-                let frame = &self.token_cursor.frame;
-                let stream = frame.tree_cursor.stream.clone();
-                let span = frame.span;
-                let delim = frame.delim;
+
                 // Consume close delimiter
                 self.bump();
                 TokenTree::Delimited(span, delim, stream)
index b45bca3d2e024acf169d5a34411a32d9430b07d7..691bfdb01a43ebfef224e141869c992c1f0ce57a 100644 (file)
 impl<'a> Parser<'a> {
     /// Checks whether a non-terminal may begin with a particular token.
     ///
-    /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
-    /// token. Be conservative (return true) if not sure.
+    /// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with
+    /// that token. Be conservative (return true) if not sure. Inlined because it has a single call
+    /// site.
+    #[inline]
     pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
         /// Checks whether the non-terminal may contain a single (non-keyword) identifier.
         fn may_be_ident(nt: &token::Nonterminal) -> bool {
@@ -95,7 +97,9 @@ fn may_be_ident(nt: &token::Nonterminal) -> bool {
         }
     }
 
-    /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`).
+    /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
+    /// site.
+    #[inline]
     pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, NtOrTt> {
         // Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
         // needs to have them force-captured here.
index 5a1373ad1a218dc94c0987cc3a6b2023ca0e4811..db083d0453bc05d7cc9a6924a3a3e3ca845eca8c 100644 (file)
@@ -1,21 +1,18 @@
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
-use rustc_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_session::config::{CrateType, EntryFnType};
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
 
-struct EntryContext<'a, 'tcx> {
-    session: &'a Session,
-
-    map: Map<'tcx>,
+struct EntryContext<'tcx> {
+    tcx: TyCtxt<'tcx>,
 
     /// The function that has attribute named `main`.
     attr_main_fn: Option<(LocalDefId, Span)>,
@@ -28,10 +25,9 @@ struct EntryContext<'a, 'tcx> {
     non_main_fns: Vec<Span>,
 }
 
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
-        let def_key = self.map.def_key(item.def_id);
-        let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
+        let at_root = self.tcx.local_parent(item.def_id) == Some(CRATE_DEF_ID);
         find_item(item, self, at_root);
     }
 
@@ -60,13 +56,8 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
         return None;
     }
 
-    let mut ctxt = EntryContext {
-        session: tcx.sess,
-        map: tcx.hir(),
-        attr_main_fn: None,
-        start_fn: None,
-        non_main_fns: Vec::new(),
-    };
+    let mut ctxt =
+        EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
 
     tcx.hir().visit_all_item_likes(&mut ctxt);
 
@@ -75,11 +66,11 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
 
 // Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
 // (with `ast::Item`), so make sure to keep them in sync.
-fn entry_point_type(ctxt: &EntryContext<'_, '_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
-    let attrs = ctxt.map.attrs(item.hir_id());
-    if ctxt.session.contains_name(attrs, sym::start) {
+fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
+    let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+    if ctxt.tcx.sess.contains_name(attrs, sym::start) {
         EntryPointType::Start
-    } else if ctxt.session.contains_name(attrs, sym::rustc_main) {
+    } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
         EntryPointType::MainAttr
     } else if item.ident.name == sym::main {
         if at_root {
@@ -98,16 +89,16 @@ fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
         .emit();
 }
 
-fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
+fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
     match entry_point_type(ctxt, item, at_root) {
         EntryPointType::None => (),
         _ if !matches!(item.kind, ItemKind::Fn(..)) => {
-            let attrs = ctxt.map.attrs(item.hir_id());
-            if let Some(attr) = ctxt.session.find_by_name(attrs, sym::start) {
-                throw_attr_err(&ctxt.session, attr.span, "start");
+            let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+            if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
+                throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
             }
-            if let Some(attr) = ctxt.session.find_by_name(attrs, sym::rustc_main) {
-                throw_attr_err(&ctxt.session, attr.span, "rustc_main");
+            if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::rustc_main) {
+                throw_attr_err(&ctxt.tcx.sess, attr.span, "rustc_main");
             }
         }
         EntryPointType::MainNamed => (),
@@ -119,7 +110,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
                 ctxt.attr_main_fn = Some((item.def_id, item.span));
             } else {
                 struct_span_err!(
-                    ctxt.session,
+                    ctxt.tcx.sess,
                     item.span,
                     E0137,
                     "multiple functions with a `#[main]` attribute"
@@ -133,7 +124,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
             if ctxt.start_fn.is_none() {
                 ctxt.start_fn = Some((item.def_id, item.span));
             } else {
-                struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
+                struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions")
                     .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
                     .span_label(item.span, "multiple `start` functions")
                     .emit();
@@ -142,7 +133,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
     }
 }
 
-fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
+fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
     if let Some((def_id, _)) = visitor.start_fn {
         Some((def_id.to_def_id(), EntryFnType::Start))
     } else if let Some((def_id, _)) = visitor.attr_main_fn {
@@ -177,7 +168,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(De
     }
 }
 
-fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
+fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
     let sp = tcx.def_span(CRATE_DEF_ID);
     if *tcx.sess.parse_sess.reached_eof.borrow() {
         // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
index 56755d68686e3d27b4c70df96de00d5ef82db02d..379a6827c8aac5d3d41075a5aa1998ee7d4cec24 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lock;
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirId, ItemLocalId};
@@ -89,7 +89,7 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId,
         self.owner = Some(owner);
         walk(self);
 
-        if owner.local_def_index == CRATE_DEF_INDEX {
+        if owner == CRATE_DEF_ID {
             return;
         }
 
index 01ba9e35c24dc65c22e1ba4d79e9ef381214cfbc..35a858cb86c3f1851f40e4b266c2571bf0fc5342 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
@@ -703,7 +703,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                 let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id) else {
                     return;
                 };
-                let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+                let def_id = cnum.as_def_id();
                 self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
             }
 
index acccf43f06285f59b8421227b0373d47bbbfac26..b20aa7b53468aa0f329071cde63314849288ccc1 100644 (file)
@@ -1,7 +1,7 @@
 use measureme::{StringComponent, StringId};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfiler;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
 use rustc_middle::ty::{TyCtxt, WithOptConstParam};
 use rustc_query_system::query::QueryCache;
@@ -143,7 +143,7 @@ fn spec_to_self_profile_string(
         &self,
         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
     ) -> StringId {
-        builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
+        builder.def_id_to_string_id(self.as_def_id())
     }
 }
 
index 54e8c03156d558448b64e58721c885d99457b7bd..d97d9199b77eed1f4c7b6bd3d8bf700697095973 100644 (file)
@@ -23,7 +23,7 @@
 use rustc_expand::base::SyntaxExtension;
 use rustc_expand::expand::AstFragment;
 use rustc_hir::def::{self, *};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_metadata::creader::LoadedMacro;
 use rustc_middle::bug;
 use rustc_middle::metadata::ModChild;
@@ -140,8 +140,8 @@ pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> {
                     let parent = def_key.parent.map(|index| {
                         self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
                     });
-                    let name = if def_id.index == CRATE_DEF_INDEX {
-                        self.cstore().crate_name(def_id.krate)
+                    let name = if let Some(cnum) = def_id.as_crate_root() {
+                        self.cstore().crate_name(cnum)
                     } else {
                         def_key.disambiguated_data.data.get_opt_name().expect("module without name")
                     };
@@ -250,7 +250,7 @@ fn try_resolve_visibility<'ast>(
         match vis.kind {
             ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
             ast::VisibilityKind::Crate(..) => {
-                Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
+                Ok(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))
             }
             ast::VisibilityKind::Inherited => {
                 Ok(match self.parent_scope.module.kind {
@@ -521,11 +521,10 @@ fn build_reduced_graph_for_use_tree(
                         // while the current crate doesn't have a valid `crate_name`.
                         if crate_name != kw::Empty {
                             // `crate_name` should not be interpreted as relative.
-                            module_path.push(Segment {
-                                ident: Ident { name: kw::PathRoot, span: source.ident.span },
-                                id: Some(self.r.next_node_id()),
-                                has_generic_args: false,
-                            });
+                            module_path.push(Segment::from_ident_and_id(
+                                Ident { name: kw::PathRoot, span: source.ident.span },
+                                self.r.next_node_id(),
+                            ));
                             source.ident.name = crate_name;
                         }
                         if rename.is_none() {
@@ -759,7 +758,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
                     let mut ctor_vis = if vis == ty::Visibility::Public
                         && self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
                     {
-                        ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+                        ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
                     } else {
                         vis
                     };
@@ -1108,7 +1107,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool
                 root_span: span,
                 span,
                 module_path: Vec::new(),
-                vis: Cell::new(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))),
+                vis: Cell::new(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())),
                 used: Cell::new(false),
             })
         };
@@ -1244,7 +1243,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
             let vis = if is_macro_export {
                 ty::Visibility::Public
             } else {
-                ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+                ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
             };
             let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
             self.r.set_binding_parent_module(binding, parent_scope.module);
@@ -1490,7 +1489,7 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
         let ctor_vis = if vis == ty::Visibility::Public
             && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
         {
-            ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+            ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
         } else {
             vis
         };
index 8ea5dca6f108a64ae7a5cabe661fc66059c1a2f6..1e8cca6122c4c58724bad81648e96417624a6073 100644 (file)
@@ -133,8 +133,10 @@ fn visit_item(&mut self, i: &'a Item) {
     }
 
     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
-        if let FnKind::Fn(_, _, sig, _, body) = fn_kind {
+        if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
             if let Async::Yes { closure_id, return_impl_trait_id, .. } = sig.header.asyncness {
+                self.visit_generics(generics);
+
                 let return_impl_trait_id =
                     self.create_def(return_impl_trait_id, DefPathData::ImplTrait, span);
 
index f3b8c1e266c5871a2ca30a56c286f8ba0b64064d..9bbecf104e55e897964cc1838e9e31bb3a39154a 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_middle::bug;
 use rustc_middle::ty::DefIdTree;
@@ -1014,7 +1014,7 @@ fn add_suggestion_for_duplicate_nested_use(
             }
             ResolutionError::InvalidAsmSym => {
                 let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
-                err.span_label(span, &format!("is a local variable"));
+                err.span_label(span, "is a local variable");
                 err.help("`sym` operands must refer to either a function or a static");
                 err
             }
@@ -1167,7 +1167,7 @@ fn early_lookup_typo_candidate(
                 }
                 Scope::ExternPrelude => {
                     suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
-                        let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
+                        let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
                         filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res))
                     }));
                 }
index 24b6d6569810702522450851ae51700c7f4dd25d..84fe0ec83d26c3c075dc332a7b7982f03d8e655a 100644 (file)
@@ -1402,7 +1402,7 @@ fn validate_res_from_ribs(
         let mut allow_super = true;
         let mut second_binding = None;
 
-        for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
+        for (i, &Segment { ident, id, .. }) in path.iter().enumerate() {
             debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
             let record_segment_res = |this: &mut Self, res| {
                 if finalize.is_some() {
index 763f31622bc1f4ec18dcbff1156a25b28fc80318..7635ad9bd87bf145a752cf87c004b0e74f723115 100644 (file)
 use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
 use smallvec::{smallvec, SmallVec};
 
 use rustc_span::source_map::{respan, Spanned};
@@ -188,6 +189,68 @@ fn new(kind: RibKind<'a>) -> Rib<'a, R> {
     }
 }
 
+#[derive(Copy, Clone, Debug)]
+enum LifetimeRibKind {
+    /// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
+    Item,
+
+    /// This rib declares generic parameters.
+    Generics { span: Span, kind: LifetimeBinderKind },
+
+    /// For **Modern** cases, create a new anonymous region parameter
+    /// and reference that.
+    ///
+    /// For **Dyn Bound** cases, pass responsibility to
+    /// `resolve_lifetime` code.
+    ///
+    /// For **Deprecated** cases, report an error.
+    AnonymousCreateParameter,
+
+    /// Give a hard error when either `&` or `'_` is written. Used to
+    /// rule out things like `where T: Foo<'_>`. Does not imply an
+    /// error on default object bounds (e.g., `Box<dyn Foo>`).
+    AnonymousReportError,
+
+    /// Pass responsibility to `resolve_lifetime` code for all cases.
+    AnonymousPassThrough,
+}
+
+#[derive(Copy, Clone, Debug)]
+enum LifetimeBinderKind {
+    BareFnType,
+    PolyTrait,
+    WhereBound,
+    Item,
+    Function,
+    ImplBlock,
+}
+
+impl LifetimeBinderKind {
+    fn descr(self) -> &'static str {
+        use LifetimeBinderKind::*;
+        match self {
+            BareFnType => "type",
+            PolyTrait => "bound",
+            WhereBound => "bound",
+            Item => "item",
+            ImplBlock => "impl block",
+            Function => "function",
+        }
+    }
+}
+
+#[derive(Debug)]
+struct LifetimeRib {
+    kind: LifetimeRibKind,
+    bindings: IdentMap<()>,
+}
+
+impl LifetimeRib {
+    fn new(kind: LifetimeRibKind) -> LifetimeRib {
+        LifetimeRib { bindings: Default::default(), kind }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 crate enum AliasPossibility {
     No,
@@ -422,6 +485,9 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
     /// The current set of local scopes, for labels.
     label_ribs: Vec<Rib<'a, NodeId>>,
 
+    /// The current set of local scopes for lifetimes.
+    lifetime_ribs: Vec<LifetimeRib>,
+
     /// The trait that the current context can refer to.
     current_trait_ref: Option<(Module<'a>, TraitRef)>,
 
@@ -446,7 +512,7 @@ fn visit_item(&mut self, item: &'ast Item) {
         let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
         // Always report errors in items we just entered.
         let old_ignore = replace(&mut self.in_func_body, false);
-        self.resolve_item(item);
+        self.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item));
         self.in_func_body = old_ignore;
         self.diagnostic_metadata.current_item = prev;
     }
@@ -481,6 +547,12 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
         let prev = self.diagnostic_metadata.current_trait_object;
         let prev_ty = self.diagnostic_metadata.current_type_path;
         match ty.kind {
+            TyKind::Rptr(None, _) => {
+                // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
+                // NodeId `ty.id`.
+                let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
+                self.resolve_elided_lifetime(ty.id, span);
+            }
             TyKind::Path(ref qself, ref path) => {
                 self.diagnostic_metadata.current_type_path = Some(ty);
                 self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
@@ -500,36 +572,86 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
             TyKind::TraitObject(ref bounds, ..) => {
                 self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
             }
+            TyKind::BareFn(ref bare_fn) => {
+                let span = if bare_fn.generic_params.is_empty() {
+                    ty.span.shrink_to_lo()
+                } else {
+                    ty.span
+                };
+                self.with_generic_param_rib(
+                    &bare_fn.generic_params,
+                    NormalRibKind,
+                    LifetimeRibKind::Generics { kind: LifetimeBinderKind::BareFnType, span },
+                    |this| {
+                        this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                            this.visit_generic_param_vec(&bare_fn.generic_params, false);
+                            visit::walk_fn_decl(this, &bare_fn.decl);
+                        });
+                    },
+                );
+                self.diagnostic_metadata.current_trait_object = prev;
+                return;
+            }
             _ => (),
         }
         visit::walk_ty(self, ty);
         self.diagnostic_metadata.current_trait_object = prev;
         self.diagnostic_metadata.current_type_path = prev_ty;
     }
-    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
-        self.smart_resolve_path(
-            tref.trait_ref.ref_id,
-            None,
-            &tref.trait_ref.path,
-            PathSource::Trait(AliasPossibility::Maybe),
+    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
+        let span =
+            if tref.bound_generic_params.is_empty() { tref.span.shrink_to_lo() } else { tref.span };
+        self.with_generic_param_rib(
+            &tref.bound_generic_params,
+            NormalRibKind,
+            LifetimeRibKind::Generics { kind: LifetimeBinderKind::PolyTrait, span },
+            |this| {
+                this.visit_generic_param_vec(&tref.bound_generic_params, false);
+                this.smart_resolve_path(
+                    tref.trait_ref.ref_id,
+                    None,
+                    &tref.trait_ref.path,
+                    PathSource::Trait(AliasPossibility::Maybe),
+                );
+                this.visit_trait_ref(&tref.trait_ref);
+            },
         );
-        visit::walk_poly_trait_ref(self, tref, m);
     }
     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
         match foreign_item.kind {
-            ForeignItemKind::Fn(box Fn { ref generics, .. })
-            | ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
-                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    visit::walk_foreign_item(this, foreign_item);
+            ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
+                self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+                    this.with_generic_param_rib(
+                        &generics.params,
+                        ItemRibKind(HasGenericParams::Yes),
+                        LifetimeRibKind::Generics {
+                            kind: LifetimeBinderKind::Item,
+                            span: generics.span,
+                        },
+                        |this| visit::walk_foreign_item(this, foreign_item),
+                    )
+                });
+            }
+            ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
+                self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+                    this.with_generic_param_rib(
+                        &generics.params,
+                        ItemRibKind(HasGenericParams::Yes),
+                        LifetimeRibKind::Generics {
+                            kind: LifetimeBinderKind::Function,
+                            span: generics.span,
+                        },
+                        |this| visit::walk_foreign_item(this, foreign_item),
+                    )
                 });
             }
             ForeignItemKind::Static(..) => {
-                self.with_item_rib(HasGenericParams::No, |this| {
+                self.with_item_rib(|this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
             }
             ForeignItemKind::MacCall(..) => {
-                visit::walk_foreign_item(self, foreign_item);
+                panic!("unexpanded macro in resolve!")
             }
         }
     }
@@ -537,11 +659,15 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
         let rib_kind = match fn_kind {
             // Bail if the function is foreign, and thus cannot validly have
             // a body, or if there's no body for some other reason.
-            FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => {
-                // We don't need to deal with patterns in parameters, because
-                // they are not possible for foreign or bodiless functions.
-                self.visit_fn_header(&sig.header);
-                visit::walk_fn_decl(self, &sig.decl);
+            FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
+            | FnKind::Fn(_, _, sig, _, generics, None) => {
+                self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                    // We don't need to deal with patterns in parameters, because
+                    // they are not possible for foreign or bodiless functions.
+                    this.visit_fn_header(&sig.header);
+                    this.visit_generics(generics);
+                    visit::walk_fn_decl(this, &sig.decl);
+                });
                 return;
             }
             FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
@@ -559,19 +685,44 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
         self.with_rib(ValueNS, rib_kind, |this| {
             // Create a label rib for the function.
             this.with_label_rib(rib_kind, |this| {
-                // Add each argument to the rib.
-                this.resolve_params(&declaration.inputs);
+                let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id());
 
-                visit::walk_fn_ret_ty(this, &declaration.output);
+                if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind {
+                    this.visit_generics(generics);
+                }
+
+                if async_node_id.is_some() {
+                    // In `async fn`, argument-position elided lifetimes
+                    // must be transformed into fresh generic parameters so that
+                    // they can be applied to the opaque `impl Trait` return type.
+                    this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
+                        // Add each argument to the rib.
+                        this.resolve_params(&declaration.inputs)
+                    });
+
+                    this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                        visit::walk_fn_ret_ty(this, &declaration.output)
+                    });
+                } else {
+                    this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                        // Add each argument to the rib.
+                        this.resolve_params(&declaration.inputs);
+
+                        visit::walk_fn_ret_ty(this, &declaration.output);
+                    });
+                };
 
                 // Ignore errors in function bodies if this is rustdoc
                 // Be sure not to set this until the function signature has been resolved.
                 let previous_state = replace(&mut this.in_func_body, true);
                 // Resolve the function body, potentially inside the body of an async closure
-                match fn_kind {
-                    FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
-                    FnKind::Closure(_, body) => this.visit_expr(body),
-                };
+                this.with_lifetime_rib(
+                    LifetimeRibKind::AnonymousPassThrough,
+                    |this| match fn_kind {
+                        FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
+                        FnKind::Closure(_, body) => this.visit_expr(body),
+                    },
+                );
 
                 debug!("(resolving function) leaving function");
                 this.in_func_body = previous_state;
@@ -579,89 +730,15 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
         });
         self.diagnostic_metadata.current_function = previous_value;
     }
+    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
+        self.resolve_lifetime(lifetime)
+    }
 
     fn visit_generics(&mut self, generics: &'ast Generics) {
-        // For type parameter defaults, we have to ban access
-        // to following type parameters, as the InternalSubsts can only
-        // provide previous type parameters as they're built. We
-        // put all the parameters on the ban list and then remove
-        // them one by one as they are processed and become available.
-        let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
-        let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
-        for param in generics.params.iter() {
-            match param.kind {
-                GenericParamKind::Type { .. } => {
-                    forward_ty_ban_rib
-                        .bindings
-                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
-                }
-                GenericParamKind::Const { .. } => {
-                    forward_const_ban_rib
-                        .bindings
-                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
-                }
-                GenericParamKind::Lifetime => {}
-            }
-        }
-
-        // rust-lang/rust#61631: The type `Self` is essentially
-        // another type parameter. For ADTs, we consider it
-        // well-defined only after all of the ADT type parameters have
-        // been provided. Therefore, we do not allow use of `Self`
-        // anywhere in ADT type parameter defaults.
-        //
-        // (We however cannot ban `Self` for defaults on *all* generic
-        // lists; e.g. trait generics can usefully refer to `Self`,
-        // such as in the case of `trait Add<Rhs = Self>`.)
-        if self.diagnostic_metadata.current_self_item.is_some() {
-            // (`Some` if + only if we are in ADT's generics.)
-            forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
-        }
-
-        for param in &generics.params {
-            match param.kind {
-                GenericParamKind::Lifetime => self.visit_generic_param(param),
-                GenericParamKind::Type { ref default } => {
-                    for bound in &param.bounds {
-                        self.visit_param_bound(bound);
-                    }
-
-                    if let Some(ref ty) = default {
-                        self.ribs[TypeNS].push(forward_ty_ban_rib);
-                        self.ribs[ValueNS].push(forward_const_ban_rib);
-                        self.visit_ty(ty);
-                        forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
-                        forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
-                    }
-
-                    // Allow all following defaults to refer to this type parameter.
-                    forward_ty_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
-                }
-                GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
-                    // Const parameters can't have param bounds.
-                    assert!(param.bounds.is_empty());
-
-                    self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
-                    self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
-                    self.visit_ty(ty);
-                    self.ribs[TypeNS].pop().unwrap();
-                    self.ribs[ValueNS].pop().unwrap();
-
-                    if let Some(ref expr) = default {
-                        self.ribs[TypeNS].push(forward_ty_ban_rib);
-                        self.ribs[ValueNS].push(forward_const_ban_rib);
-                        self.visit_anon_const(expr);
-                        forward_const_ban_rib = self.ribs[ValueNS].pop().unwrap();
-                        forward_ty_ban_rib = self.ribs[TypeNS].pop().unwrap();
-                    }
-
-                    // Allow all following defaults to refer to this const parameter.
-                    forward_const_ban_rib
-                        .bindings
-                        .remove(&Ident::with_dummy_span(param.ident.name));
-                }
-            }
-        }
+        self.visit_generic_param_vec(
+            &generics.params,
+            self.diagnostic_metadata.current_self_item.is_some(),
+        );
         for p in &generics.where_clause.predicates {
             self.visit_where_predicate(p);
         }
@@ -720,11 +797,52 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
         self.diagnostic_metadata.currently_processing_generics = prev;
     }
 
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
+        if let Some(ref args) = path_segment.args {
+            match &**args {
+                GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args),
+                GenericArgs::Parenthesized(..) => self
+                    .with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| {
+                        visit::walk_generic_args(this, path_span, args)
+                    }),
+            }
+        }
+    }
+
     fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
         debug!("visit_where_predicate {:?}", p);
         let previous_value =
             replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p));
-        visit::walk_where_predicate(self, p);
+        self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+            if let WherePredicate::BoundPredicate(WhereBoundPredicate {
+                ref bounded_ty,
+                ref bounds,
+                ref bound_generic_params,
+                span: predicate_span,
+                ..
+            }) = p
+            {
+                let span = if bound_generic_params.is_empty() {
+                    predicate_span.shrink_to_lo()
+                } else {
+                    *predicate_span
+                };
+                this.with_generic_param_rib(
+                    &bound_generic_params,
+                    NormalRibKind,
+                    LifetimeRibKind::Generics { kind: LifetimeBinderKind::WhereBound, span },
+                    |this| {
+                        this.visit_generic_param_vec(&bound_generic_params, false);
+                        this.visit_ty(bounded_ty);
+                        for bound in bounds {
+                            this.visit_param_bound(bound)
+                        }
+                    },
+                );
+            } else {
+                visit::walk_where_predicate(this, p);
+            }
+        });
         self.diagnostic_metadata.current_where_predicate = previous_value;
     }
 
@@ -762,6 +880,7 @@ fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> {
                 macro_ns: vec![Rib::new(start_rib_kind)],
             },
             label_ribs: Vec::new(),
+            lifetime_ribs: Vec::new(),
             current_trait_ref: None,
             diagnostic_metadata: DiagnosticMetadata::default(),
             // errors at module scope should always be reported
@@ -864,6 +983,319 @@ fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
         }
     }
 
+    fn visit_generic_param_vec(&mut self, params: &'ast Vec<GenericParam>, add_self_upper: bool) {
+        // For type parameter defaults, we have to ban access
+        // to following type parameters, as the InternalSubsts can only
+        // provide previous type parameters as they're built. We
+        // put all the parameters on the ban list and then remove
+        // them one by one as they are processed and become available.
+        let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
+        let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
+        for param in params.iter() {
+            match param.kind {
+                GenericParamKind::Type { .. } => {
+                    forward_ty_ban_rib
+                        .bindings
+                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
+                }
+                GenericParamKind::Const { .. } => {
+                    forward_const_ban_rib
+                        .bindings
+                        .insert(Ident::with_dummy_span(param.ident.name), Res::Err);
+                }
+                GenericParamKind::Lifetime => {}
+            }
+        }
+
+        // rust-lang/rust#61631: The type `Self` is essentially
+        // another type parameter. For ADTs, we consider it
+        // well-defined only after all of the ADT type parameters have
+        // been provided. Therefore, we do not allow use of `Self`
+        // anywhere in ADT type parameter defaults.
+        //
+        // (We however cannot ban `Self` for defaults on *all* generic
+        // lists; e.g. trait generics can usefully refer to `Self`,
+        // such as in the case of `trait Add<Rhs = Self>`.)
+        if add_self_upper {
+            // (`Some` if + only if we are in ADT's generics.)
+            forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err);
+        }
+
+        self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+            for param in params {
+                match param.kind {
+                    GenericParamKind::Lifetime => {
+                        for bound in &param.bounds {
+                            this.visit_param_bound(bound);
+                        }
+                    }
+                    GenericParamKind::Type { ref default } => {
+                        for bound in &param.bounds {
+                            this.visit_param_bound(bound);
+                        }
+
+                        if let Some(ref ty) = default {
+                            this.ribs[TypeNS].push(forward_ty_ban_rib);
+                            this.ribs[ValueNS].push(forward_const_ban_rib);
+                            this.visit_ty(ty);
+                            forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
+                            forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
+                        }
+
+                        // Allow all following defaults to refer to this type parameter.
+                        forward_ty_ban_rib
+                            .bindings
+                            .remove(&Ident::with_dummy_span(param.ident.name));
+                    }
+                    GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
+                        // Const parameters can't have param bounds.
+                        assert!(param.bounds.is_empty());
+
+                        this.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
+                        this.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
+                        this.visit_ty(ty);
+                        this.ribs[TypeNS].pop().unwrap();
+                        this.ribs[ValueNS].pop().unwrap();
+
+                        if let Some(ref expr) = default {
+                            this.ribs[TypeNS].push(forward_ty_ban_rib);
+                            this.ribs[ValueNS].push(forward_const_ban_rib);
+                            this.visit_anon_const(expr);
+                            forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
+                            forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
+                        }
+
+                        // Allow all following defaults to refer to this const parameter.
+                        forward_const_ban_rib
+                            .bindings
+                            .remove(&Ident::with_dummy_span(param.ident.name));
+                    }
+                }
+            }
+        })
+    }
+
+    #[tracing::instrument(level = "debug", skip(self, work))]
+    fn with_lifetime_rib<T>(
+        &mut self,
+        kind: LifetimeRibKind,
+        work: impl FnOnce(&mut Self) -> T,
+    ) -> T {
+        self.lifetime_ribs.push(LifetimeRib::new(kind));
+        let ret = work(self);
+        self.lifetime_ribs.pop();
+        ret
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime) {
+        let ident = lifetime.ident;
+
+        if ident.name == kw::StaticLifetime {
+            return;
+        }
+
+        if ident.name == kw::UnderscoreLifetime {
+            return self.resolve_anonymous_lifetime(lifetime, false);
+        }
+
+        let mut indices = (0..self.lifetime_ribs.len()).rev();
+        for i in &mut indices {
+            let rib = &self.lifetime_ribs[i];
+            let normalized_ident = ident.normalize_to_macros_2_0();
+            if let Some(_) = rib.bindings.get_key_value(&normalized_ident) {
+                return;
+            }
+
+            if let LifetimeRibKind::Item = rib.kind {
+                break;
+            }
+        }
+
+        let mut outer_res = None;
+        for i in indices {
+            let rib = &self.lifetime_ribs[i];
+            let normalized_ident = ident.normalize_to_macros_2_0();
+            if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) {
+                outer_res = Some(outer);
+                break;
+            }
+        }
+
+        self.emit_undeclared_lifetime_error(lifetime, outer_res);
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
+        debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
+
+        for i in (0..self.lifetime_ribs.len()).rev() {
+            let rib = &mut self.lifetime_ribs[i];
+            match rib.kind {
+                LifetimeRibKind::AnonymousReportError => {
+                    let (msg, note) = if elided {
+                        (
+                            "`&` without an explicit lifetime name cannot be used here",
+                            "explicit lifetime name needed here",
+                        )
+                    } else {
+                        ("`'_` cannot be used here", "`'_` is a reserved lifetime name")
+                    };
+                    rustc_errors::struct_span_err!(
+                        self.r.session,
+                        lifetime.ident.span,
+                        E0637,
+                        "{}",
+                        msg,
+                    )
+                    .span_label(lifetime.ident.span, note)
+                    .emit();
+
+                    return;
+                }
+                LifetimeRibKind::AnonymousCreateParameter
+                | LifetimeRibKind::AnonymousPassThrough
+                | LifetimeRibKind::Item => return,
+                _ => {}
+            }
+        }
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
+        let id = self.r.next_node_id();
+        let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
+        self.resolve_anonymous_lifetime(&lt, true);
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_elided_lifetimes_in_path(
+        &mut self,
+        path_id: NodeId,
+        partial_res: PartialRes,
+        path: &[Segment],
+        source: PathSource<'_>,
+        finalize: Finalize,
+    ) {
+        let Some(path_span) = finalize.path_span() else {
+            return;
+        };
+        let proj_start = path.len() - partial_res.unresolved_segments();
+        for (i, segment) in path.iter().enumerate() {
+            if segment.has_lifetime_args {
+                continue;
+            }
+            let Some(segment_id) = segment.id else {
+                continue;
+            };
+
+            // Figure out if this is a type/trait segment,
+            // which may need lifetime elision performed.
+            let type_def_id = match partial_res.base_res() {
+                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
+                    self.r.parent(def_id).unwrap()
+                }
+                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
+                    self.r.parent(def_id).unwrap()
+                }
+                Res::Def(DefKind::Struct, def_id)
+                | Res::Def(DefKind::Union, def_id)
+                | Res::Def(DefKind::Enum, def_id)
+                | Res::Def(DefKind::TyAlias, def_id)
+                | Res::Def(DefKind::Trait, def_id)
+                    if i + 1 == proj_start =>
+                {
+                    def_id
+                }
+                _ => continue,
+            };
+
+            let expected_lifetimes = self.r.item_generics_num_lifetimes(type_def_id);
+            if expected_lifetimes == 0 {
+                continue;
+            }
+
+            let missing = match source {
+                PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
+                PathSource::Expr(..)
+                | PathSource::Pat
+                | PathSource::Struct
+                | PathSource::TupleStruct(..) => false,
+            };
+            let mut error = false;
+            for rib in self.lifetime_ribs.iter().rev() {
+                match rib.kind {
+                    // In create-parameter mode we error here because we don't want to support
+                    // deprecated impl elision in new features like impl elision and `async fn`,
+                    // both of which work using the `CreateParameter` mode:
+                    //
+                    //     impl Foo for std::cell::Ref<u32> // note lack of '_
+                    //     async fn foo(_: std::cell::Ref<u32>) { ... }
+                    LifetimeRibKind::AnonymousCreateParameter => {
+                        error = true;
+                        break;
+                    }
+                    // `PassThrough` is the normal case.
+                    // `new_error_lifetime`, which would usually be used in the case of `ReportError`,
+                    // is unsuitable here, as these can occur from missing lifetime parameters in a
+                    // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit
+                    // lifetime. Instead, we simply create an implicit lifetime, which will be checked
+                    // later, at which point a suitable error will be emitted.
+                    LifetimeRibKind::AnonymousPassThrough
+                    | LifetimeRibKind::AnonymousReportError
+                    | LifetimeRibKind::Item => break,
+                    _ => {}
+                }
+            }
+
+            if !missing {
+                continue;
+            }
+
+            let elided_lifetime_span = if segment.has_generic_args {
+                // If there are brackets, but not generic arguments, then use the opening bracket
+                segment.args_span.with_hi(segment.args_span.lo() + BytePos(1))
+            } else {
+                // If there are no brackets, use the identifier span.
+                // HACK: we use find_ancestor_inside to properly suggest elided spans in paths
+                // originating from macros, since the segment's span might be from a macro arg.
+                segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span)
+            };
+            if error {
+                let sess = self.r.session;
+                let mut err = rustc_errors::struct_span_err!(
+                    sess,
+                    path_span,
+                    E0726,
+                    "implicit elided lifetime not allowed here"
+                );
+                rustc_errors::add_elided_lifetime_in_path_suggestion(
+                    sess.source_map(),
+                    &mut err,
+                    expected_lifetimes,
+                    path_span,
+                    !segment.has_generic_args,
+                    elided_lifetime_span,
+                );
+                err.note("assuming a `'static` lifetime...");
+                err.emit();
+            } else {
+                self.r.lint_buffer.buffer_lint_with_diagnostic(
+                    lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
+                    segment_id,
+                    elided_lifetime_span,
+                    "hidden lifetime parameters in types are deprecated",
+                    lint::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
+                        expected_lifetimes,
+                        path_span,
+                        !segment.has_generic_args,
+                        elided_lifetime_span,
+                    ),
+                );
+            }
+        }
+    }
+
     /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
     /// label and reports an error if the label is not found or is unreachable.
     fn resolve_label(&self, mut label: Ident) -> Option<NodeId> {
@@ -944,15 +1376,20 @@ fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
     fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         debug!("resolve_adt");
         self.with_current_self_item(item, |this| {
-            this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                let item_def_id = this.r.local_def_id(item.id).to_def_id();
-                this.with_self_rib(
-                    Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
-                    |this| {
-                        visit::walk_item(this, item);
-                    },
-                );
-            });
+            this.with_generic_param_rib(
+                &generics.params,
+                ItemRibKind(HasGenericParams::Yes),
+                LifetimeRibKind::Generics { kind: LifetimeBinderKind::Item, span: generics.span },
+                |this| {
+                    let item_def_id = this.r.local_def_id(item.id).to_def_id();
+                    this.with_self_rib(
+                        Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
+                        |this| {
+                            visit::walk_item(this, item);
+                        },
+                    );
+                },
+            );
         });
     }
 
@@ -1004,18 +1441,33 @@ fn resolve_item(&mut self, item: &'ast Item) {
         debug!("(resolving item) resolving {} ({:?})", name, item.kind);
 
         match item.kind {
-            ItemKind::TyAlias(box TyAlias { ref generics, .. })
-            | ItemKind::Fn(box Fn { ref generics, .. }) => {
-                self.compute_num_lifetime_params(item.id, generics);
-                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    visit::walk_item(this, item)
-                });
+            ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes),
+                    LifetimeRibKind::Generics {
+                        kind: LifetimeBinderKind::Item,
+                        span: generics.span,
+                    },
+                    |this| visit::walk_item(this, item),
+                );
+            }
+
+            ItemKind::Fn(box Fn { ref generics, .. }) => {
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes),
+                    LifetimeRibKind::Generics {
+                        kind: LifetimeBinderKind::Function,
+                        span: generics.span,
+                    },
+                    |this| visit::walk_item(this, item),
+                );
             }
 
             ItemKind::Enum(_, ref generics)
             | ItemKind::Struct(_, ref generics)
             | ItemKind::Union(_, ref generics) => {
-                self.compute_num_lifetime_params(item.id, generics);
                 self.resolve_adt(item, generics);
             }
 
@@ -1026,72 +1478,113 @@ fn resolve_item(&mut self, item: &'ast Item) {
                 items: ref impl_items,
                 ..
             }) => {
-                self.compute_num_lifetime_params(item.id, generics);
                 self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
             }
 
             ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {
-                self.compute_num_lifetime_params(item.id, generics);
                 // Create a new rib for the trait-wide type parameters.
-                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let def = this.r.local_def_id(item.id).to_def_id();
-                    this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
-                        this.visit_generics(generics);
-                        walk_list!(this, visit_param_bound, bounds);
-
-                        let walk_assoc_item = |this: &mut Self, generics, item| {
-                            this.with_generic_param_rib(generics, AssocItemRibKind, |this| {
-                                visit::walk_assoc_item(this, item, AssocCtxt::Trait)
-                            });
-                        };
-
-                        this.with_trait_items(items, |this| {
-                            for item in items {
-                                match &item.kind {
-                                    AssocItemKind::Const(_, ty, default) => {
-                                        this.visit_ty(ty);
-                                        // Only impose the restrictions of `ConstRibKind` for an
-                                        // actual constant expression in a provided default.
-                                        if let Some(expr) = default {
-                                            // We allow arbitrary const expressions inside of associated consts,
-                                            // even if they are potentially not const evaluatable.
-                                            //
-                                            // Type parameters can already be used and as associated consts are
-                                            // not used as part of the type system, this is far less surprising.
-                                            this.with_constant_rib(
-                                                IsRepeatExpr::No,
-                                                true,
-                                                None,
-                                                |this| this.visit_expr(expr),
-                                            );
-                                        }
-                                    }
-                                    AssocItemKind::Fn(box Fn { generics, .. }) => {
-                                        walk_assoc_item(this, generics, item);
-                                    }
-                                    AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
-                                        walk_assoc_item(this, generics, item);
-                                    }
-                                    AssocItemKind::MacCall(_) => {
-                                        panic!("unexpanded macro in resolve!")
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes),
+                    LifetimeRibKind::Generics {
+                        kind: LifetimeBinderKind::Item,
+                        span: generics.span,
+                    },
+                    |this| {
+                        let local_def_id = this.r.local_def_id(item.id).to_def_id();
+                        this.with_self_rib(
+                            Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
+                            |this| {
+                                this.visit_generics(generics);
+                                walk_list!(this, visit_param_bound, bounds);
+
+                                let walk_assoc_item =
+                                    |this: &mut Self,
+                                     generics: &Generics,
+                                     kind,
+                                     item: &'ast AssocItem| {
+                                        this.with_generic_param_rib(
+                                            &generics.params,
+                                            AssocItemRibKind,
+                                            LifetimeRibKind::Generics { span: generics.span, kind },
+                                            |this| {
+                                                visit::walk_assoc_item(this, item, AssocCtxt::Trait)
+                                            },
+                                        );
+                                    };
+
+                                this.with_trait_items(items, |this| {
+                                    for item in items {
+                                        match &item.kind {
+                                            AssocItemKind::Const(_, ty, default) => {
+                                                this.visit_ty(ty);
+                                                // Only impose the restrictions of `ConstRibKind` for an
+                                                // actual constant expression in a provided default.
+                                                if let Some(expr) = default {
+                                                    // We allow arbitrary const expressions inside of associated consts,
+                                                    // even if they are potentially not const evaluatable.
+                                                    //
+                                                    // Type parameters can already be used and as associated consts are
+                                                    // not used as part of the type system, this is far less surprising.
+                                                    this.with_constant_rib(
+                                                        IsRepeatExpr::No,
+                                                        true,
+                                                        None,
+                                                        |this| this.visit_expr(expr),
+                                                    );
+                                                }
+                                            }
+                                            AssocItemKind::Fn(box Fn { generics, .. }) => {
+                                                walk_assoc_item(
+                                                    this,
+                                                    generics,
+                                                    LifetimeBinderKind::Function,
+                                                    item,
+                                                );
+                                            }
+                                            AssocItemKind::TyAlias(box TyAlias {
+                                                generics,
+                                                ..
+                                            }) => {
+                                                walk_assoc_item(
+                                                    this,
+                                                    generics,
+                                                    LifetimeBinderKind::Item,
+                                                    item,
+                                                );
+                                            }
+                                            AssocItemKind::MacCall(_) => {
+                                                panic!("unexpanded macro in resolve!")
+                                            }
+                                        };
                                     }
-                                };
-                            }
-                        });
-                    });
-                });
+                                });
+                            },
+                        );
+                    },
+                );
             }
 
             ItemKind::TraitAlias(ref generics, ref bounds) => {
-                self.compute_num_lifetime_params(item.id, generics);
                 // Create a new rib for the trait-wide type parameters.
-                self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let def = this.r.local_def_id(item.id).to_def_id();
-                    this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
-                        this.visit_generics(generics);
-                        walk_list!(this, visit_param_bound, bounds);
-                    });
-                });
+                self.with_generic_param_rib(
+                    &generics.params,
+                    ItemRibKind(HasGenericParams::Yes),
+                    LifetimeRibKind::Generics {
+                        kind: LifetimeBinderKind::Item,
+                        span: generics.span,
+                    },
+                    |this| {
+                        let local_def_id = this.r.local_def_id(item.id).to_def_id();
+                        this.with_self_rib(
+                            Res::SelfTy { trait_: Some(local_def_id), alias_to: None },
+                            |this| {
+                                this.visit_generics(generics);
+                                walk_list!(this, visit_param_bound, bounds);
+                            },
+                        );
+                    },
+                );
             }
 
             ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
@@ -1101,7 +1594,7 @@ fn resolve_item(&mut self, item: &'ast Item) {
             }
 
             ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
-                self.with_item_rib(HasGenericParams::No, |this| {
+                self.with_item_rib(|this| {
                     this.visit_ty(ty);
                     if let Some(expr) = expr {
                         let constant_item_kind = match item.kind {
@@ -1137,13 +1630,19 @@ fn resolve_item(&mut self, item: &'ast Item) {
         }
     }
 
-    fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: RibKind<'a>, f: F)
-    where
+    fn with_generic_param_rib<'c, F>(
+        &'c mut self,
+        params: &'c Vec<GenericParam>,
+        kind: RibKind<'a>,
+        lifetime_kind: LifetimeRibKind,
+        f: F,
+    ) where
         F: FnOnce(&mut Self),
     {
         debug!("with_generic_param_rib");
         let mut function_type_rib = Rib::new(kind);
         let mut function_value_rib = Rib::new(kind);
+        let mut function_lifetime_rib = LifetimeRib::new(lifetime_kind);
         let mut seen_bindings = FxHashMap::default();
 
         // We also can't shadow bindings from the parent item
@@ -1160,11 +1659,7 @@ fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: Rib
             add_bindings_for_ns(TypeNS);
         }
 
-        for param in &generics.params {
-            if let GenericParamKind::Lifetime = param.kind {
-                continue;
-            }
-
+        for param in params {
             let ident = param.ident.normalize_to_macros_2_0();
             debug!("with_generic_param_rib: {}", param.id);
 
@@ -1172,24 +1667,57 @@ fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: Rib
                 Entry::Occupied(entry) => {
                     let span = *entry.get();
                     let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, span);
-                    self.report_error(param.ident.span, err);
+                    if !matches!(param.kind, GenericParamKind::Lifetime) {
+                        self.report_error(param.ident.span, err);
+                    }
                 }
                 Entry::Vacant(entry) => {
                     entry.insert(param.ident.span);
                 }
             }
 
+            if param.ident.name == kw::UnderscoreLifetime {
+                rustc_errors::struct_span_err!(
+                    self.r.session,
+                    param.ident.span,
+                    E0637,
+                    "`'_` cannot be used here"
+                )
+                .span_label(param.ident.span, "`'_` is a reserved lifetime name")
+                .emit();
+                continue;
+            }
+
+            if param.ident.name == kw::StaticLifetime {
+                rustc_errors::struct_span_err!(
+                    self.r.session,
+                    param.ident.span,
+                    E0262,
+                    "invalid lifetime parameter name: `{}`",
+                    param.ident,
+                )
+                .span_label(param.ident.span, "'static is a reserved lifetime name")
+                .emit();
+                continue;
+            }
+
+            let def_id = self.r.local_def_id(param.id);
+
             // Plain insert (no renaming).
             let (rib, def_kind) = match param.kind {
                 GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam),
                 GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
-                _ => unreachable!(),
+                GenericParamKind::Lifetime => {
+                    function_lifetime_rib.bindings.insert(ident, ());
+                    continue;
+                }
             };
-            let res = Res::Def(def_kind, self.r.local_def_id(param.id).to_def_id());
+            let res = Res::Def(def_kind, def_id.to_def_id());
             self.r.record_partial_res(param.id, PartialRes::new(res));
             rib.bindings.insert(ident, res);
         }
 
+        self.lifetime_ribs.push(function_lifetime_rib);
         self.ribs[ValueNS].push(function_value_rib);
         self.ribs[TypeNS].push(function_type_rib);
 
@@ -1197,6 +1725,7 @@ fn with_generic_param_rib<'c, F>(&'c mut self, generics: &'c Generics, kind: Rib
 
         self.ribs[TypeNS].pop();
         self.ribs[ValueNS].pop();
+        self.lifetime_ribs.pop();
     }
 
     fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
@@ -1205,9 +1734,11 @@ fn with_label_rib(&mut self, kind: RibKind<'a>, f: impl FnOnce(&mut Self)) {
         self.label_ribs.pop();
     }
 
-    fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce(&mut Self)) {
-        let kind = ItemRibKind(has_generic_params);
-        self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
+    fn with_item_rib(&mut self, f: impl FnOnce(&mut Self)) {
+        let kind = ItemRibKind(HasGenericParams::No);
+        self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
+            this.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
+        })
     }
 
     // HACK(min_const_generics,const_evaluatable_unchecked): We
@@ -1318,128 +1849,137 @@ fn resolve_implementation(
     ) {
         debug!("resolve_implementation");
         // If applicable, create a rib for the type parameters.
-        self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
+        self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::ImplBlock }, |this| {
             // Dummy self type for better errors if `Self` is used in the trait path.
             this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
-                // Resolve the trait reference, if necessary.
-                this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
-                    let item_def_id = this.r.local_def_id(item_id);
-
-                    // Register the trait definitions from here.
-                    if let Some(trait_id) = trait_id {
-                        this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
-                    }
-
-                    let item_def_id = item_def_id.to_def_id();
-                    let res =
-                        Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
-                    this.with_self_rib(res, |this| {
-                        if let Some(trait_ref) = opt_trait_reference.as_ref() {
-                            // Resolve type arguments in the trait path.
-                            visit::walk_trait_ref(this, trait_ref);
+                this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter, |this| {
+                    // Resolve the trait reference, if necessary.
+                    this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
+                        let item_def_id = this.r.local_def_id(item_id);
+
+                        // Register the trait definitions from here.
+                        if let Some(trait_id) = trait_id {
+                            this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
                         }
-                        // Resolve the self type.
-                        this.visit_ty(self_type);
-                        // Resolve the generic parameters.
-                        this.visit_generics(generics);
-                        // Resolve the items within the impl.
-                        this.with_current_self_type(self_type, |this| {
-                            this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
-                                debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
-                                for item in impl_items {
-                                    use crate::ResolutionError::*;
-                                    match &item.kind {
-                                        AssocItemKind::Const(_default, _ty, _expr) => {
-                                            debug!("resolve_implementation AssocItemKind::Const");
-                                            // If this is a trait impl, ensure the const
-                                            // exists in trait
-                                            this.check_trait_item(
-                                                item.id,
-                                                item.ident,
-                                                &item.kind,
-                                                ValueNS,
-                                                item.span,
-                                                |i, s, c| ConstNotMemberOfTrait(i, s, c),
-                                            );
-
-                                            // We allow arbitrary const expressions inside of associated consts,
-                                            // even if they are potentially not const evaluatable.
-                                            //
-                                            // Type parameters can already be used and as associated consts are
-                                            // not used as part of the type system, this is far less surprising.
-                                            this.with_constant_rib(
-                                                IsRepeatExpr::No,
-                                                true,
-                                                None,
-                                                |this| {
-                                                    visit::walk_assoc_item(
-                                                        this,
-                                                        item,
-                                                        AssocCtxt::Impl,
-                                                    )
-                                                },
-                                            );
-                                        }
-                                        AssocItemKind::Fn(box Fn { generics, .. }) => {
-                                            debug!("resolve_implementation AssocItemKind::Fn");
-                                            // We also need a new scope for the impl item type parameters.
-                                            this.with_generic_param_rib(
-                                                generics,
-                                                AssocItemRibKind,
-                                                |this| {
-                                                    // If this is a trait impl, ensure the method
-                                                    // exists in trait
-                                                    this.check_trait_item(
-                                                        item.id,
-                                                        item.ident,
-                                                        &item.kind,
-                                                        ValueNS,
-                                                        item.span,
-                                                        |i, s, c| MethodNotMemberOfTrait(i, s, c),
-                                                    );
-
-                                                    visit::walk_assoc_item(
-                                                        this,
-                                                        item,
-                                                        AssocCtxt::Impl,
-                                                    )
-                                                },
-                                            );
-                                        }
-                                        AssocItemKind::TyAlias(box TyAlias {
-                                            generics, ..
-                                        }) => {
-                                            debug!("resolve_implementation AssocItemKind::TyAlias");
-                                            // We also need a new scope for the impl item type parameters.
-                                            this.with_generic_param_rib(
-                                                generics,
-                                                AssocItemRibKind,
-                                                |this| {
-                                                    // If this is a trait impl, ensure the type
-                                                    // exists in trait
-                                                    this.check_trait_item(
-                                                        item.id,
-                                                        item.ident,
-                                                        &item.kind,
-                                                        TypeNS,
-                                                        item.span,
-                                                        |i, s, c| TypeNotMemberOfTrait(i, s, c),
-                                                    );
 
-                                                    visit::walk_assoc_item(
-                                                        this,
-                                                        item,
-                                                        AssocCtxt::Impl,
-                                                    )
-                                                },
-                                            );
-                                        }
-                                        AssocItemKind::MacCall(_) => {
-                                            panic!("unexpanded macro in resolve!")
-                                        }
-                                    }
-                                }
-                            });
+                        let item_def_id = item_def_id.to_def_id();
+                        let res =
+                            Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
+                        this.with_self_rib(res, |this| {
+                            if let Some(trait_ref) = opt_trait_reference.as_ref() {
+                                // Resolve type arguments in the trait path.
+                                visit::walk_trait_ref(this, trait_ref);
+                            }
+                            // Resolve the self type.
+                            this.visit_ty(self_type);
+                            // Resolve the generic parameters.
+                            this.visit_generics(generics);
+
+                            // Resolve the items within the impl.
+                            this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough,
+                                |this| {
+                                    this.with_current_self_type(self_type, |this| {
+                                        this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
+                                            debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
+                                            for item in impl_items {
+                                                use crate::ResolutionError::*;
+                                                match &item.kind {
+                                                    AssocItemKind::Const(_default, _ty, _expr) => {
+                                                        debug!("resolve_implementation AssocItemKind::Const");
+                                                        // If this is a trait impl, ensure the const
+                                                        // exists in trait
+                                                        this.check_trait_item(
+                                                            item.id,
+                                                            item.ident,
+                                                            &item.kind,
+                                                            ValueNS,
+                                                            item.span,
+                                                            |i, s, c| ConstNotMemberOfTrait(i, s, c),
+                                                        );
+
+                                                        // We allow arbitrary const expressions inside of associated consts,
+                                                        // even if they are potentially not const evaluatable.
+                                                        //
+                                                        // Type parameters can already be used and as associated consts are
+                                                        // not used as part of the type system, this is far less surprising.
+                                                        this.with_constant_rib(
+                                                            IsRepeatExpr::No,
+                                                            true,
+                                                            None,
+                                                            |this| {
+                                                                visit::walk_assoc_item(
+                                                                    this,
+                                                                    item,
+                                                                    AssocCtxt::Impl,
+                                                                )
+                                                            },
+                                                        );
+                                                    }
+                                                    AssocItemKind::Fn(box Fn { generics, .. }) => {
+                                                        debug!("resolve_implementation AssocItemKind::Fn");
+                                                        // We also need a new scope for the impl item type parameters.
+                                                        this.with_generic_param_rib(
+                                                            &generics.params,
+                                                            AssocItemRibKind,
+                                                            LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Function },
+                                                            |this| {
+                                                                // If this is a trait impl, ensure the method
+                                                                // exists in trait
+                                                                this.check_trait_item(
+                                                                    item.id,
+                                                                    item.ident,
+                                                                    &item.kind,
+                                                                    ValueNS,
+                                                                    item.span,
+                                                                    |i, s, c| MethodNotMemberOfTrait(i, s, c),
+                                                                );
+
+                                                                visit::walk_assoc_item(
+                                                                    this,
+                                                                    item,
+                                                                    AssocCtxt::Impl,
+                                                                )
+                                                            },
+                                                        );
+                                                    }
+                                                    AssocItemKind::TyAlias(box TyAlias {
+                                                        generics, ..
+                                                    }) => {
+                                                        debug!("resolve_implementation AssocItemKind::TyAlias");
+                                                        // We also need a new scope for the impl item type parameters.
+                                                        this.with_generic_param_rib(
+                                                            &generics.params,
+                                                            AssocItemRibKind,
+                                                            LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Item },
+                                                            |this| {
+                                                                // If this is a trait impl, ensure the type
+                                                                // exists in trait
+                                                                this.check_trait_item(
+                                                                    item.id,
+                                                                    item.ident,
+                                                                    &item.kind,
+                                                                    TypeNS,
+                                                                    item.span,
+                                                                    |i, s, c| TypeNotMemberOfTrait(i, s, c),
+                                                                );
+
+                                                                visit::walk_assoc_item(
+                                                                    this,
+                                                                    item,
+                                                                    AssocCtxt::Impl,
+                                                                )
+                                                            },
+                                                        );
+                                                    }
+                                                    AssocItemKind::MacCall(_) => {
+                                                        panic!("unexpanded macro in resolve!")
+                                                    }
+                                                }
+                                            }
+                                        });
+                                    });
+                                },
+                            );
                         });
                     });
                 });
@@ -2117,6 +2657,7 @@ fn smart_resolve_path_fragment(
             self.r.record_partial_res(id, partial_res);
         }
 
+        self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize);
         partial_res
     }
 
@@ -2210,7 +2751,7 @@ fn resolve_qpath(
                 // trait to resolve.  In that case, we leave the `B`
                 // segment to be resolved by type-check.
                 return Ok(Some(PartialRes::with_unresolved_segments(
-                    Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)),
+                    Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()),
                     path.len(),
                 )));
             }
@@ -2576,20 +3117,51 @@ fn traits_in_scope(&mut self, ident: Ident, ns: Namespace) -> Vec<TraitCandidate
             Some((ident.name, ns)),
         )
     }
+}
+
+struct LifetimeCountVisitor<'a, 'b> {
+    r: &'b mut Resolver<'a>,
+}
 
-    fn compute_num_lifetime_params(&mut self, id: NodeId, generics: &Generics) {
-        let def_id = self.r.local_def_id(id);
-        let count = generics
-            .params
-            .iter()
-            .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }))
-            .count();
-        self.r.item_generics_num_lifetimes.insert(def_id, count);
+/// Walks the whole crate in DFS order, visiting each item, counting the declared number of
+/// lifetime generic parameters.
+impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_> {
+    fn visit_item(&mut self, item: &'ast Item) {
+        match &item.kind {
+            ItemKind::TyAlias(box TyAlias { ref generics, .. })
+            | ItemKind::Fn(box Fn { ref generics, .. })
+            | ItemKind::Enum(_, ref generics)
+            | ItemKind::Struct(_, ref generics)
+            | ItemKind::Union(_, ref generics)
+            | ItemKind::Impl(box Impl { ref generics, .. })
+            | ItemKind::Trait(box Trait { ref generics, .. })
+            | ItemKind::TraitAlias(ref generics, _) => {
+                let def_id = self.r.local_def_id(item.id);
+                let count = generics
+                    .params
+                    .iter()
+                    .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }))
+                    .count();
+                self.r.item_generics_num_lifetimes.insert(def_id, count);
+            }
+
+            ItemKind::Mod(..)
+            | ItemKind::ForeignMod(..)
+            | ItemKind::Static(..)
+            | ItemKind::Const(..)
+            | ItemKind::Use(..)
+            | ItemKind::ExternCrate(..)
+            | ItemKind::MacroDef(..)
+            | ItemKind::GlobalAsm(..)
+            | ItemKind::MacCall(..) => {}
+        }
+        visit::walk_item(self, item)
     }
 }
 
 impl<'a> Resolver<'a> {
     pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
+        visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate);
         let mut late_resolution_visitor = LateResolutionVisitor::new(self);
         visit::walk_crate(&mut late_resolution_visitor, krate);
         for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() {
index 0926f24ae70efb44f497a1a654e1d72c1d597423..d77cc917e2f9a2035c05fd4d3b7b303c4c19db7c 100644 (file)
@@ -1,6 +1,7 @@
 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
 use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
+use crate::late::{LifetimeBinderKind, LifetimeRibKind};
 use crate::path_names_to_string;
 use crate::{Finalize, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
@@ -19,7 +20,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::parse::feature_err;
 use rustc_span::edition::Edition;
@@ -351,7 +352,7 @@ pub(crate) fn smart_resolve_report_errors(
                 }
             })
             .collect::<Vec<_>>();
-        let crate_def_id = DefId::local(CRATE_DEF_INDEX);
+        let crate_def_id = CRATE_DEF_ID.to_def_id();
         if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
             let mut enum_candidates: Vec<_> = self
                 .r
@@ -1331,10 +1332,8 @@ fn lookup_typo_candidate(
                             names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
                                 self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
                                     |crate_id| {
-                                        let crate_mod = Res::Def(
-                                            DefKind::Mod,
-                                            DefId { krate: crate_id, index: CRATE_DEF_INDEX },
-                                        );
+                                        let crate_mod =
+                                            Res::Def(DefKind::Mod, crate_id.as_def_id());
 
                                         if filter_fn(crate_mod) {
                                             Some(TypoSuggestion::typo_from_res(
@@ -1793,83 +1792,118 @@ fn suggest_using_enum_variant(
             (*ident, within_scope)
         })
     }
-}
 
-impl<'tcx> LifetimeContext<'_, 'tcx> {
-    crate fn report_missing_lifetime_specifiers(
+    crate fn emit_undeclared_lifetime_error(
         &self,
-        spans: Vec<Span>,
-        count: usize,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        struct_span_err!(
-            self.tcx.sess,
-            spans,
-            E0106,
-            "missing lifetime specifier{}",
-            pluralize!(count)
-        )
-    }
+        lifetime_ref: &ast::Lifetime,
+        outer_lifetime_ref: Option<Ident>,
+    ) {
+        debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
+        let mut err = if let Some(outer) = outer_lifetime_ref {
+            let mut err = struct_span_err!(
+                self.r.session,
+                lifetime_ref.ident.span,
+                E0401,
+                "can't use generic parameters from outer item",
+            );
+            err.span_label(lifetime_ref.ident.span, "use of generic parameter from outer item");
+            err.span_label(outer.span, "lifetime parameter from outer item");
+            err
+        } else {
+            let mut err = struct_span_err!(
+                self.r.session,
+                lifetime_ref.ident.span,
+                E0261,
+                "use of undeclared lifetime name `{}`",
+                lifetime_ref.ident
+            );
+            err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
+            err
+        };
+        let mut suggest_note = true;
 
-    crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            lifetime_ref.span,
-            E0261,
-            "use of undeclared lifetime name `{}`",
-            lifetime_ref
-        );
-        err.span_label(lifetime_ref.span, "undeclared lifetime");
-        let mut suggested_spans = vec![];
-        for missing in &self.missing_named_lifetime_spots {
-            match missing {
-                MissingLifetimeSpot::Generics(generics) => {
-                    let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
-                        !matches!(
-                            p.kind,
-                            hir::GenericParamKind::Type { synthetic: true, .. }
-                                | hir::GenericParamKind::Lifetime {
-                                    kind: hir::LifetimeParamKind::Elided,
-                                }
-                        )
-                    }) {
-                        (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
-                    } else {
-                        (generics.span, format!("<{}>", lifetime_ref))
-                    };
-                    if suggested_spans.contains(&span) {
+        for rib in self.lifetime_ribs.iter().rev() {
+            match rib.kind {
+                LifetimeRibKind::Generics { span, kind } => {
+                    if !span.can_be_used_for_suggestions() && suggest_note {
+                        suggest_note = false; // Avoid displaying the same help multiple times.
+                        err.span_label(
+                            span,
+                            &format!(
+                                "lifetime `{}` is missing in item created through this procedural macro",
+                                lifetime_ref.ident,
+                            ),
+                        );
                         continue;
                     }
-                    suggested_spans.push(span);
-                    if span.can_be_used_for_suggestions() {
+
+                    let higher_ranked = matches!(
+                        kind,
+                        LifetimeBinderKind::BareFnType
+                            | LifetimeBinderKind::PolyTrait
+                            | LifetimeBinderKind::WhereBound
+                    );
+                    let (span, sugg) = if span.is_empty() {
+                        let sugg = format!(
+                            "{}<{}>{}",
+                            if higher_ranked { "for" } else { "" },
+                            lifetime_ref.ident,
+                            if higher_ranked { " " } else { "" },
+                        );
+                        (span, sugg)
+                    } else {
+                        let span =
+                            self.r.session.source_map().span_through_char(span, '<').shrink_to_hi();
+                        let sugg = format!("{}, ", lifetime_ref.ident);
+                        (span, sugg)
+                    };
+                    if higher_ranked {
+                        err.span_suggestion(
+                            span,
+                            &format!(
+                                "consider making the {} lifetime-generic with a new `{}` lifetime",
+                                kind.descr(),
+                                lifetime_ref
+                            ),
+                            sugg,
+                            Applicability::MaybeIncorrect,
+                        );
+                        err.note_once(
+                            "for more information on higher-ranked polymorphism, visit \
+                             https://doc.rust-lang.org/nomicon/hrtb.html",
+                        );
+                    } else {
                         err.span_suggestion(
                             span,
-                            &format!("consider introducing lifetime `{}` here", lifetime_ref),
+                            &format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
                             sugg,
                             Applicability::MaybeIncorrect,
                         );
                     }
                 }
-                MissingLifetimeSpot::HigherRanked { span, span_type } => {
-                    err.span_suggestion(
-                        *span,
-                        &format!(
-                            "consider making the {} lifetime-generic with a new `{}` lifetime",
-                            span_type.descr(),
-                            lifetime_ref
-                        ),
-                        span_type.suggestion(&lifetime_ref.to_string()),
-                        Applicability::MaybeIncorrect,
-                    );
-                    err.note(
-                        "for more information on higher-ranked polymorphism, visit \
-                         https://doc.rust-lang.org/nomicon/hrtb.html",
-                    );
-                }
+                LifetimeRibKind::Item => break,
                 _ => {}
             }
         }
+
         err.emit();
     }
+}
+
+impl<'tcx> LifetimeContext<'_, 'tcx> {
+    crate fn report_missing_lifetime_specifiers(
+        &self,
+        spans: Vec<Span>,
+        count: usize,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        struct_span_err!(
+            self.tcx.sess,
+            spans,
+            E0106,
+            "missing lifetime specifier{}",
+            pluralize!(count)
+        )
+    }
 
     /// Returns whether to add `'static` lifetime to the suggested lifetime list.
     crate fn report_elision_failure(
@@ -1950,38 +1984,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         }
     }
 
-    crate fn report_elided_lifetime_in_ty(&self, lifetime_refs: &[&hir::Lifetime]) {
-        let Some(missing_lifetime) = lifetime_refs.iter().find(|lt| {
-            lt.name == hir::LifetimeName::Implicit(true)
-        }) else { return };
-
-        let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
-        spans.sort();
-        let mut spans_dedup = spans.clone();
-        spans_dedup.dedup();
-        let spans_with_counts: Vec<_> = spans_dedup
-            .into_iter()
-            .map(|sp| (sp, spans.iter().filter(|nsp| *nsp == &sp).count()))
-            .collect();
-
-        self.tcx.struct_span_lint_hir(
-            rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
-            missing_lifetime.hir_id,
-            spans,
-            |lint| {
-                let mut db = lint.build("hidden lifetime parameters in types are deprecated");
-                self.add_missing_lifetime_specifiers_label(
-                    &mut db,
-                    spans_with_counts,
-                    &FxHashSet::from_iter([kw::UnderscoreLifetime]),
-                    Vec::new(),
-                    &[],
-                );
-                db.emit();
-            },
-        );
-    }
-
     // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
     // generics. We are disallowing this until we can decide on how we want to handle non-'static
     // lifetimes in const generics. See issue #74052 for discussion.
@@ -2416,9 +2418,7 @@ fn span_underscore_borrow(&self) -> Span {
         );
         let is_allowed_lifetime = matches!(
             lifetime_ref.name,
-            hir::LifetimeName::Implicit(_)
-                | hir::LifetimeName::Static
-                | hir::LifetimeName::Underscore
+            hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
         );
 
         if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
index 2bf01146fae027709d33c1af365940c4859eeb0d..d5f2e2db1e39b1851754fbbc0fed7d35c36b81fb 100644 (file)
@@ -164,9 +164,6 @@ struct NamedRegionMap {
     map: &'a mut NamedRegionMap,
     scope: ScopeRef<'a>,
 
-    /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
-    is_in_fn_syntax: bool,
-
     is_in_const_generic: bool,
 
     /// Indicates that we only care about the definition of a trait. This should
@@ -455,7 +452,6 @@ fn do_resolve(
         tcx,
         map: &mut named_region_map,
         scope: ROOT_SCOPE,
-        is_in_fn_syntax: false,
         is_in_const_generic: false,
         trait_definition_only,
         labels_in_fn: vec![],
@@ -874,8 +870,6 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
         match ty.kind {
             hir::TyKind::BareFn(ref c) => {
                 let next_early_index = self.next_early_index();
-                let was_in_fn_syntax = self.is_in_fn_syntax;
-                self.is_in_fn_syntax = true;
                 let lifetime_span: Option<Span> =
                     c.generic_params.iter().rev().find_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => Some(param.span),
@@ -917,7 +911,6 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     intravisit::walk_ty(this, ty);
                 });
                 self.missing_named_lifetime_spots.pop();
-                self.is_in_fn_syntax = was_in_fn_syntax;
             }
             hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
@@ -928,7 +921,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     }
                 });
                 match lifetime.name {
-                    LifetimeName::Implicit(_) => {
+                    LifetimeName::Implicit => {
                         // For types like `dyn Foo`, we should
                         // generate a special form of elided.
                         span_bug!(ty.span, "object-lifetime-default expected, not implicit",);
@@ -1805,7 +1798,6 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
             tcx: *tcx,
             map,
             scope: &wrap_scope,
-            is_in_fn_syntax: self.is_in_fn_syntax,
             is_in_const_generic: self.is_in_const_generic,
             trait_definition_only: self.trait_definition_only,
             labels_in_fn,
@@ -2320,7 +2312,10 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
 
             self.insert_lifetime(lifetime_ref, def);
         } else {
-            self.emit_undeclared_lifetime_error(lifetime_ref);
+            self.tcx.sess.delay_span_bug(
+                lifetime_ref.span,
+                &format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
+            );
         }
     }
 
@@ -2336,10 +2331,7 @@ fn visit_segment_args(
         );
 
         if generic_args.parenthesized {
-            let was_in_fn_syntax = self.is_in_fn_syntax;
-            self.is_in_fn_syntax = true;
             self.visit_fn_like_elision(generic_args.inputs(), Some(generic_args.bindings[0].ty()));
-            self.is_in_fn_syntax = was_in_fn_syntax;
             return;
         }
 
@@ -2963,9 +2955,9 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
         let error = loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
-                Scope::Body { .. } => break Ok(()),
+                Scope::Body { .. } => return,
 
-                Scope::Root => break Err(None),
+                Scope::Root => break None,
 
                 Scope::Binder { s, ref lifetimes, scope_type, .. } => {
                     // collect named lifetimes for suggestions
@@ -2992,7 +2984,7 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
 
                         self.insert_lifetime(lifetime_ref, lifetime);
                     }
-                    break Ok(());
+                    return;
                 }
 
                 Scope::Elision { elide: Elide::Exact(l), .. } => {
@@ -3000,7 +2992,7 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
                     for lifetime_ref in lifetime_refs {
                         self.insert_lifetime(lifetime_ref, lifetime);
                     }
-                    break Ok(());
+                    return;
                 }
 
                 Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
@@ -3025,10 +3017,10 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
                             _ => break,
                         }
                     }
-                    break Err(Some(&e[..]));
+                    break Some(&e[..]);
                 }
 
-                Scope::Elision { elide: Elide::Forbid, .. } => break Err(None),
+                Scope::Elision { elide: Elide::Forbid, .. } => break None,
 
                 Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
@@ -3038,14 +3030,6 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
             }
         };
 
-        let error = match error {
-            Ok(()) => {
-                self.report_elided_lifetime_in_ty(lifetime_refs);
-                return;
-            }
-            Err(error) => error,
-        };
-
         // If we specifically need the `scope_for_path` map, then we're in the
         // diagnostic pass and we don't want to emit more errors.
         if self.map.scope_for_path.is_some() {
@@ -3130,18 +3114,10 @@ fn check_lifetime_params(
             if let hir::ParamName::Plain(_) = lifetime_i_name {
                 let name = lifetime_i_name.ident().name;
                 if name == kw::UnderscoreLifetime || name == kw::StaticLifetime {
-                    let mut err = struct_span_err!(
-                        self.tcx.sess,
-                        lifetime_i.span,
-                        E0262,
-                        "invalid lifetime parameter name: `{}`",
-                        lifetime_i.name.ident(),
-                    );
-                    err.span_label(
+                    self.tcx.sess.delay_span_bug(
                         lifetime_i.span,
-                        format!("{} is a reserved lifetime name", name),
+                        &format!("invalid lifetime parameter name: `{}`", lifetime_i.name.ident()),
                     );
-                    err.emit();
                 }
             }
 
@@ -3190,7 +3166,7 @@ fn check_lifetime_params(
                                 ))
                                 .emit();
                         }
-                        hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit(_) => {
+                        hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => {
                             self.resolve_lifetime_ref(lt);
                         }
                         hir::LifetimeName::ImplicitObjectLifetimeDefault => {
index 0335c40d70d8c57eb899a245d754d4e31d867a4a..4dfb7aef86f5a7f01c63e52e7b751777edd3df71 100644 (file)
@@ -11,6 +11,7 @@
 #![feature(drain_filter)]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
+#![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
@@ -27,7 +28,7 @@
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
-use rustc_ast::{Crate, Expr, ExprKind, LitKind, Path};
+use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::intern::Interned;
@@ -37,7 +38,7 @@
 use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId};
-use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::TraitCandidate;
 use rustc_index::vec::IndexVec;
@@ -282,6 +283,9 @@ pub struct Segment {
     /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
     /// nonsensical suggestions.
     has_generic_args: bool,
+    /// Signals whether this `PathSegment` has lifetime arguments.
+    has_lifetime_args: bool,
+    args_span: Span,
 }
 
 impl Segment {
@@ -290,7 +294,23 @@ fn from_path(path: &Path) -> Vec<Segment> {
     }
 
     fn from_ident(ident: Ident) -> Segment {
-        Segment { ident, id: None, has_generic_args: false }
+        Segment {
+            ident,
+            id: None,
+            has_generic_args: false,
+            has_lifetime_args: false,
+            args_span: DUMMY_SP,
+        }
+    }
+
+    fn from_ident_and_id(ident: Ident, id: NodeId) -> Segment {
+        Segment {
+            ident,
+            id: Some(id),
+            has_generic_args: false,
+            has_lifetime_args: false,
+            args_span: DUMMY_SP,
+        }
     }
 
     fn names_to_string(segments: &[Segment]) -> String {
@@ -300,7 +320,28 @@ fn names_to_string(segments: &[Segment]) -> String {
 
 impl<'a> From<&'a ast::PathSegment> for Segment {
     fn from(seg: &'a ast::PathSegment) -> Segment {
-        Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() }
+        let has_generic_args = seg.args.is_some();
+        let (args_span, has_lifetime_args) = if let Some(args) = seg.args.as_deref() {
+            match args {
+                GenericArgs::AngleBracketed(args) => {
+                    let found_lifetimes = args
+                        .args
+                        .iter()
+                        .any(|arg| matches!(arg, AngleBracketedArg::Arg(GenericArg::Lifetime(_))));
+                    (args.span, found_lifetimes)
+                }
+                GenericArgs::Parenthesized(args) => (args.span, true),
+            }
+        } else {
+            (DUMMY_SP, false)
+        };
+        Segment {
+            ident: seg.ident,
+            id: Some(seg.id),
+            has_generic_args,
+            has_lifetime_args,
+            args_span,
+        }
     }
 }
 
@@ -755,7 +796,7 @@ fn is_extern_crate(&self) -> bool {
             NameBindingKind::Module(&ModuleData {
                 kind: ModuleKind::Def(DefKind::Mod, def_id, _),
                 ..
-            }) => def_id.index == CRATE_DEF_INDEX,
+            }) => def_id.is_crate_root(),
             _ => false,
         }
     }
@@ -1207,18 +1248,17 @@ pub fn new(
         );
 
         let definitions = Definitions::new(session.local_stable_crate_id(), krate.spans.inner_span);
-        let root = definitions.get_root_def();
 
         let mut visibilities = FxHashMap::default();
         visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public);
 
         let mut def_id_to_node_id = IndexVec::default();
-        assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
+        assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), CRATE_DEF_ID);
         let mut node_id_to_def_id = FxHashMap::default();
-        node_id_to_def_id.insert(CRATE_NODE_ID, root);
+        node_id_to_def_id.insert(CRATE_NODE_ID, CRATE_DEF_ID);
 
         let mut invocation_parents = FxHashMap::default();
-        invocation_parents.insert(LocalExpnId::ROOT, (root, ImplTraitContext::Existential));
+        invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential));
 
         let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
             .opts
@@ -1358,9 +1398,17 @@ fn new_module(
     }
 
     pub fn next_node_id(&mut self) -> NodeId {
-        let next =
-            self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
-        mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next))
+        let start = self.next_node_id;
+        let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+        self.next_node_id = ast::NodeId::from_u32(next);
+        start
+    }
+
+    pub fn next_node_ids(&mut self, count: usize) -> std::ops::Range<NodeId> {
+        let start = self.next_node_id;
+        let end = start.as_usize().checked_add(count).expect("input too large; ran out of NodeIds");
+        self.next_node_id = ast::NodeId::from_usize(end);
+        start..self.next_node_id
     }
 
     pub fn lint_buffer(&mut self) -> &mut LintBuffer {
index 5a447aa6237345f2e6c608666f90bf0fecc34a8f..12c5c4445d46f333c9437fd7270a81afac91692a 100644 (file)
@@ -3,20 +3,18 @@
 
 pub use crate::options::*;
 
-use crate::lint;
 use crate::search_paths::SearchPath;
 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use crate::{early_error, early_warn, Session};
+use crate::{lint, HashStableContext};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::impl_stable_hash_via_hash;
 
+use rustc_data_structures::stable_hasher::ToStableHashKey;
 use rustc_target::abi::{Align, TargetDataLayout};
 use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
 use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
 
-use rustc_serialize::json;
-
 use crate::parse::{CrateCheckConfig, CrateConfig};
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
@@ -80,7 +78,7 @@ pub enum CFProtection {
     Full,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
 pub enum OptLevel {
     No,         // -O0
     Less,       // -O1
@@ -90,8 +88,6 @@ pub enum OptLevel {
     SizeMin,    // -Oz
 }
 
-impl_stable_hash_via_hash!(OptLevel);
-
 /// This is what the `LtoCli` values get mapped to after resolving defaults and
 /// and taking other command line options into account.
 ///
@@ -232,15 +228,13 @@ pub fn enabled(&self) -> bool {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
 #[derive(Encodable, Decodable)]
 pub enum SymbolManglingVersion {
     Legacy,
     V0,
 }
 
-impl_stable_hash_via_hash!(SymbolManglingVersion);
-
 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
 pub enum DebugInfo {
     None,
@@ -279,7 +273,7 @@ fn from_str(s: &str) -> Result<Self, ()> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
 #[derive(Encodable, Decodable)]
 pub enum OutputType {
     Bitcode,
@@ -292,7 +286,13 @@ pub enum OutputType {
     DepInfo,
 }
 
-impl_stable_hash_via_hash!(OutputType);
+impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
+    type KeyType = Self;
+
+    fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
+        *self
+    }
+}
 
 impl OutputType {
     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
@@ -398,7 +398,7 @@ pub enum TrimmedDefPaths {
 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
 /// should only depend on the output types, not the paths they're written to.
-#[derive(Clone, Debug, Hash)]
+#[derive(Clone, Debug, Hash, HashStable_Generic)]
 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
 
 impl OutputTypes {
@@ -460,9 +460,6 @@ pub fn should_link(&self) -> bool {
 #[derive(Clone)]
 pub struct Externs(BTreeMap<String, ExternEntry>);
 
-#[derive(Clone)]
-pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
-
 #[derive(Clone, Debug)]
 pub struct ExternEntry {
     pub location: ExternLocation,
@@ -494,27 +491,6 @@ pub enum ExternLocation {
     ExactPaths(BTreeSet<CanonicalizedPath>),
 }
 
-/// Supplied source location of a dependency - for example in a build specification
-/// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
-/// a file and line, then the build system can specify that. On the other hand, it may
-/// make more sense to have an arbitrary raw string.
-#[derive(Clone, PartialEq)]
-pub enum ExternDepSpec {
-    /// Raw string
-    Raw(String),
-    /// Raw data in json format
-    Json(json::Json),
-}
-
-impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
-    fn from(from: &'a ExternDepSpec) -> Self {
-        match from {
-            ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
-            ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
-        }
-    }
-}
-
 impl Externs {
     /// Used for testing.
     pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
@@ -547,25 +523,6 @@ pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
     }
 }
 
-impl ExternDepSpecs {
-    pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
-        ExternDepSpecs(data)
-    }
-
-    pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
-        self.0.get(key)
-    }
-}
-
-impl fmt::Display for ExternDepSpec {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            ExternDepSpec::Raw(raw) => fmt.write_str(raw),
-            ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
-        }
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PrintRequest {
     FileNames,
@@ -630,7 +587,7 @@ pub fn source_name(&self) -> FileName {
     }
 }
 
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Hash, Debug, HashStable_Generic)]
 pub struct OutputFilenames {
     pub out_directory: PathBuf,
     filestem: String,
@@ -639,8 +596,6 @@ pub struct OutputFilenames {
     pub outputs: OutputTypes,
 }
 
-impl_stable_hash_via_hash!(OutputFilenames);
-
 pub const RLINK_EXT: &str = "rlink";
 pub const RUST_CGU_EXT: &str = "rcgu";
 pub const DWARF_OBJECT_EXT: &str = "dwo";
@@ -785,7 +740,6 @@ fn default() -> Options {
             cg: Default::default(),
             error_format: ErrorOutputType::default(),
             externs: Externs(BTreeMap::new()),
-            extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
             crate_name: None,
             libs: Vec::new(),
             unstable_features: UnstableFeatures::Disallow,
@@ -854,15 +808,14 @@ pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags
 }
 
 // The type of entry function, so users can have their own entry functions
-#[derive(Copy, Clone, PartialEq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
 pub enum EntryFnType {
     Main,
     Start,
 }
 
-impl_stable_hash_via_hash!(EntryFnType);
-
 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
 pub enum CrateType {
     Executable,
     Dylib,
@@ -872,8 +825,6 @@ pub enum CrateType {
     ProcMacro,
 }
 
-impl_stable_hash_via_hash!(CrateType);
-
 impl CrateType {
     /// When generated, is this crate type an archive?
     pub fn is_archive(&self) -> bool {
@@ -1454,12 +1405,6 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
             "Specify where an external rust library is located",
             "NAME[=PATH]",
         ),
-        opt::multi_s(
-            "",
-            "extern-location",
-            "Location where an external crate dependency is specified",
-            "NAME=LOCATION",
-        ),
         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
         opt::opt_s(
@@ -2221,68 +2166,6 @@ pub fn parse_externs(
     Externs(externs)
 }
 
-fn parse_extern_dep_specs(
-    matches: &getopts::Matches,
-    debugging_opts: &DebuggingOptions,
-    error_format: ErrorOutputType,
-) -> ExternDepSpecs {
-    let is_unstable_enabled = debugging_opts.unstable_options;
-    let mut map = BTreeMap::new();
-
-    for arg in matches.opt_strs("extern-location") {
-        if !is_unstable_enabled {
-            early_error(
-                error_format,
-                "`--extern-location` option is unstable: set `-Z unstable-options`",
-            );
-        }
-
-        let mut parts = arg.splitn(2, '=');
-        let name = parts.next().unwrap_or_else(|| {
-            early_error(error_format, "`--extern-location` value must not be empty")
-        });
-        let loc = parts.next().unwrap_or_else(|| {
-            early_error(
-                error_format,
-                &format!("`--extern-location`: specify location for extern crate `{name}`"),
-            )
-        });
-
-        let locparts: Vec<_> = loc.split(':').collect();
-        let spec = match &locparts[..] {
-            ["raw", ..] => {
-                // Don't want `:` split string
-                let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
-                    early_error(error_format, "`--extern-location`: missing `raw` location")
-                });
-                ExternDepSpec::Raw(raw.to_string())
-            }
-            ["json", ..] => {
-                // Don't want `:` split string
-                let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
-                    early_error(error_format, "`--extern-location`: missing `json` location")
-                });
-                let json = json::from_str(raw).unwrap_or_else(|_| {
-                    early_error(
-                        error_format,
-                        &format!("`--extern-location`: malformed json location `{raw}`"),
-                    )
-                });
-                ExternDepSpec::Json(json)
-            }
-            [bad, ..] => early_error(
-                error_format,
-                &format!("unknown location type `{bad}`: use `raw` or `json`"),
-            ),
-            [] => early_error(error_format, "missing location specification"),
-        };
-
-        map.insert(name.to_string(), spec);
-    }
-
-    ExternDepSpecs::new(map)
-}
-
 fn parse_remap_path_prefix(
     matches: &getopts::Matches,
     debugging_opts: &DebuggingOptions,
@@ -2525,7 +2408,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     }
 
     let externs = parse_externs(matches, &debugging_opts, error_format);
-    let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
 
     let crate_name = matches.opt_str("crate-name");
 
@@ -2601,7 +2483,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         error_format,
         externs,
         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
-        extern_dep_specs,
         crate_name,
         libs,
         debug_assertions,
index 4994f8eaeb2dcaae287369413334f0710c10c62b..df65409a8a063b1c7e87994b5d2a0ed31f93f939 100644 (file)
@@ -183,7 +183,6 @@ pub struct Options {
         borrowck_mode: BorrowckMode [UNTRACKED],
         cg: CodegenOptions [SUBSTRUCT],
         externs: Externs [UNTRACKED],
-        extern_dep_specs: ExternDepSpecs [UNTRACKED],
         crate_name: Option<String> [TRACKED],
         /// Indicates how the compiler should treat unstable features.
         unstable_features: UnstableFeatures [TRACKED],
index b6bde28233d243bc2ad86c0e5619111f3bc1d6d7..56a6b6f3b03efe6d18c98fd80ad69e1fa6c5af2c 100644 (file)
@@ -26,7 +26,7 @@ pub struct SearchPathFile {
     pub file_name_str: String,
 }
 
-#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable)]
+#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable, HashStable_Generic)]
 pub enum PathKind {
     Native,
     Crate,
@@ -36,8 +36,6 @@ pub enum PathKind {
     All,
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(PathKind);
-
 impl PathKind {
     pub fn matches(&self, kind: PathKind) -> bool {
         match (self, kind) {
index 9a286d94ab89da3aa65042e8d9b14fba2e268acd..8064c217457bb561bc66185b27d75822f0fbce1e 100644 (file)
@@ -18,6 +18,7 @@ pub fn time<R>(&self, what: &'static str, f: impl FnOnce() -> R) -> R {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
 pub enum NativeLibKind {
     /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC)
     Static {
@@ -57,9 +58,8 @@ pub fn has_modifiers(&self) -> bool {
     }
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
-
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
 pub struct NativeLib {
     pub name: String,
     pub new_name: Option<String>,
@@ -73,8 +73,6 @@ pub fn has_modifiers(&self) -> bool {
     }
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLib);
-
 /// A path that has been canonicalized along with its original, non-canonicalized form
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub struct CanonicalizedPath {
index 6d1b36796d869fec88463521d022bc76dea66489..d5f806308cf41bbca3b16ea67cd7f1fe77278fd5 100644 (file)
@@ -283,8 +283,19 @@ pub fn expect_local(self) -> LocalDefId {
         self.as_local().unwrap_or_else(|| panic!("DefId::expect_local: `{:?}` isn't local", self))
     }
 
+    #[inline]
+    pub fn is_crate_root(self) -> bool {
+        self.index == CRATE_DEF_INDEX
+    }
+
+    #[inline]
+    pub fn as_crate_root(self) -> Option<CrateNum> {
+        if self.is_crate_root() { Some(self.krate) } else { None }
+    }
+
+    #[inline]
     pub fn is_top_level_module(self) -> bool {
-        self.is_local() && self.index == CRATE_DEF_INDEX
+        self.is_local() && self.is_crate_root()
     }
 }
 
@@ -357,7 +368,7 @@ pub fn to_def_id(self) -> DefId {
 
     #[inline]
     pub fn is_top_level_module(self) -> bool {
-        self.local_def_index == CRATE_DEF_INDEX
+        self == CRATE_DEF_ID
     }
 }
 
index 7ebf323e20d8889dacd9dc4c2aab2399c67ca9e8..3889639b50f454bf232b430c17bbf9ff86397db1 100644 (file)
@@ -103,16 +103,6 @@ impl !PartialOrd for LocalExpnId {}
 /// of `HashingControls` settings.
 fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
     match ctx.hashing_controls() {
-        // Ideally, we would also check that `node_id_hashing_mode` was always
-        // `NodeIdHashingMode::HashDefPath`. However, we currently end up hashing
-        // `Span`s in this mode, and there's not an easy way to change that.
-        // All of the span-related data that we hash is pretty self-contained
-        // (in particular, we don't hash any `HirId`s), so this shouldn't result
-        // in any caching problems.
-        // FIXME: Enforce that we don't end up transitively hashing any `HirId`s,
-        // or ensure that this method is always invoked with the same
-        // `NodeIdHashingMode`
-        //
         // Note that we require that `hash_spans` be set according to the global
         // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
         // which will cause us to require that this method always be called with `Span` hashing
index b132c0a2132b724b0077f3019432112d4a1ba55e..b0307cc20d174f39645a81d5a8f7646ff515eda9 100644 (file)
@@ -1130,6 +1130,7 @@ pub fn get_source(&self) -> Option<&Lrc<String>> {
 pub struct OffsetOverflowError;
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
 pub enum SourceFileHashAlgorithm {
     Md5,
     Sha1,
@@ -1149,8 +1150,6 @@ fn from_str(s: &str) -> Result<SourceFileHashAlgorithm, ()> {
     }
 }
 
-rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm);
-
 /// The hash of the on-disk source file used for debug info.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
index d9bada295894f314be2b5c90268a155a19a0c3b7..e3ce8105a8b47a825ccb5499944993015f4bea92 100644 (file)
         keyword,
         kind,
         kreg,
+        kreg0,
         label,
         label_break_value,
         lang,
index 5bc4b566daf67f86a241082c544ba75b90a6444d..6bc807c7c4421649f89e81867da730d26a88b733 100644 (file)
@@ -893,7 +893,7 @@ macro_rules! clobbered_regs {
 
                     xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
 
-                    k1, k2, k3, k4, k5, k6, k7,
+                    k0, k1, k2, k3, k4, k5, k6, k7,
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
@@ -908,7 +908,7 @@ macro_rules! clobbered_regs {
                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
 
-                    k1, k2, k3, k4, k5, k6, k7,
+                    k0, k1, k2, k3, k4, k5, k6, k7,
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
@@ -927,7 +927,7 @@ macro_rules! clobbered_regs {
                     zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
                     zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
 
-                    k1, k2, k3, k4, k5, k6, k7,
+                    k0, k1, k2, k3, k4, k5, k6, k7,
 
                     mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
                     st0, st1, st2, st3, st4, st5, st6, st7,
index 7c136a475486b63eb835a2e3bdac065f6204f54a..854674c7f2fa7c98804c4ce6cc28bc9d5c483a9b 100644 (file)
@@ -14,6 +14,7 @@
         ymm_reg,
         zmm_reg,
         kreg,
+        kreg0,
         mmx_reg,
         x87_reg,
     }
@@ -38,7 +39,7 @@ pub fn valid_modifiers(self, arch: super::InlineAsmArch) -> &'static [char] {
             }
             Self::reg_byte => &[],
             Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
-            Self::kreg => &[],
+            Self::kreg | Self::kreg0 => &[],
             Self::mmx_reg | Self::x87_reg => &[],
         }
     }
@@ -77,7 +78,7 @@ pub fn suggest_modifier(
                 256 => Some(('y', "ymm0")),
                 _ => Some(('x', "xmm0")),
             },
-            Self::kreg => None,
+            Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
         }
     }
@@ -95,7 +96,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
             Self::xmm_reg => Some(('x', "xmm0")),
             Self::ymm_reg => Some(('y', "ymm0")),
             Self::zmm_reg => Some(('z', "zmm0")),
-            Self::kreg => None,
+            Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
         }
     }
@@ -132,6 +133,7 @@ pub fn supported_types(
                 avx512f: I8, I16;
                 avx512bw: I32, I64;
             },
+            Self::kreg0 => &[],
             Self::mmx_reg | Self::x87_reg => &[],
         }
     }
@@ -294,6 +296,7 @@ fn esi_reserved(
         zmm29: zmm_reg = ["zmm29", "xmm29", "ymm29"] % x86_64_only,
         zmm30: zmm_reg = ["zmm30", "xmm30", "ymm30"] % x86_64_only,
         zmm31: zmm_reg = ["zmm31", "xmm31", "ymm31"] % x86_64_only,
+        k0: kreg0 = ["k0"],
         k1: kreg = ["k1"],
         k2: kreg = ["k2"],
         k3: kreg = ["k3"],
@@ -323,8 +326,6 @@ fn esi_reserved(
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["ip", "eip", "rip"] =>
             "the instruction pointer cannot be used as an operand for inline asm",
-        #error = ["k0"] =>
-            "the k0 AVX mask register cannot be used as an operand for inline asm",
     }
 }
 
index 7485c082f4eaf5af2b542719f7a204dccb038ebe..0c1ca65c48f6adb9230785eb5e494973c04cc70c 100644 (file)
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
-    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
+    TypeFoldable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -44,6 +46,123 @@ pub enum GeneratorInteriorOrUpvar {
     Upvar(Span),
 }
 
+// This type provides a uniform interface to retrieve data on generators, whether it originated from
+// the local crate being compiled or from a foreign crate.
+#[derive(Debug)]
+pub enum GeneratorData<'tcx, 'a> {
+    Local(&'a TypeckResults<'tcx>),
+    Foreign(&'tcx GeneratorDiagnosticData<'tcx>),
+}
+
+impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
+    // Try to get information about variables captured by the generator that matches a type we are
+    // looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
+    // meet an obligation
+    fn try_get_upvar_span<F>(
+        &self,
+        infer_context: &InferCtxt<'a, 'tcx>,
+        generator_did: DefId,
+        ty_matches: F,
+    ) -> Option<GeneratorInteriorOrUpvar>
+    where
+        F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+    {
+        match self {
+            GeneratorData::Local(typeck_results) => {
+                infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
+                    upvars.iter().find_map(|(upvar_id, upvar)| {
+                        let upvar_ty = typeck_results.node_type(*upvar_id);
+                        let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
+                        if ty_matches(ty::Binder::dummy(upvar_ty)) {
+                            Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+                        } else {
+                            None
+                        }
+                    })
+                })
+            }
+            GeneratorData::Foreign(_) => None,
+        }
+    }
+
+    // Try to get the span of a type being awaited on that matches the type we are looking with the
+    // `ty_matches` function. We uses it to find awaited type which causes a failure to meet an
+    // obligation
+    fn get_from_await_ty<F>(
+        &self,
+        visitor: AwaitsVisitor,
+        hir: map::Map<'tcx>,
+        ty_matches: F,
+    ) -> Option<Span>
+    where
+        F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+    {
+        match self {
+            GeneratorData::Local(typeck_results) => visitor
+                .awaits
+                .into_iter()
+                .map(|id| hir.expect_expr(id))
+                .find(|await_expr| {
+                    ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+                })
+                .map(|expr| expr.span),
+            GeneratorData::Foreign(generator_diagnostic_data) => visitor
+                .awaits
+                .into_iter()
+                .map(|id| hir.expect_expr(id))
+                .find(|await_expr| {
+                    ty_matches(ty::Binder::dummy(
+                        generator_diagnostic_data
+                            .adjustments
+                            .get(&await_expr.hir_id.local_id)
+                            .map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..])
+                            .last()
+                            .map_or_else::<Ty<'tcx>, _, _>(
+                                || {
+                                    generator_diagnostic_data
+                                        .nodes_types
+                                        .get(&await_expr.hir_id.local_id)
+                                        .cloned()
+                                        .unwrap_or_else(|| {
+                                            bug!(
+                                                "node_type: no type for node `{}`",
+                                                ty::tls::with(|tcx| tcx
+                                                    .hir()
+                                                    .node_to_string(await_expr.hir_id))
+                                            )
+                                        })
+                                },
+                                |adj| adj.target,
+                            ),
+                    ))
+                })
+                .map(|expr| expr.span),
+        }
+    }
+
+    /// Get the type, expression, span and optional scope span of all types
+    /// that are live across the yield of this generator
+    fn get_generator_interior_types(
+        &self,
+    ) -> ty::Binder<'tcx, &Vec<GeneratorInteriorTypeCause<'tcx>>> {
+        match self {
+            GeneratorData::Local(typeck_result) => typeck_result.generator_interior_types.as_ref(),
+            GeneratorData::Foreign(generator_diagnostic_data) => {
+                generator_diagnostic_data.generator_interior_types.as_ref()
+            }
+        }
+    }
+
+    // Used to get the source of the data, note we don't have as much information for generators
+    // originated from foreign crates
+    fn is_foreign(&self) -> bool {
+        match self {
+            GeneratorData::Local(_) => false,
+            GeneratorData::Foreign(_) => true,
+        }
+    }
+}
+
 // This trait is public to expose the diagnostics methods to clippy.
 pub trait InferCtxtExt<'tcx> {
     fn suggest_restricting_param_bound(
@@ -152,7 +271,7 @@ fn note_obligation_cause_for_async_await(
         err: &mut Diagnostic,
         interior_or_upvar_span: GeneratorInteriorOrUpvar,
         interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
-        inner_generator_body: Option<&hir::Body<'tcx>>,
+        is_async: bool,
         outer_generator: Option<DefId>,
         trait_pred: ty::TraitPredicate<'tcx>,
         target_ty: Ty<'tcx>,
@@ -1642,6 +1761,17 @@ fn maybe_note_obligation_cause_for_async_await(
             .map(|def_id| hir.local_def_id_to_hir_id(def_id))
             .and_then(|hir_id| hir.maybe_body_owned_by(hir_id))
             .map(|body_id| hir.body(body_id));
+        let is_async = match generator_did.as_local() {
+            Some(_) => generator_body
+                .and_then(|body| body.generator_kind())
+                .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+                .unwrap_or(false),
+            None => self
+                .tcx
+                .generator_kind(generator_did)
+                .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+                .unwrap_or(false),
+        };
         let mut visitor = AwaitsVisitor::default();
         if let Some(body) = generator_body {
             visitor.visit_body(body);
@@ -1682,61 +1812,55 @@ fn maybe_note_obligation_cause_for_async_await(
         // type-checking; otherwise, get them by performing a query.  This is needed to avoid
         // cycles. If we can't use resolved types because the generator comes from another crate,
         // we still provide a targeted error but without all the relevant spans.
-        let query_typeck_results;
-        let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
-            Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
+        let generator_data: Option<GeneratorData<'tcx, '_>> = match &in_progress_typeck_results {
+            Some(t) if t.hir_owner.to_def_id() == generator_did_root => {
+                Some(GeneratorData::Local(&t))
+            }
             _ if generator_did.is_local() => {
-                query_typeck_results = self.tcx.typeck(generator_did.expect_local());
-                Some(&query_typeck_results)
+                Some(GeneratorData::Local(self.tcx.typeck(generator_did.expect_local())))
             }
-            _ => None, // Do not ICE on closure typeck (#66868).
+            _ => self
+                .tcx
+                .generator_diagnostic_data(generator_did)
+                .as_ref()
+                .map(|generator_diag_data| GeneratorData::Foreign(generator_diag_data)),
         };
-        if let Some(typeck_results) = typeck_results {
-            if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
-                interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
-                    let upvar_ty = typeck_results.node_type(*upvar_id);
-                    let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
-                    if ty_matches(ty::Binder::dummy(upvar_ty)) {
-                        Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
-                    } else {
-                        None
-                    }
-                });
-            };
+
+        if let Some(generator_data) = generator_data.as_ref() {
+            interior_or_upvar_span =
+                generator_data.try_get_upvar_span(&self, generator_did, ty_matches);
 
             // The generator interior types share the same binders
             if let Some(cause) =
-                typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
+                generator_data.get_generator_interior_types().skip_binder().iter().find(
                     |ty::GeneratorInteriorTypeCause { ty, .. }| {
-                        ty_matches(typeck_results.generator_interior_types.rebind(*ty))
+                        ty_matches(generator_data.get_generator_interior_types().rebind(*ty))
                     },
                 )
             {
-                // Check to see if any awaited expressions have the target type.
-                let from_awaited_ty = visitor
-                    .awaits
-                    .into_iter()
-                    .map(|id| hir.expect_expr(id))
-                    .find(|await_expr| {
-                        ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
-                    })
-                    .map(|expr| expr.span);
+                let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
                 let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
                     cause;
 
                 interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
                 interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
-            };
-        } else {
-            interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+            }
+
+            if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
+                interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+            }
         }
 
         if let Some(interior_or_upvar_span) = interior_or_upvar_span {
+            let typeck_results = generator_data.and_then(|generator_data| match generator_data {
+                GeneratorData::Local(typeck_results) => Some(typeck_results),
+                GeneratorData::Foreign(_) => None,
+            });
             self.note_obligation_cause_for_async_await(
                 err,
                 interior_or_upvar_span,
                 interior_extra_info,
-                generator_body,
+                is_async,
                 outer_generator,
                 trait_ref,
                 target_ty,
@@ -1757,7 +1881,7 @@ fn note_obligation_cause_for_async_await(
         err: &mut Diagnostic,
         interior_or_upvar_span: GeneratorInteriorOrUpvar,
         interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
-        inner_generator_body: Option<&hir::Body<'tcx>>,
+        is_async: bool,
         outer_generator: Option<DefId>,
         trait_pred: ty::TraitPredicate<'tcx>,
         target_ty: Ty<'tcx>,
@@ -1767,10 +1891,6 @@ fn note_obligation_cause_for_async_await(
     ) {
         let source_map = self.tcx.sess.source_map();
 
-        let is_async = inner_generator_body
-            .and_then(|body| body.generator_kind())
-            .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
-            .unwrap_or(false);
         let (await_or_yield, an_await_or_yield) =
             if is_async { ("await", "an await") } else { ("yield", "a yield") };
         let future_or_generator = if is_async { "future" } else { "generator" };
index 1a10b07cc2706fa28038dc04960ebfab847c212c..38cc74a5e37348ccca400456140e43b9650d210b 100644 (file)
@@ -10,7 +10,6 @@
 use rustc_span::{Span, DUMMY_SP};
 
 use std::collections::BTreeSet;
-use std::iter;
 
 impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
@@ -323,6 +322,7 @@ pub(crate) fn complain_about_missing_associated_types(
         let mut suggestions = vec![];
         let mut types_count = 0;
         let mut where_constraints = vec![];
+        let mut already_has_generics_args_suggestion = false;
         for (span, assoc_items) in &associated_types {
             let mut names: FxHashMap<_, usize> = FxHashMap::default();
             for item in assoc_items {
@@ -343,16 +343,10 @@ pub(crate) fn complain_about_missing_associated_types(
                 }
             }
             if potential_assoc_types.len() == assoc_items.len() {
-                // Only suggest when the amount of missing associated types equals the number of
-                // extra type arguments present, as that gives us a relatively high confidence
-                // that the user forgot to give the associated type's name. The canonical
-                // example would be trying to use `Iterator<isize>` instead of
-                // `Iterator<Item = isize>`.
-                for (potential, item) in iter::zip(&potential_assoc_types, assoc_items) {
-                    if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) {
-                        suggestions.push((*potential, format!("{} = {}", item.name, snippet)));
-                    }
-                }
+                // When the amount of missing associated types equals the number of
+                // extra type arguments present.  A suggesting to replace the generic args with
+                // associated types is already emitted.
+                already_has_generics_args_suggestion = true;
             } else if let (Ok(snippet), false) =
                 (tcx.sess.source_map().span_to_snippet(*span), dupes)
             {
@@ -382,7 +376,7 @@ pub(crate) fn complain_about_missing_associated_types(
             // the same associated type name.
             err.help(where_msg);
         }
-        if suggestions.len() != 1 {
+        if suggestions.len() != 1 || already_has_generics_args_suggestion {
             // We don't need this label if there's an inline suggestion, show otherwise.
             for (span, assoc_items) in &associated_types {
                 let mut names: FxHashMap<_, usize> = FxHashMap::default();
index 80f6190732ac2a273fba37ba057898525803ccfb..616aa11f00a6b638870cfa61e6f9bf4c7463ee9f 100644 (file)
@@ -968,9 +968,9 @@ enum SuggestionText {
                 SuggestionText::Remove(plural) => {
                     Some(format!("remove the extra argument{}", if plural { "s" } else { "" }))
                 }
-                SuggestionText::Swap => Some(format!("swap these arguments")),
-                SuggestionText::Reorder => Some(format!("reorder these arguments")),
-                SuggestionText::DidYouMean => Some(format!("did you mean")),
+                SuggestionText::Swap => Some("swap these arguments".to_string()),
+                SuggestionText::Reorder => Some("reorder these arguments".to_string()),
+                SuggestionText::DidYouMean => Some("did you mean".to_string()),
             };
             if let Some(suggestion_text) = suggestion_text {
                 let source_map = self.sess().source_map();
index f3dcf5fff74cc39bd4562826d12b1263616f6d73..cf0c5703cd0ee7c724ff760b13ef9987ac79bab1 100644 (file)
@@ -2042,63 +2042,60 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: T
             self.tcx.sess,
             span,
             E0529,
-            "expected an array or slice, found `{}`",
-            expected_ty
+            "expected an array or slice, found `{expected_ty}`"
         );
-        if let ty::Ref(_, ty, _) = expected_ty.kind() {
-            if let ty::Array(..) | ty::Slice(..) = ty.kind() {
-                err.help("the semantics of slice patterns changed recently; see issue #62254");
-            }
+        if let ty::Ref(_, ty, _) = expected_ty.kind()
+            && let ty::Array(..) | ty::Slice(..) = ty.kind()
+        {
+            err.help("the semantics of slice patterns changed recently; see issue #62254");
         } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
             .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
+            && let (Some(span), true) = (ti.span, ti.origin_expr)
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
         {
-            if let (Some(span), true) = (ti.span, ti.origin_expr) {
-                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    let applicability = Autoderef::new(
-                        &self.infcx,
-                        self.param_env,
-                        self.body_id,
-                        span,
-                        self.resolve_vars_if_possible(ti.expected),
+            let ty = self.resolve_vars_if_possible(ti.expected);
+            let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(&mut err, snippet.clone(), ty);
+            match is_slice_or_array_or_vector.1.kind() {
+                ty::Adt(adt_def, _)
+                    if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
+                        || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
+                {
+                    // Slicing won't work here, but `.as_deref()` might (issue #91328).
+                    err.span_suggestion(
                         span,
-                    )
-                    .find_map(|(ty, _)| {
-                        match ty.kind() {
-                            ty::Adt(adt_def, _)
-                                if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
-                                    || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
-                            {
-                                // Slicing won't work here, but `.as_deref()` might (issue #91328).
-                                err.span_suggestion(
-                                    span,
-                                    "consider using `as_deref` here",
-                                    format!("{}.as_deref()", snippet),
-                                    Applicability::MaybeIncorrect,
-                                );
-                                Some(None)
-                            }
-
-                            ty::Slice(..) | ty::Array(..) => {
-                                Some(Some(Applicability::MachineApplicable))
-                            }
-
-                            _ => None,
-                        }
-                    })
-                    .unwrap_or(Some(Applicability::MaybeIncorrect));
-
-                    if let Some(applicability) = applicability {
-                        err.span_suggestion(
-                            span,
-                            "consider slicing here",
-                            format!("{}[..]", snippet),
-                            applicability,
-                        );
-                    }
+                        "consider using `as_deref` here",
+                        format!("{snippet}.as_deref()"),
+                        Applicability::MaybeIncorrect,
+                    );
                 }
+                _ => ()
+            }
+            if is_slice_or_array_or_vector.0 {
+                err.span_suggestion(
+                    span,
+                    "consider slicing here",
+                    format!("{snippet}[..]"),
+                    Applicability::MachineApplicable,
+                );
             }
         }
-        err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty));
+        err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`"));
         err.emit();
     }
+
+    fn is_slice_or_array_or_vector(
+        &self,
+        err: &mut Diagnostic,
+        snippet: String,
+        ty: Ty<'tcx>,
+    ) -> (bool, Ty<'tcx>) {
+        match ty.kind() {
+            ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
+                (true, ty)
+            }
+            ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(err, snippet, *ty),
+            ty::Slice(..) | ty::Array(..) => (true, ty),
+            _ => (false, ty),
+        }
+    }
 }
index 1088be5f566571d2ff7039c47a40b04012519dee..fc08171d2f4c290c00f831bca2b3de293c5c8e80 100644 (file)
@@ -134,7 +134,7 @@ pub struct TypeofReservedKeywordUsed<'tcx> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[suggestion_verbose(message = "suggestion", code = "{ty}")]
+    #[suggestion_verbose(code = "{ty}")]
     pub opt_sugg: Option<(Span, Applicability)>,
 }
 
index 1b1a2037d9eaa9dd5c819c67f8a76dea55d3b9af..5cd7a7d578e4bbcdaca2d1a1bf533c7b7f8bc0f4 100644 (file)
@@ -6,9 +6,10 @@
 use rustc_hir as hir;
 use rustc_middle::hir::map::fn_sig;
 use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
-use rustc_middle::ty::{self as ty, TyCtxt};
+use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
 use rustc_session::Session;
 use rustc_span::def_id::DefId;
+use std::iter;
 
 use GenericArgsInfo::*;
 
@@ -334,6 +335,22 @@ fn get_type_or_const_args_suggestions_from_param_names(
             .join(", ")
     }
 
+    fn get_unbound_associated_types(&self) -> Vec<String> {
+        if self.tcx.is_trait(self.def_id) {
+            let items: &AssocItems<'_> = self.tcx.associated_items(self.def_id);
+            items
+                .in_definition_order()
+                .filter(|item| item.kind == AssocKind::Type)
+                .filter(|item| {
+                    !self.gen_args.bindings.iter().any(|binding| binding.ident.name == item.name)
+                })
+                .map(|item| item.name.to_ident_string())
+                .collect()
+        } else {
+            Vec::default()
+        }
+    }
+
     fn create_error_message(&self) -> String {
         let def_path = self.tcx.def_path_str(self.def_id);
         let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
@@ -618,6 +635,7 @@ fn suggest_adding_type_and_const_args(&self, err: &mut Diagnostic) {
     fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
         let num_provided_lt_args = self.num_provided_lifetime_args();
         let num_provided_type_const_args = self.num_provided_type_or_const_args();
+        let unbound_types = self.get_unbound_associated_types();
         let num_provided_args = num_provided_lt_args + num_provided_type_const_args;
         assert!(num_provided_args > 0);
 
@@ -629,6 +647,8 @@ fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
         let redundant_type_or_const_args = num_redundant_type_or_const_args > 0;
 
         let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
+        let provided_args_matches_unbound_traits =
+            unbound_types.len() == num_redundant_type_or_const_args;
 
         let remove_lifetime_args = |err: &mut Diagnostic| {
             let mut lt_arg_spans = Vec::new();
@@ -713,7 +733,28 @@ fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
             );
         };
 
-        if remove_entire_generics {
+        // If there is a single unbound associated type and a single excess generic param
+        // suggest replacing the generic param with the associated type bound
+        if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
+            let mut suggestions = vec![];
+            let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
+            for (potential, name) in iter::zip(unused_generics, &unbound_types) {
+                if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(potential.span()) {
+                    suggestions.push((potential.span(), format!("{} = {}", name, snippet)));
+                }
+            }
+
+            if !suggestions.is_empty() {
+                err.multipart_suggestion(
+                    &format!(
+                        "replace the generic bound{s} with the associated type{s}",
+                        s = pluralize!(unbound_types.len())
+                    ),
+                    suggestions,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        } else if remove_entire_generics {
             let span = self
                 .path_segment
                 .args
index 6e53d9b442f1609ec929f1c021984391d038e879..dd886879b145d897f50d9ddae5307caacc3293ac 100644 (file)
@@ -473,13 +473,23 @@ changelog-seen = 2
 # FIXME(#61117): Some tests fail when this option is enabled.
 #debuginfo-level-tests = 0
 
-# Whether to run `dsymutil` on Apple platforms to gather debug info into .dSYM
-# bundles. `dsymutil` adds time to builds for no clear benefit, and also makes
-# it more difficult for debuggers to find debug info. The compiler currently
-# defaults to running `dsymutil` to preserve its historical default, but when
-# compiling the compiler itself, we skip it by default since we know it's safe
-# to do so in that case.
-#run-dsymutil = false
+# Should rustc be build with split debuginfo? Default is platform dependent.
+# Valid values are the same as those accepted by `-C split-debuginfo`
+# (`off`/`unpacked`/`packed`).
+#
+# On Linux, split debuginfo is disabled by default.
+#
+# On Apple platforms, unpacked split debuginfo is used by default. Unpacked
+# debuginfo does not run `dsymutil`, which packages debuginfo from disparate
+# object files into a single `.dSYM` file. `dsymutil` adds time to builds for
+# no clear benefit, and also makes it more difficult for debuggers to find
+# debug info. The compiler currently defaults to running `dsymutil` to preserve
+# its historical default, but when compiling the compiler itself, we skip it by
+# default since we know it's safe to do so in that case.
+#
+# On Windows platforms, packed debuginfo is the only supported option,
+# producing a `.pdb` file.
+#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked }
 
 # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
 #backtrace = true
index d3e9e65c3fe57b493001b6c77c9afc99287ff126..22c19243e7f53fca729e9e75503e51b59802355f 100644 (file)
@@ -34,7 +34,7 @@
 /// be mindful of side effects.
 ///
 /// [`Vec`]: crate::vec::Vec
-#[cfg(not(test))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "vec_macro"]
@@ -55,7 +55,7 @@ macro_rules! vec {
 // required for this macro definition, is not available. Instead use the
 // `slice::into_vec`  function which is only available with cfg(test)
 // NB see the slice::hack module in slice.rs for more information
-#[cfg(test)]
+#[cfg(all(not(no_global_oom_handling), test))]
 macro_rules! vec {
     () => (
         $crate::vec::Vec::new()
index 8e02ca8431744b4effcffb88f1e85ef2e6b2351a..bddbe2b9b0df104da8c8c9b500835c2fe86969ad 100644 (file)
@@ -1,7 +1,7 @@
 //! Compiler intrinsics.
 //!
-//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`.
-//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs`
+//! The corresponding definitions are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs>.
+//! The corresponding const implementations are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs>.
 //!
 //! # Const intrinsics
 //!
@@ -10,8 +10,8 @@
 //!
 //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
 //! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
-//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a
-//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
+//! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs> and add a
+//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
 //!
 //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
 //! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
index 68f39dc434780fe1471d84cf5bc41d27a76970c0..7ef2e95542bba6b3a0ec1e7fb92491cc88c240dc 100644 (file)
@@ -295,7 +295,7 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
@@ -358,7 +358,7 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
@@ -1188,7 +1188,7 @@ pub const fn as_ptr(self) -> *const T {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
index 4c9b0f7cc0c0513934871184251a4a728f5243d4..56f9c84f5af6f3341db11472f75528917fc9b76e 100644 (file)
@@ -302,7 +302,7 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
@@ -368,7 +368,7 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
@@ -550,7 +550,7 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get accessed (read or written) through any other pointer.
     ///
     /// This applies even if the result of this method is unused!
@@ -615,7 +615,7 @@ pub const fn wrapping_offset(self, count: isize) -> *mut T
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get accessed (read or written) through any other pointer.
     ///
     /// This applies even if the result of this method is unused!
@@ -1461,7 +1461,7 @@ pub const fn as_mut_ptr(self) -> *mut T {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
@@ -1513,7 +1513,7 @@ pub const fn as_mut_ptr(self) -> *mut T {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get accessed (read or written) through any other pointer.
     ///
     /// This applies even if the result of this method is unused!
index 6f402924e75dfadec1cb0bb3acdf2ff0e8c40e6c..5ebe61509063f3a7807bacdc5ace278d7666366b 100644 (file)
@@ -114,7 +114,7 @@ pub const fn dangling() -> Self {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
@@ -148,7 +148,7 @@ pub const fn dangling() -> Self {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get accessed (read or written) through any other pointer.
     ///
     /// This applies even if the result of this method is unused!
@@ -350,7 +350,7 @@ pub const fn as_ptr(self) -> *mut T {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
@@ -400,7 +400,7 @@ pub const fn as_ptr(self) -> *mut T {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get accessed (read or written) through any other pointer.
     ///
     /// This applies even if the result of this method is unused!
@@ -580,7 +580,7 @@ pub const fn as_mut_ptr(self) -> *mut T {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get mutated (except inside `UnsafeCell`).
     ///
     /// This applies even if the result of this method is unused!
@@ -626,7 +626,7 @@ pub const fn as_mut_ptr(self) -> *mut T {
     ///
     /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
     ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, for the duration of this lifetime, the memory the pointer points to must
+    ///   In particular, while this reference exists, the memory the pointer points to must
     ///   not get accessed (read or written) through any other pointer.
     ///
     /// This applies even if the result of this method is unused!
index 22662f7d18d07da1bb1d533a1e0d73711fa43c1b..98dd1521d0e85bea969b63d583f976bd74a023ee 100644 (file)
@@ -358,6 +358,20 @@ impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> {
     pub(super) fn new(slice: &'a [T], pred: P) -> Self {
         Self { v: slice, pred, finished: false }
     }
+    /// Returns a slice which contains items not yet handled by split.
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(split_as_slice)]
+    /// let slice = [1,2,3,4,5];
+    /// let mut split = slice.split(|v| v % 2 == 0);
+    /// assert!(split.next().is_some());
+    /// assert_eq!(split.as_slice(), &[3,4,5]);
+    /// ```
+    #[unstable(feature = "split_as_slice", issue = "96137")]
+    pub fn as_slice(&self) -> &'a [T] {
+        if self.finished { &[] } else { &self.v }
+    }
 }
 
 #[stable(feature = "core_impl_debug", since = "1.9.0")]
index 5c0e114e93c158098ea579352ab50fc9c208fa82..877d0841830551b0b104f0f3d5967e553007278f 100644 (file)
@@ -15,28 +15,6 @@ fn hash<H: Hasher>(&self, state: &mut H) {
     }
 }
 
-macro_rules! u8to64_le {
-    ($buf:expr, $i:expr) => {
-        $buf[0 + $i] as u64
-            | ($buf[1 + $i] as u64) << 8
-            | ($buf[2 + $i] as u64) << 16
-            | ($buf[3 + $i] as u64) << 24
-            | ($buf[4 + $i] as u64) << 32
-            | ($buf[5 + $i] as u64) << 40
-            | ($buf[6 + $i] as u64) << 48
-            | ($buf[7 + $i] as u64) << 56
-    };
-    ($buf:expr, $i:expr, $len:expr) => {{
-        let mut t = 0;
-        let mut out = 0;
-        while t < $len {
-            out |= ($buf[t + $i] as u64) << t * 8;
-            t += 1;
-        }
-        out
-    }};
-}
-
 fn hash_with<H: Hasher, T: Hash>(mut st: H, x: &T) -> u64 {
     x.hash(&mut st);
     st.finish()
@@ -123,7 +101,7 @@ fn test_siphash_1_3() {
     let mut state_inc = SipHasher13::new_with_keys(k0, k1);
 
     while t < 64 {
-        let vec = u8to64_le!(vecs[t], 0);
+        let vec = u64::from_le_bytes(vecs[t]);
         let out = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf));
         assert_eq!(vec, out);
 
@@ -217,7 +195,7 @@ fn test_siphash_2_4() {
     let mut state_inc = SipHasher::new_with_keys(k0, k1);
 
     while t < 64 {
-        let vec = u8to64_le!(vecs[t], 0);
+        let vec = u64::from_le_bytes(vecs[t]);
         let out = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf));
         assert_eq!(vec, out);
 
index 447a6fcf7567e5c4242676c32fe0a4d6a3f7bae8..485fa305c00e19834cc3f4b590f08fdc15615607 100644 (file)
@@ -46,6 +46,7 @@
 #![feature(sort_internals)]
 #![feature(slice_take)]
 #![feature(slice_from_ptr_range)]
+#![feature(split_as_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_array_assume_init)]
 #![feature(maybe_uninit_write_slice)]
index ada479147db95806c3e638a9ecc36687d91bba9c..872786ed1bd8083427ef1b4f2f3719e5a51947ca 100644 (file)
@@ -2339,6 +2339,18 @@ fn slice_rsplit_array_mut() {
     }
 }
 
+#[test]
+fn split_as_slice() {
+    let arr = [1, 2, 3, 4, 5, 6];
+    let mut split = arr.split(|v| v % 2 == 0);
+    assert_eq!(split.as_slice(), &[1, 2, 3, 4, 5, 6]);
+    assert!(split.next().is_some());
+    assert_eq!(split.as_slice(), &[3, 4, 5, 6]);
+    assert!(split.next().is_some());
+    assert!(split.next().is_some());
+    assert_eq!(split.as_slice(), &[]);
+}
+
 #[should_panic]
 #[test]
 fn slice_split_array_ref_out_of_bounds() {
index db5e2e4e245ea59f84c5828116a313d543f29c4c..e54a50aa15c616bcf16b03e186ec4abf4985e51d 100644 (file)
@@ -5,3 +5,7 @@ edition = "2021"
 
 [dependencies]
 std = { path = "../std" }
+# Workaround: when documenting this crate rustdoc will try to load crate named
+# `core` when resolving doc links. Without this line a different `core` will be
+# loaded from sysroot causing duplicate lang items and other similar errors.
+core = { path = "../core" }
index 4e16a55edece26a1b71d9acf7578d712d8efa0ca..fb292ed29a18a5b90d508aaf81df12247fdb6863 100644 (file)
@@ -59,12 +59,12 @@ fn read_atomically<T, F>(&mut self, inner: F) -> Option<T>
 
     /// Run a parser, but fail if the entire input wasn't consumed.
     /// Doesn't run atomically.
-    fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
+    fn parse_with<T, F>(&mut self, inner: F, kind: AddrKind) -> Result<T, AddrParseError>
     where
         F: FnOnce(&mut Parser<'_>) -> Option<T>,
     {
         let result = inner(self);
-        if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
+        if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(kind))
     }
 
     /// Peek the next character from the input
@@ -278,7 +278,7 @@ fn read_socket_addr(&mut self) -> Option<SocketAddr> {
 impl FromStr for IpAddr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_ip_addr())
+        Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
     }
 }
 
@@ -288,9 +288,9 @@ impl FromStr for Ipv4Addr {
     fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
         // don't try to parse if too long
         if s.len() > 15 {
-            Err(AddrParseError(()))
+            Err(AddrParseError(AddrKind::Ipv4))
         } else {
-            Parser::new(s).parse_with(|p| p.read_ipv4_addr())
+            Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
         }
     }
 }
@@ -299,7 +299,7 @@ fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
 impl FromStr for Ipv6Addr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_ipv6_addr())
+        Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
     }
 }
 
@@ -307,7 +307,7 @@ fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
 impl FromStr for SocketAddrV4 {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr_v4())
+        Parser::new(s).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
     }
 }
 
@@ -315,7 +315,7 @@ fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
 impl FromStr for SocketAddrV6 {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr_v6())
+        Parser::new(s).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
     }
 }
 
@@ -323,10 +323,20 @@ fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
 impl FromStr for SocketAddr {
     type Err = AddrParseError;
     fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
-        Parser::new(s).parse_with(|p| p.read_socket_addr())
+        Parser::new(s).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
     }
 }
 
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum AddrKind {
+    Ip,
+    Ipv4,
+    Ipv6,
+    Socket,
+    SocketV4,
+    SocketV6,
+}
+
 /// An error which can be returned when parsing an IP address or a socket address.
 ///
 /// This error is used as the error type for the [`FromStr`] implementation for
@@ -353,7 +363,7 @@ fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub struct AddrParseError(());
+pub struct AddrParseError(AddrKind);
 
 #[stable(feature = "addr_parse_error_error", since = "1.4.0")]
 impl fmt::Display for AddrParseError {
@@ -367,6 +377,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl Error for AddrParseError {
     #[allow(deprecated)]
     fn description(&self) -> &str {
-        "invalid IP address syntax"
+        match self.0 {
+            AddrKind::Ip => "invalid IP address syntax",
+            AddrKind::Ipv4 => "invalid IPv4 address syntax",
+            AddrKind::Ipv6 => "invalid IPv6 address syntax",
+            AddrKind::Socket => "invalid socket address syntax",
+            AddrKind::SocketV4 => "invalid IPv4 socket address syntax",
+            AddrKind::SocketV6 => "invalid IPv6 socket address syntax",
+        }
     }
 }
index 415cbba101c67061fd197808fc1463b344f829f0..97b4c49896f63f1aaa783071d44004019a4c2c44 100644 (file)
@@ -1,6 +1,5 @@
 use crate::cell::UnsafeCell;
 use crate::collections::VecDeque;
-use crate::ffi::c_void;
 use crate::hint;
 use crate::ops::{Deref, DerefMut, Drop};
 use crate::ptr;
@@ -220,38 +219,3 @@ pub unsafe fn try_lock(&self) -> bool {
     #[inline]
     pub unsafe fn destroy(&self) {}
 }
-
-pub struct ReentrantMutex {
-    inner: *const c_void,
-}
-
-impl ReentrantMutex {
-    pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex { inner: ptr::null() }
-    }
-
-    #[inline]
-    pub unsafe fn init(&self) {
-        let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
-    }
-
-    #[inline]
-    pub unsafe fn lock(&self) {
-        let _ = abi::recmutex_lock(self.inner);
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        true
-    }
-
-    #[inline]
-    pub unsafe fn unlock(&self) {
-        let _ = abi::recmutex_unlock(self.inner);
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        let _ = abi::recmutex_destroy(self.inner);
-    }
-}
index e01f595ac54abeefcb835b8fa54891209e95251c..5ee231882bb589e8faf273d9ddab311e8b239045 100644 (file)
@@ -5,7 +5,6 @@
     error::{expect_success, expect_success_aborting, fail, ItronError},
     spin::SpinIdOnceCell,
 };
-use crate::cell::UnsafeCell;
 
 pub struct Mutex {
     /// The ID of the underlying mutex object
@@ -89,95 +88,3 @@ fn drop(&mut self) {
         unsafe { self.0.unlock() };
     }
 }
-
-// All empty stubs because this platform does not yet support threads, so lock
-// acquisition always succeeds.
-pub struct ReentrantMutex {
-    /// The ID of the underlying mutex object
-    mtx: abi::ID,
-    /// The lock count.
-    count: UnsafeCell<usize>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
-    pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex { mtx: 0, count: UnsafeCell::new(0) }
-    }
-
-    pub unsafe fn init(&mut self) {
-        self.mtx = expect_success(
-            unsafe {
-                abi::acre_mtx(&abi::T_CMTX {
-                    // Priority inheritance mutex
-                    mtxatr: abi::TA_INHERIT,
-                    // Unused
-                    ceilpri: 0,
-                })
-            },
-            &"acre_mtx",
-        );
-    }
-
-    pub unsafe fn lock(&self) {
-        match unsafe { abi::loc_mtx(self.mtx) } {
-            abi::E_OBJ => {
-                // Recursive lock
-                unsafe {
-                    let count = &mut *self.count.get();
-                    if let Some(new_count) = count.checked_add(1) {
-                        *count = new_count;
-                    } else {
-                        // counter overflow
-                        rtabort!("lock count overflow");
-                    }
-                }
-            }
-            er => {
-                expect_success(er, &"loc_mtx");
-            }
-        }
-    }
-
-    pub unsafe fn unlock(&self) {
-        unsafe {
-            let count = &mut *self.count.get();
-            if *count > 0 {
-                *count -= 1;
-                return;
-            }
-        }
-
-        expect_success_aborting(unsafe { abi::unl_mtx(self.mtx) }, &"unl_mtx");
-    }
-
-    pub unsafe fn try_lock(&self) -> bool {
-        let er = unsafe { abi::ploc_mtx(self.mtx) };
-        if er == abi::E_OBJ {
-            // Recursive lock
-            unsafe {
-                let count = &mut *self.count.get();
-                if let Some(new_count) = count.checked_add(1) {
-                    *count = new_count;
-                } else {
-                    // counter overflow
-                    rtabort!("lock count overflow");
-                }
-            }
-            true
-        } else if er == abi::E_TMOUT {
-            // Locked by another thread
-            false
-        } else {
-            expect_success(er, &"ploc_mtx");
-            // Top-level lock by the current thread
-            true
-        }
-    }
-
-    pub unsafe fn destroy(&self) {
-        expect_success_aborting(unsafe { abi::del_mtx(self.mtx) }, &"del_mtx");
-    }
-}
index 0b2d1f4487f618dac25f4453f2e29d8caabaf014..98a390c4c2bcabe06cae174626f442ecb4324ee3 100644 (file)
@@ -1,8 +1,4 @@
-use fortanix_sgx_abi::Tcs;
-
-use super::abi::thread;
-
-use super::waitqueue::{try_lock_or_false, NotifiedTcs, SpinMutex, WaitQueue, WaitVariable};
+use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
 
 pub struct Mutex {
     inner: SpinMutex<WaitVariable<bool>>,
@@ -60,84 +56,3 @@ pub unsafe fn try_lock(&self) -> bool {
     #[inline]
     pub unsafe fn destroy(&self) {}
 }
-
-struct ReentrantLock {
-    owner: Option<Tcs>,
-    count: usize,
-}
-
-pub struct ReentrantMutex {
-    inner: SpinMutex<WaitVariable<ReentrantLock>>,
-}
-
-impl ReentrantMutex {
-    pub const fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex {
-            inner: SpinMutex::new(WaitVariable::new(ReentrantLock { owner: None, count: 0 })),
-        }
-    }
-
-    #[inline]
-    pub unsafe fn init(&self) {}
-
-    #[inline]
-    pub unsafe fn lock(&self) {
-        let mut guard = self.inner.lock();
-        match guard.lock_var().owner {
-            Some(tcs) if tcs != thread::current() => {
-                // Another thread has the lock, wait
-                WaitQueue::wait(guard, || {});
-                // Another thread has passed the lock to us
-            }
-            _ => {
-                // We are just now obtaining the lock
-                guard.lock_var_mut().owner = Some(thread::current());
-                guard.lock_var_mut().count += 1;
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn unlock(&self) {
-        let mut guard = self.inner.lock();
-        if guard.lock_var().count > 1 {
-            guard.lock_var_mut().count -= 1;
-        } else {
-            match WaitQueue::notify_one(guard) {
-                Err(mut guard) => {
-                    // No other waiters, unlock
-                    guard.lock_var_mut().count = 0;
-                    guard.lock_var_mut().owner = None;
-                }
-                Ok(mut guard) => {
-                    // There was a thread waiting, just pass the lock
-                    if let NotifiedTcs::Single(tcs) = guard.notified_tcs() {
-                        guard.lock_var_mut().owner = Some(tcs)
-                    } else {
-                        unreachable!() // called notify_one
-                    }
-                }
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        let mut guard = try_lock_or_false!(self.inner);
-        match guard.lock_var().owner {
-            Some(tcs) if tcs != thread::current() => {
-                // Another thread has the lock
-                false
-            }
-            _ => {
-                // We are just now obtaining the lock
-                guard.lock_var_mut().owner = Some(thread::current());
-                guard.lock_var_mut().count += 1;
-                true
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
-}
index 7181451de575fcb8ff7df27ba5a66b18a08904be..a60b19976ba4e0d4376ba9396db9229e4f45fdc2 100644 (file)
@@ -1647,8 +1647,9 @@ fn is_dir(ent: &DirEntry) -> Option<bool> {
     fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
         // try opening as directory
         let fd = match openat_nofollow_dironly(parent_fd, &path) {
-            Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
+            Err(err) if matches!(err.raw_os_error(), Some(libc::ENOTDIR | libc::ELOOP)) => {
                 // not a directory - don't traverse further
+                // (for symlinks, older Linux kernels may return ELOOP instead of ENOTDIR)
                 return match parent_fd {
                     // unlink...
                     Some(parent_fd) => {
index 62760373a6affecba019d63754011973ffaa2db1..c12ee169e797aa78c904d3e5d125e16ceed4145d 100644 (file)
@@ -52,25 +52,6 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
     }
 }
 
-#[cfg(target_os = "emscripten")]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) {
-    extern "C" {
-        fn emscripten_futex_wait(
-            addr: *const AtomicU32,
-            val: libc::c_uint,
-            max_wait_ms: libc::c_double,
-        ) -> libc::c_int;
-    }
-
-    unsafe {
-        emscripten_futex_wait(
-            futex,
-            expected,
-            timeout.map_or(crate::f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
-        );
-    }
-}
-
 /// Wake up one thread that's blocked on futex_wait on this futex.
 ///
 /// Returns true if this actually woke up such a thread,
@@ -101,10 +82,32 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 }
 
 #[cfg(target_os = "emscripten")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
-    extern "C" {
-        fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+extern "C" {
+    fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+    fn emscripten_futex_wait(
+        addr: *const AtomicU32,
+        val: libc::c_uint,
+        max_wait_ms: libc::c_double,
+    ) -> libc::c_int;
+}
+
+#[cfg(target_os = "emscripten")]
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+    unsafe {
+        emscripten_futex_wait(
+            futex,
+            expected,
+            timeout.map_or(f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
+        ) != -libc::ETIMEDOUT
     }
+}
 
+#[cfg(target_os = "emscripten")]
+pub fn futex_wake(futex: &AtomicU32) -> bool {
     unsafe { emscripten_futex_wake(futex, 1) > 0 }
 }
+
+#[cfg(target_os = "emscripten")]
+pub fn futex_wake_all(futex: &AtomicU32) {
+    unsafe { emscripten_futex_wake(futex, i32::MAX) };
+}
index b166e7c453cad17bbdee1ad7f4bae550d6a02e71..7a63af1ad7cf7dfa45bc95efbd20ae62545f78f0 100644 (file)
@@ -1,6 +1,5 @@
-use crate::cell::UnsafeCell;
 use crate::sync::atomic::{
-    AtomicU32, AtomicUsize,
+    AtomicU32,
     Ordering::{Acquire, Relaxed, Release},
 };
 use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
@@ -163,98 +162,3 @@ unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option<Duration>)
         r
     }
 }
-
-/// A reentrant mutex. Used by stdout().lock() and friends.
-///
-/// The 'owner' field tracks which thread has locked the mutex.
-///
-/// We use current_thread_unique_ptr() as the thread identifier,
-/// which is just the address of a thread local variable.
-///
-/// If `owner` is set to the identifier of the current thread,
-/// we assume the mutex is already locked and instead of locking it again,
-/// we increment `lock_count`.
-///
-/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
-/// it reaches zero.
-///
-/// `lock_count` is protected by the mutex and only accessed by the thread that has
-/// locked the mutex, so needs no synchronization.
-///
-/// `owner` can be checked by other threads that want to see if they already
-/// hold the lock, so needs to be atomic. If it compares equal, we're on the
-/// same thread that holds the mutex and memory access can use relaxed ordering
-/// since we're not dealing with multiple threads. If it compares unequal,
-/// synchronization is left to the mutex, making relaxed memory ordering for
-/// the `owner` field fine in all cases.
-pub struct ReentrantMutex {
-    mutex: Mutex,
-    owner: AtomicUsize,
-    lock_count: UnsafeCell<u32>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
-    #[inline]
-    pub const unsafe fn uninitialized() -> Self {
-        Self { mutex: Mutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0) }
-    }
-
-    #[inline]
-    pub unsafe fn init(&self) {}
-
-    #[inline]
-    pub unsafe fn destroy(&self) {}
-
-    pub unsafe fn try_lock(&self) -> bool {
-        let this_thread = current_thread_unique_ptr();
-        if self.owner.load(Relaxed) == this_thread {
-            self.increment_lock_count();
-            true
-        } else if self.mutex.try_lock() {
-            self.owner.store(this_thread, Relaxed);
-            debug_assert_eq!(*self.lock_count.get(), 0);
-            *self.lock_count.get() = 1;
-            true
-        } else {
-            false
-        }
-    }
-
-    pub unsafe fn lock(&self) {
-        let this_thread = current_thread_unique_ptr();
-        if self.owner.load(Relaxed) == this_thread {
-            self.increment_lock_count();
-        } else {
-            self.mutex.lock();
-            self.owner.store(this_thread, Relaxed);
-            debug_assert_eq!(*self.lock_count.get(), 0);
-            *self.lock_count.get() = 1;
-        }
-    }
-
-    unsafe fn increment_lock_count(&self) {
-        *self.lock_count.get() = (*self.lock_count.get())
-            .checked_add(1)
-            .expect("lock count overflow in reentrant mutex");
-    }
-
-    pub unsafe fn unlock(&self) {
-        *self.lock_count.get() -= 1;
-        if *self.lock_count.get() == 0 {
-            self.owner.store(0, Relaxed);
-            self.mutex.unlock();
-        }
-    }
-}
-
-/// Get an address that is unique per running thread.
-///
-/// This can be used as a non-null usize-sized ID.
-pub fn current_thread_unique_ptr() -> usize {
-    // Use a non-drop type to make sure it's still available during thread destruction.
-    thread_local! { static X: u8 = const { 0 } }
-    X.with(|x| <*const _>::addr(x))
-}
index e0404f40c69bfbdcd0b9fddce862b4d5af2f2ade..3e39c8b9b23e7a00ab22c9c317d49d97e73d45a2 100644 (file)
@@ -2,18 +2,17 @@
     if #[cfg(any(
         target_os = "linux",
         target_os = "android",
+        all(target_os = "emscripten", target_feature = "atomics"),
     ))] {
         mod futex;
         mod futex_rwlock;
-        pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar, ReentrantMutex};
+        pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
         pub use futex_rwlock::{RwLock, MovableRwLock};
     } else {
         mod pthread_mutex;
-        mod pthread_remutex;
         mod pthread_rwlock;
         mod pthread_condvar;
         pub use pthread_mutex::{Mutex, MovableMutex};
-        pub use pthread_remutex::ReentrantMutex;
         pub use pthread_rwlock::{RwLock, MovableRwLock};
         pub use pthread_condvar::{Condvar, MovableCondvar};
     }
diff --git a/library/std/src/sys/unix/locks/pthread_remutex.rs b/library/std/src/sys/unix/locks/pthread_remutex.rs
deleted file mode 100644 (file)
index b006181..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-use super::pthread_mutex::PthreadMutexAttr;
-use crate::cell::UnsafeCell;
-use crate::mem::MaybeUninit;
-use crate::sys::cvt_nz;
-
-pub struct ReentrantMutex {
-    inner: UnsafeCell<libc::pthread_mutex_t>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
-    pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
-    }
-
-    pub unsafe fn init(&self) {
-        let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
-        cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
-        let attr = PthreadMutexAttr(&mut attr);
-        cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE))
-            .unwrap();
-        cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap();
-    }
-
-    pub unsafe fn lock(&self) {
-        let result = libc::pthread_mutex_lock(self.inner.get());
-        debug_assert_eq!(result, 0);
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        libc::pthread_mutex_trylock(self.inner.get()) == 0
-    }
-
-    pub unsafe fn unlock(&self) {
-        let result = libc::pthread_mutex_unlock(self.inner.get());
-        debug_assert_eq!(result, 0);
-    }
-
-    pub unsafe fn destroy(&self) {
-        let result = libc::pthread_mutex_destroy(self.inner.get());
-        debug_assert_eq!(result, 0);
-    }
-}
index 1be733ba106e866828c87a9f8cc1769a1530ba14..92bea9346d8f8ea888515778589c5d42c66d8ea8 100644 (file)
@@ -427,7 +427,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     crate::fs::read_to_string("sys:exe").map(PathBuf::from)
 }
 
-#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
+#[cfg(target_os = "l4re")]
 pub fn current_exe() -> io::Result<PathBuf> {
     use crate::io::ErrorKind;
     Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
@@ -451,6 +451,26 @@ pub fn current_exe() -> io::Result<PathBuf> {
     super::unsupported::unsupported()
 }
 
+#[cfg(target_os = "fuchsia")]
+pub fn current_exe() -> io::Result<PathBuf> {
+    use crate::io::ErrorKind;
+
+    #[cfg(test)]
+    use realstd::env;
+
+    #[cfg(not(test))]
+    use crate::env;
+
+    let exe_path = env::args().next().ok_or(io::const_io_error!(
+        ErrorKind::Uncategorized,
+        "an executable path was not found because no arguments were provided through argv"
+    ))?;
+    let path = PathBuf::from(exe_path);
+
+    // Prepend the current working directory to the path if it's not absolute.
+    if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
+}
+
 pub struct Env {
     iter: vec::IntoIter<(OsString, OsString)>,
 }
index 9f1a645372f42b06f09552aa26244e55d415d822..1956b3692a7ea8f2cc37dfb9c9ff6a99a781c6eb 100644 (file)
@@ -3,7 +3,7 @@
 use crate::ffi::OsStr;
 use crate::mem;
 use crate::ptr;
-use crate::sys::cvt;
+use crate::sys::{cvt, cvt_nz};
 
 macro_rules! t {
     ($e:expr) => {
@@ -39,7 +39,7 @@ fn test_process_mask() {
         let mut old_set = mem::MaybeUninit::<libc::sigset_t>::uninit();
         t!(cvt(sigemptyset(set.as_mut_ptr())));
         t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT)));
-        t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr())));
+        t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr())));
 
         cmd.stdin(Stdio::MakePipe);
         cmd.stdout(Stdio::MakePipe);
@@ -48,7 +48,7 @@ fn test_process_mask() {
         let stdin_write = pipes.stdin.take().unwrap();
         let stdout_read = pipes.stdout.take().unwrap();
 
-        t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
+        t!(cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut())));
 
         t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
         // We need to wait until SIGINT is definitely delivered. The
index 3d305cd7310fd4b8419d220d1adeadebb9fda914..d48faaa88fb4f56e91082d73172a97ceed6d8cc7 100644 (file)
@@ -328,6 +328,7 @@ unsafe fn do_exec(
         #[cfg(not(target_os = "emscripten"))]
         {
             use crate::mem::MaybeUninit;
+            use crate::sys::cvt_nz;
             // Reset signal handling so the child process starts in a
             // standardized state. libstd ignores SIGPIPE, and signal-handling
             // libraries often set a mask. Child processes inherit ignored
@@ -337,7 +338,7 @@ unsafe fn do_exec(
             // we're about to run.
             let mut set = MaybeUninit::<libc::sigset_t>::uninit();
             cvt(sigemptyset(set.as_mut_ptr()))?;
-            cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?;
+            cvt_nz(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?;
 
             #[cfg(target_os = "android")] // see issue #88585
             {
index da63c068384a2b56a4926360db10c4213646d616..e4ff21b25bd9ce47aea69b7fd0f2eb696c873306 100644 (file)
@@ -25,7 +25,8 @@
 use crate::ffi::CStr;
 use crate::marker::PhantomData;
 use crate::mem;
-use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::ptr;
+use crate::sync::atomic::{self, AtomicPtr, Ordering};
 
 // We can use true weak linkage on ELF targets.
 #[cfg(not(any(target_os = "macos", target_os = "ios")))]
@@ -83,13 +84,13 @@ pub(crate) fn get(&self) -> Option<F> {
 }
 pub(crate) struct DlsymWeak<F> {
     name: &'static str,
-    addr: AtomicUsize,
+    func: AtomicPtr<libc::c_void>,
     _marker: PhantomData<F>,
 }
 
 impl<F> DlsymWeak<F> {
     pub(crate) const fn new(name: &'static str) -> Self {
-        DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
+        DlsymWeak { name, func: AtomicPtr::new(ptr::invalid_mut(1)), _marker: PhantomData }
     }
 
     #[inline]
@@ -97,11 +98,11 @@ pub(crate) fn get(&self) -> Option<F> {
         unsafe {
             // Relaxed is fine here because we fence before reading through the
             // pointer (see the comment below).
-            match self.addr.load(Ordering::Relaxed) {
-                1 => self.initialize(),
-                0 => None,
-                addr => {
-                    let func = mem::transmute_copy::<usize, F>(&addr);
+            match self.func.load(Ordering::Relaxed) {
+                func if func.addr() == 1 => self.initialize(),
+                func if func.is_null() => None,
+                func => {
+                    let func = mem::transmute_copy::<*mut libc::c_void, F>(&func);
                     // The caller is presumably going to read through this value
                     // (by calling the function we've dlsymed). This means we'd
                     // need to have loaded it with at least C11's consume
@@ -129,25 +130,22 @@ pub(crate) fn get(&self) -> Option<F> {
     // Cold because it should only happen during first-time initialization.
     #[cold]
     unsafe fn initialize(&self) -> Option<F> {
-        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+        assert_eq!(mem::size_of::<F>(), mem::size_of::<*mut libc::c_void>());
 
         let val = fetch(self.name);
         // This synchronizes with the acquire fence in `get`.
-        self.addr.store(val, Ordering::Release);
+        self.func.store(val, Ordering::Release);
 
-        match val {
-            0 => None,
-            addr => Some(mem::transmute_copy::<usize, F>(&addr)),
-        }
+        if val.is_null() { None } else { Some(mem::transmute_copy::<*mut libc::c_void, F>(&val)) }
     }
 }
 
-unsafe fn fetch(name: &str) -> usize {
+unsafe fn fetch(name: &str) -> *mut libc::c_void {
     let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
         Ok(cstr) => cstr,
-        Err(..) => return 0,
+        Err(..) => return ptr::null_mut(),
     };
-    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
+    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr())
 }
 
 #[cfg(not(any(target_os = "linux", target_os = "android")))]
index 35bd59130346f2bb7672ea13397cb7c4fbed012b..d412ff152a047daa4a56475300d0eb164631f92a 100644 (file)
@@ -2,5 +2,5 @@
 mod mutex;
 mod rwlock;
 pub use condvar::{Condvar, MovableCondvar};
-pub use mutex::{MovableMutex, Mutex, ReentrantMutex};
+pub use mutex::{MovableMutex, Mutex};
 pub use rwlock::{MovableRwLock, RwLock};
index b3203c16c50022bb6f67e436899dd7a9879640ed..cad991aae5e961257ef56edccf0e06b36ba5fb8f 100644 (file)
@@ -36,26 +36,3 @@ pub unsafe fn try_lock(&self) -> bool {
     #[inline]
     pub unsafe fn destroy(&self) {}
 }
-
-// All empty stubs because this platform does not yet support threads, so lock
-// acquisition always succeeds.
-pub struct ReentrantMutex {}
-
-impl ReentrantMutex {
-    pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex {}
-    }
-
-    pub unsafe fn init(&self) {}
-
-    pub unsafe fn lock(&self) {}
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        true
-    }
-
-    pub unsafe fn unlock(&self) {}
-
-    pub unsafe fn destroy(&self) {}
-}
diff --git a/library/std/src/sys/wasm/atomics/condvar.rs b/library/std/src/sys/wasm/atomics/condvar.rs
deleted file mode 100644 (file)
index f06c07c..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-use crate::arch::wasm32;
-use crate::cmp;
-use crate::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sys::locks::Mutex;
-use crate::time::Duration;
-
-pub struct Condvar {
-    cnt: AtomicUsize,
-}
-
-pub type MovableCondvar = Condvar;
-
-// Condition variables are implemented with a simple counter internally that is
-// likely to cause spurious wakeups. Blocking on a condition variable will first
-// read the value of the internal counter, unlock the given mutex, and then
-// block if and only if the counter's value is still the same. Notifying a
-// condition variable will modify the counter (add one for now) and then wake up
-// a thread waiting on the address of the counter.
-//
-// A thread waiting on the condition variable will as a result avoid going to
-// sleep if it's notified after the lock is unlocked but before it fully goes to
-// sleep. A sleeping thread is guaranteed to be woken up at some point as it can
-// only be woken up with a call to `wake`.
-//
-// Note that it's possible for 2 or more threads to be woken up by a call to
-// `notify_one` with this implementation. That can happen where the modification
-// of `cnt` causes any threads in the middle of `wait` to avoid going to sleep,
-// and the subsequent `wake` may wake up a thread that's actually blocking. We
-// consider this a spurious wakeup, though, which all users of condition
-// variables must already be prepared to handle. As a result, this source of
-// spurious wakeups is currently though to be ok, although it may be problematic
-// later on if it causes too many spurious wakeups.
-
-impl Condvar {
-    pub const fn new() -> Condvar {
-        Condvar { cnt: AtomicUsize::new(0) }
-    }
-
-    #[inline]
-    pub unsafe fn init(&mut self) {
-        // nothing to do
-    }
-
-    pub unsafe fn notify_one(&self) {
-        self.cnt.fetch_add(1, SeqCst);
-        // SAFETY: ptr() is always valid
-        unsafe {
-            wasm32::memory_atomic_notify(self.ptr(), 1);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn notify_all(&self) {
-        self.cnt.fetch_add(1, SeqCst);
-        // SAFETY: ptr() is always valid
-        unsafe {
-            wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
-        }
-    }
-
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        // "atomically block and unlock" implemented by loading our current
-        // counter's value, unlocking the mutex, and blocking if the counter
-        // still has the same value.
-        //
-        // Notifications happen by incrementing the counter and then waking a
-        // thread. Incrementing the counter after we unlock the mutex will
-        // prevent us from sleeping and otherwise the call to `wake` will
-        // wake us up once we're asleep.
-        let ticket = self.cnt.load(SeqCst) as i32;
-        mutex.unlock();
-        let val = wasm32::memory_atomic_wait32(self.ptr(), ticket, -1);
-        // 0 == woken, 1 == not equal to `ticket`, 2 == timeout (shouldn't happen)
-        debug_assert!(val == 0 || val == 1);
-        mutex.lock();
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let ticket = self.cnt.load(SeqCst) as i32;
-        mutex.unlock();
-        let nanos = dur.as_nanos();
-        let nanos = cmp::min(i64::MAX as u128, nanos);
-
-        // If the return value is 2 then a timeout happened, so we return
-        // `false` as we weren't actually notified.
-        let ret = wasm32::memory_atomic_wait32(self.ptr(), ticket, nanos as i64) != 2;
-        mutex.lock();
-        return ret;
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        // nothing to do
-    }
-
-    #[inline]
-    fn ptr(&self) -> *mut i32 {
-        assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
-        self.cnt.as_mut_ptr() as *mut i32
-    }
-}
index bbe9bd6951af967e12d9be38040d0e07b9349292..11413ba3bf5642d484b1a3de09f3c0579b18e426 100644 (file)
@@ -3,19 +3,33 @@
 use crate::sync::atomic::AtomicU32;
 use crate::time::Duration;
 
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) {
+/// Wait for a futex_wake operation to wake us.
+///
+/// Returns directly if the futex doesn't hold the expected value.
+///
+/// Returns false on timeout, and true in all other cases.
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
     let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1);
     unsafe {
         wasm32::memory_atomic_wait32(
             futex as *const AtomicU32 as *mut i32,
             expected as i32,
             timeout,
-        );
+        ) < 2
     }
 }
 
-pub fn futex_wake(futex: &AtomicU32) {
+/// Wake up one thread that's blocked on futex_wait on this futex.
+///
+/// Returns true if this actually woke up such a thread,
+/// or false if no thread was waiting on this futex.
+pub fn futex_wake(futex: &AtomicU32) -> bool {
+    unsafe { wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 }
+}
+
+/// Wake up all threads that are waiting on futex_wait on this futex.
+pub fn futex_wake_all(futex: &AtomicU32) {
     unsafe {
-        wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1);
+        wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32);
     }
 }
diff --git a/library/std/src/sys/wasm/atomics/mutex.rs b/library/std/src/sys/wasm/atomics/mutex.rs
deleted file mode 100644 (file)
index 3a09f0b..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-use crate::arch::wasm32;
-use crate::cell::UnsafeCell;
-use crate::mem;
-use crate::sync::atomic::{AtomicU32, AtomicUsize, Ordering::SeqCst};
-use crate::sys::thread;
-
-pub struct Mutex {
-    locked: AtomicUsize,
-}
-
-pub type MovableMutex = Mutex;
-
-// Mutexes have a pretty simple implementation where they contain an `i32`
-// internally that is 0 when unlocked and 1 when the mutex is locked.
-// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
-// if it fails it then waits for a notification. Releasing a lock is then done
-// by swapping in 0 and then notifying any waiters, if present.
-
-impl Mutex {
-    pub const fn new() -> Mutex {
-        Mutex { locked: AtomicUsize::new(0) }
-    }
-
-    #[inline]
-    pub unsafe fn init(&mut self) {
-        // nothing to do
-    }
-
-    pub unsafe fn lock(&self) {
-        while !self.try_lock() {
-            // SAFETY: the caller must uphold the safety contract for `memory_atomic_wait32`.
-            let val = unsafe {
-                wasm32::memory_atomic_wait32(
-                    self.ptr(),
-                    1,  // we expect our mutex is locked
-                    -1, // wait infinitely
-                )
-            };
-            // we should have either woke up (0) or got a not-equal due to a
-            // race (1). We should never time out (2)
-            debug_assert!(val == 0 || val == 1);
-        }
-    }
-
-    pub unsafe fn unlock(&self) {
-        let prev = self.locked.swap(0, SeqCst);
-        debug_assert_eq!(prev, 1);
-        wasm32::memory_atomic_notify(self.ptr(), 1); // wake up one waiter, if any
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        // nothing to do
-    }
-
-    #[inline]
-    fn ptr(&self) -> *mut i32 {
-        assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
-        self.locked.as_mut_ptr() as *mut i32
-    }
-}
-
-pub struct ReentrantMutex {
-    owner: AtomicU32,
-    recursions: UnsafeCell<u32>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-// Reentrant mutexes are similarly implemented to mutexes above except that
-// instead of "1" meaning unlocked we use the id of a thread to represent
-// whether it has locked a mutex. That way we have an atomic counter which
-// always holds the id of the thread that currently holds the lock (or 0 if the
-// lock is unlocked).
-//
-// Once a thread acquires a lock recursively, which it detects by looking at
-// the value that's already there, it will update a local `recursions` counter
-// in a nonatomic fashion (as we hold the lock). The lock is then fully
-// released when this recursion counter reaches 0.
-
-impl ReentrantMutex {
-    pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) }
-    }
-
-    pub unsafe fn init(&self) {
-        // nothing to do...
-    }
-
-    pub unsafe fn lock(&self) {
-        let me = thread::my_id();
-        while let Err(owner) = self._try_lock(me) {
-            // SAFETY: the caller must guarantee that `self.ptr()` and `owner` are valid i32.
-            let val = unsafe { wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1) };
-            debug_assert!(val == 0 || val == 1);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        unsafe { self._try_lock(thread::my_id()).is_ok() }
-    }
-
-    #[inline]
-    unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
-        let id = id.checked_add(1).unwrap();
-        match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
-            // we transitioned from unlocked to locked
-            Ok(_) => {
-                debug_assert_eq!(*self.recursions.get(), 0);
-                Ok(())
-            }
-
-            // we currently own this lock, so let's update our count and return
-            // true.
-            Err(n) if n == id => {
-                *self.recursions.get() += 1;
-                Ok(())
-            }
-
-            // Someone else owns the lock, let our caller take care of it
-            Err(other) => Err(other),
-        }
-    }
-
-    pub unsafe fn unlock(&self) {
-        // If we didn't ever recursively lock the lock then we fully unlock the
-        // mutex and wake up a waiter, if any. Otherwise we decrement our
-        // recursive counter and let some one else take care of the zero.
-        match *self.recursions.get() {
-            0 => {
-                self.owner.swap(0, SeqCst);
-                // SAFETY: the caller must guarantee that `self.ptr()` is valid i32.
-                unsafe {
-                    wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1);
-                } // wake up one waiter, if any
-            }
-            ref mut n => *n -= 1,
-        }
-    }
-
-    pub unsafe fn destroy(&self) {
-        // nothing to do...
-    }
-
-    #[inline]
-    fn ptr(&self) -> *mut i32 {
-        self.owner.as_mut_ptr() as *mut i32
-    }
-}
diff --git a/library/std/src/sys/wasm/atomics/rwlock.rs b/library/std/src/sys/wasm/atomics/rwlock.rs
deleted file mode 100644 (file)
index 690bb15..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::sys::locks::{Condvar, Mutex};
-
-pub struct RwLock {
-    lock: Mutex,
-    cond: Condvar,
-    state: UnsafeCell<State>,
-}
-
-pub type MovableRwLock = RwLock;
-
-enum State {
-    Unlocked,
-    Reading(usize),
-    Writing,
-}
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-// This rwlock implementation is a relatively simple implementation which has a
-// condition variable for readers/writers as well as a mutex protecting the
-// internal state of the lock. A current downside of the implementation is that
-// unlocking the lock will notify *all* waiters rather than just readers or just
-// writers. This can cause lots of "thundering stampede" problems. While
-// hopefully correct this implementation is very likely to want to be changed in
-// the future.
-
-impl RwLock {
-    pub const fn new() -> RwLock {
-        RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
-    }
-
-    #[inline]
-    pub unsafe fn read(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_readers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_readers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn write(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_writers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_writers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        self.lock.lock();
-        let notify = (*self.state.get()).dec_readers();
-        self.lock.unlock();
-        if notify {
-            // FIXME: should only wake up one of these some of the time
-            self.cond.notify_all();
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        self.lock.lock();
-        (*self.state.get()).dec_writers();
-        self.lock.unlock();
-        // FIXME: should only wake up one of these some of the time
-        self.cond.notify_all();
-    }
-
-    #[inline]
-    pub unsafe fn destroy(&self) {
-        self.lock.destroy();
-        self.cond.destroy();
-    }
-}
-
-impl State {
-    fn inc_readers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Reading(1);
-                true
-            }
-            State::Reading(ref mut cnt) => {
-                *cnt += 1;
-                true
-            }
-            State::Writing => false,
-        }
-    }
-
-    fn inc_writers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Writing;
-                true
-            }
-            State::Reading(_) | State::Writing => false,
-        }
-    }
-
-    fn dec_readers(&mut self) -> bool {
-        let zero = match *self {
-            State::Reading(ref mut cnt) => {
-                *cnt -= 1;
-                *cnt == 0
-            }
-            State::Unlocked | State::Writing => invalid(),
-        };
-        if zero {
-            *self = State::Unlocked;
-        }
-        zero
-    }
-
-    fn dec_writers(&mut self) {
-        match *self {
-            State::Writing => {}
-            State::Unlocked | State::Reading(_) => invalid(),
-        }
-        *self = State::Unlocked;
-    }
-}
-
-fn invalid() -> ! {
-    panic!("inconsistent rwlock");
-}
index 16418a06226e4884a89e022feb6152f255ecae7d..714b7049227940bdcd8578cc0f3f609a4478f2d0 100644 (file)
@@ -53,37 +53,3 @@ pub unsafe fn init() -> Option<Guard> {
         None
     }
 }
-
-// We currently just use our own thread-local to store our
-// current thread's ID, and then we lazily initialize it to something allocated
-// from a global counter.
-pub fn my_id() -> u32 {
-    use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};
-
-    static NEXT_ID: AtomicU32 = AtomicU32::new(0);
-
-    #[thread_local]
-    static mut MY_ID: u32 = 0;
-
-    unsafe {
-        // If our thread ID isn't set yet then we need to allocate one. Do so
-        // with with a simple "atomically add to a global counter" strategy.
-        // This strategy doesn't handled what happens when the counter
-        // overflows, however, so just abort everything once the counter
-        // overflows and eventually we could have some sort of recycling scheme
-        // (or maybe this is all totally irrelevant by that point!). In any case
-        // though we're using a CAS loop instead of a `fetch_add` to ensure that
-        // the global counter never overflows.
-        if MY_ID == 0 {
-            let mut cur = NEXT_ID.load(SeqCst);
-            MY_ID = loop {
-                let next = cur.checked_add(1).unwrap_or_else(|| crate::process::abort());
-                match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) {
-                    Ok(_) => break next,
-                    Err(i) => cur = i,
-                }
-            };
-        }
-        MY_ID
-    }
-}
index 9f6700caf14bf9dbc7d7c40e9b981ec94dd931dc..9992e44b0e7566b2fb9f8857550dcb2e29999477 100644 (file)
 
 cfg_if::cfg_if! {
     if #[cfg(target_feature = "atomics")] {
-        #[path = "atomics/condvar.rs"]
-        mod condvar;
-        #[path = "atomics/mutex.rs"]
-        mod mutex;
-        #[path = "atomics/rwlock.rs"]
-        mod rwlock;
+        #[path = "../unix/locks"]
         pub mod locks {
-            pub use super::condvar::*;
-            pub use super::mutex::*;
-            pub use super::rwlock::*;
+            #![allow(unsafe_op_in_unsafe_fn)]
+            mod futex;
+            mod futex_rwlock;
+            pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+            pub use futex_rwlock::{RwLock, MovableRwLock};
         }
         #[path = "atomics/futex.rs"]
         pub mod futex;
index 336264d99f90030e40188d0714f234d6f40bb016..5f14edaf067c096f66039e7502d4626440373a6d 100644 (file)
@@ -536,15 +536,6 @@ pub struct CONDITION_VARIABLE {
 pub struct SRWLOCK {
     pub ptr: LPVOID,
 }
-#[repr(C)]
-pub struct CRITICAL_SECTION {
-    CriticalSectionDebug: LPVOID,
-    LockCount: LONG,
-    RecursionCount: LONG,
-    OwningThread: HANDLE,
-    LockSemaphore: HANDLE,
-    SpinCount: ULONG_PTR,
-}
 
 #[repr(C)]
 pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
@@ -875,11 +866,6 @@ pub struct FILE_STANDARD_INFO {
 #[link(name = "kernel32")]
 extern "system" {
     pub fn GetCurrentProcessId() -> DWORD;
-    pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
-    pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
-    pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL;
-    pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
-    pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
 
     pub fn GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT;
     pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
index 35bd59130346f2bb7672ea13397cb7c4fbed012b..d412ff152a047daa4a56475300d0eb164631f92a 100644 (file)
@@ -2,5 +2,5 @@
 mod mutex;
 mod rwlock;
 pub use condvar::{Condvar, MovableCondvar};
-pub use mutex::{MovableMutex, Mutex, ReentrantMutex};
+pub use mutex::{MovableMutex, Mutex};
 pub use rwlock::{MovableRwLock, RwLock};
index 56f91ebe5828721777df75b3bf4372545a867748..9fa280b8b765994fdb096a1317f4130f5198004c 100644 (file)
@@ -15,7 +15,6 @@
 //!    is that there are no guarantees of fairness.
 
 use crate::cell::UnsafeCell;
-use crate::mem::MaybeUninit;
 use crate::sys::c;
 
 pub struct Mutex {
@@ -60,37 +59,3 @@ pub unsafe fn destroy(&self) {
         // SRWLock does not need to be destroyed.
     }
 }
-
-pub struct ReentrantMutex {
-    inner: MaybeUninit<UnsafeCell<c::CRITICAL_SECTION>>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
-    pub const fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex { inner: MaybeUninit::uninit() }
-    }
-
-    pub unsafe fn init(&self) {
-        c::InitializeCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
-    }
-
-    pub unsafe fn lock(&self) {
-        c::EnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        c::TryEnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())) != 0
-    }
-
-    pub unsafe fn unlock(&self) {
-        c::LeaveCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
-    }
-
-    pub unsafe fn destroy(&self) {
-        c::DeleteCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
-    }
-}
index 801c9c28dd388a871fada0b020427bfdde9fd1bd..8f252308de760e8515212aaf4209ecfa9089b032 100644 (file)
@@ -1,10 +1,12 @@
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
 
+use crate::cell::UnsafeCell;
 use crate::marker::PhantomPinned;
 use crate::ops::Deref;
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::pin::Pin;
+use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
 use crate::sys::locks as sys;
 
 /// A re-entrant mutual exclusion
 /// This mutex will block *other* threads waiting for the lock to become
 /// available. The thread which has already locked the mutex can lock it
 /// multiple times without blocking, preventing a common source of deadlocks.
+///
+/// This is used by stdout().lock() and friends.
+///
+/// ## Implementation details
+///
+/// The 'owner' field tracks which thread has locked the mutex.
+///
+/// We use current_thread_unique_ptr() as the thread identifier,
+/// which is just the address of a thread local variable.
+///
+/// If `owner` is set to the identifier of the current thread,
+/// we assume the mutex is already locked and instead of locking it again,
+/// we increment `lock_count`.
+///
+/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
+/// it reaches zero.
+///
+/// `lock_count` is protected by the mutex and only accessed by the thread that has
+/// locked the mutex, so needs no synchronization.
+///
+/// `owner` can be checked by other threads that want to see if they already
+/// hold the lock, so needs to be atomic. If it compares equal, we're on the
+/// same thread that holds the mutex and memory access can use relaxed ordering
+/// since we're not dealing with multiple threads. If it compares unequal,
+/// synchronization is left to the mutex, making relaxed memory ordering for
+/// the `owner` field fine in all cases.
 pub struct ReentrantMutex<T> {
-    inner: sys::ReentrantMutex,
+    mutex: sys::Mutex,
+    owner: AtomicUsize,
+    lock_count: UnsafeCell<u32>,
     data: T,
     _pinned: PhantomPinned,
 }
@@ -53,7 +83,9 @@ impl<T> ReentrantMutex<T> {
     /// lock/unlock methods safe.
     pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
         ReentrantMutex {
-            inner: sys::ReentrantMutex::uninitialized(),
+            mutex: sys::Mutex::new(),
+            owner: AtomicUsize::new(0),
+            lock_count: UnsafeCell::new(0),
             data: t,
             _pinned: PhantomPinned,
         }
@@ -66,7 +98,7 @@ impl<T> ReentrantMutex<T> {
     /// Unsafe to call more than once, and must be called after this will no
     /// longer move in memory.
     pub unsafe fn init(self: Pin<&mut Self>) {
-        self.get_unchecked_mut().inner.init()
+        self.get_unchecked_mut().mutex.init()
     }
 
     /// Acquires a mutex, blocking the current thread until it is able to do so.
@@ -82,7 +114,19 @@ pub unsafe fn init(self: Pin<&mut Self>) {
     /// this call will return failure if the mutex would otherwise be
     /// acquired.
     pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> {
-        unsafe { self.inner.lock() }
+        let this_thread = current_thread_unique_ptr();
+        // Safety: We only touch lock_count when we own the lock,
+        // and since self is pinned we can safely call the lock() on the mutex.
+        unsafe {
+            if self.owner.load(Relaxed) == this_thread {
+                self.increment_lock_count();
+            } else {
+                self.mutex.lock();
+                self.owner.store(this_thread, Relaxed);
+                debug_assert_eq!(*self.lock_count.get(), 0);
+                *self.lock_count.get() = 1;
+            }
+        }
         ReentrantMutexGuard { lock: self }
     }
 
@@ -99,20 +143,35 @@ pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> {
     /// this call will return failure if the mutex would otherwise be
     /// acquired.
     pub fn try_lock(self: Pin<&Self>) -> Option<ReentrantMutexGuard<'_, T>> {
-        if unsafe { self.inner.try_lock() } {
-            Some(ReentrantMutexGuard { lock: self })
-        } else {
-            None
+        let this_thread = current_thread_unique_ptr();
+        // Safety: We only touch lock_count when we own the lock,
+        // and since self is pinned we can safely call the try_lock on the mutex.
+        unsafe {
+            if self.owner.load(Relaxed) == this_thread {
+                self.increment_lock_count();
+                Some(ReentrantMutexGuard { lock: self })
+            } else if self.mutex.try_lock() {
+                self.owner.store(this_thread, Relaxed);
+                debug_assert_eq!(*self.lock_count.get(), 0);
+                *self.lock_count.get() = 1;
+                Some(ReentrantMutexGuard { lock: self })
+            } else {
+                None
+            }
         }
     }
+
+    unsafe fn increment_lock_count(&self) {
+        *self.lock_count.get() = (*self.lock_count.get())
+            .checked_add(1)
+            .expect("lock count overflow in reentrant mutex");
+    }
 }
 
 impl<T> Drop for ReentrantMutex<T> {
     fn drop(&mut self) {
-        // This is actually safe b/c we know that there is no further usage of
-        // this mutex (it's up to the user to arrange for a mutex to get
-        // dropped, that's not our job)
-        unsafe { self.inner.destroy() }
+        // Safety: We're the unique owner of this mutex and not going to use it afterwards.
+        unsafe { self.mutex.destroy() }
     }
 }
 
@@ -127,8 +186,22 @@ fn deref(&self) -> &T {
 impl<T> Drop for ReentrantMutexGuard<'_, T> {
     #[inline]
     fn drop(&mut self) {
+        // Safety: We own the lock, and the lock is pinned.
         unsafe {
-            self.lock.inner.unlock();
+            *self.lock.lock_count.get() -= 1;
+            if *self.lock.lock_count.get() == 0 {
+                self.lock.owner.store(0, Relaxed);
+                self.lock.mutex.unlock();
+            }
         }
     }
 }
+
+/// Get an address that is unique per running thread.
+///
+/// This can be used as a non-null usize-sized ID.
+pub fn current_thread_unique_ptr() -> usize {
+    // Use a non-drop type to make sure it's still available during thread destruction.
+    thread_local! { static X: u8 = const { 0 } }
+    X.with(|x| <*const _>::addr(x))
+}
index 047d07ad57df148035ae8a1003082529985c91c3..4ab8fb2e9052c6d20b0233e43d3f34495a30be8c 100644 (file)
@@ -178,7 +178,7 @@ macro_rules! thread_local {
 macro_rules! __thread_local_inner {
     // used to generate the `LocalKey` value for const-initialized thread locals
     (@key $t:ty, const $init:expr) => {{
-        #[cfg_attr(not(windows), inline(always))] // see comments below
+        #[cfg_attr(not(windows), inline)] // see comments below
         #[deny(unsafe_op_in_unsafe_fn)]
         unsafe fn __getit(
             _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
@@ -312,7 +312,7 @@ fn __init() -> $t { $init }
             // gets the pessimistic path for now where it's never inlined.
             //
             // The issue of "should enable on Windows sometimes" is #84933
-            #[cfg_attr(not(windows), inline(always))]
+            #[cfg_attr(not(windows), inline)]
             unsafe fn __getit(
                 init: $crate::option::Option<&mut $crate::option::Option<$t>>,
             ) -> $crate::option::Option<&'static $t> {
index d437397045c64d0920b6d6330891fad2ac858b2c..ac1c47524fd0e2f65c295411645e47dfafcfe69a 100644 (file)
@@ -817,7 +817,7 @@ class RustBuild(object):
         return os.path.join(self.bin_root(True), '.rustfmt-stamp')
 
     def llvm_stamp(self):
-        """Return the path for .rustfmt-stamp
+        """Return the path for .llvm-stamp
 
         >>> rb = RustBuild()
         >>> rb.build_dir = "build"
index 0276d15a5b472bb857bdb8add33e031e54e3f047..0c4f3265dbf9e7869d0fb7599cceb70981a7b336 100644 (file)
@@ -3,7 +3,7 @@
 use std::collections::BTreeSet;
 use std::env;
 use std::ffi::OsStr;
-use std::fmt::Debug;
+use std::fmt::{Debug, Write};
 use std::fs;
 use std::hash::Hash;
 use std::ops::Deref;
@@ -14,7 +14,7 @@
 use crate::cache::{Cache, Interned, INTERNER};
 use crate::check;
 use crate::compile;
-use crate::config::TargetSelection;
+use crate::config::{SplitDebuginfo, TargetSelection};
 use crate::dist;
 use crate::doc;
 use crate::flags::{Color, Subcommand};
@@ -125,7 +125,8 @@ pub fn parse(path: impl Into<PathBuf>) -> TaskPath {
                     if found_kind.is_empty() {
                         panic!("empty kind in task path {}", path.display());
                     }
-                    kind = Some(Kind::parse(found_kind));
+                    kind = Kind::parse(found_kind);
+                    assert!(kind.is_some());
                     path = Path::new(found_prefix).join(components.as_path());
                 }
             }
@@ -364,6 +365,19 @@ pub fn krate(mut self, name: &str) -> Self {
         self
     }
 
+    // single alias, which does not correspond to any on-disk path
+    pub fn alias(mut self, alias: &str) -> Self {
+        assert!(
+            !self.builder.src.join(alias).exists(),
+            "use `builder.path()` for real paths: {}",
+            alias
+        );
+        self.paths.insert(PathSet::Set(
+            std::iter::once(TaskPath { path: alias.into(), kind: Some(self.kind) }).collect(),
+        ));
+        self
+    }
+
     // single, non-aliased path
     pub fn path(self, path: &str) -> Self {
         self.paths(&[path])
@@ -372,7 +386,19 @@ pub fn path(self, path: &str) -> Self {
     // multiple aliases for the same job
     pub fn paths(mut self, paths: &[&str]) -> Self {
         self.paths.insert(PathSet::Set(
-            paths.iter().map(|p| TaskPath { path: p.into(), kind: Some(self.kind) }).collect(),
+            paths
+                .iter()
+                .map(|p| {
+                    // FIXME(#96188): make sure this is actually a path.
+                    // This currently breaks for paths within submodules.
+                    //assert!(
+                    //    self.builder.src.join(p).exists(),
+                    //    "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
+                    //    p
+                    //);
+                    TaskPath { path: p.into(), kind: Some(self.kind) }
+                })
+                .collect(),
         ));
         self
     }
@@ -406,43 +432,53 @@ pub enum Kind {
     Check,
     Clippy,
     Fix,
+    Format,
     Test,
     Bench,
-    Dist,
     Doc,
+    Clean,
+    Dist,
     Install,
     Run,
+    Setup,
 }
 
 impl Kind {
-    fn parse(string: &str) -> Kind {
-        match string {
-            "build" => Kind::Build,
-            "check" => Kind::Check,
+    pub fn parse(string: &str) -> Option<Kind> {
+        // these strings, including the one-letter aliases, must match the x.py help text
+        Some(match string {
+            "build" | "b" => Kind::Build,
+            "check" | "c" => Kind::Check,
             "clippy" => Kind::Clippy,
             "fix" => Kind::Fix,
-            "test" => Kind::Test,
+            "fmt" => Kind::Format,
+            "test" | "t" => Kind::Test,
             "bench" => Kind::Bench,
+            "doc" | "d" => Kind::Doc,
+            "clean" => Kind::Clean,
             "dist" => Kind::Dist,
-            "doc" => Kind::Doc,
             "install" => Kind::Install,
-            "run" => Kind::Run,
-            other => panic!("unknown kind: {}", other),
-        }
+            "run" | "r" => Kind::Run,
+            "setup" => Kind::Setup,
+            _ => return None,
+        })
     }
 
-    fn as_str(&self) -> &'static str {
+    pub fn as_str(&self) -> &'static str {
         match self {
             Kind::Build => "build",
             Kind::Check => "check",
             Kind::Clippy => "clippy",
             Kind::Fix => "fix",
+            Kind::Format => "fmt",
             Kind::Test => "test",
             Kind::Bench => "bench",
-            Kind::Dist => "dist",
             Kind::Doc => "doc",
+            Kind::Clean => "clean",
+            Kind::Dist => "dist",
             Kind::Install => "install",
             Kind::Run => "run",
+            Kind::Setup => "setup",
         }
     }
 }
@@ -486,7 +522,7 @@ macro_rules! describe {
                 native::Lld,
                 native::CrtBeginEnd
             ),
-            Kind::Check | Kind::Clippy { .. } | Kind::Fix => describe!(
+            Kind::Check => describe!(
                 check::Std,
                 check::Rustc,
                 check::Rustdoc,
@@ -616,32 +652,29 @@ macro_rules! describe {
                 install::Rustc
             ),
             Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest, run::BumpStage0),
+            // These commands either don't use paths, or they're special-cased in Build::build()
+            Kind::Clean | Kind::Clippy | Kind::Fix | Kind::Format | Kind::Setup => vec![],
         }
     }
 
-    pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
-        let kind = match subcommand {
-            "build" | "b" => Kind::Build,
-            "doc" | "d" => Kind::Doc,
-            "test" | "t" => Kind::Test,
-            "bench" => Kind::Bench,
-            "dist" => Kind::Dist,
-            "install" => Kind::Install,
-            _ => return None,
-        };
+    pub fn get_help(build: &Build, kind: Kind) -> Option<String> {
+        let step_descriptions = Builder::get_step_descriptions(kind);
+        if step_descriptions.is_empty() {
+            return None;
+        }
 
         let builder = Self::new_internal(build, kind, vec![]);
         let builder = &builder;
         // The "build" kind here is just a placeholder, it will be replaced with something else in
         // the following statement.
         let mut should_run = ShouldRun::new(builder, Kind::Build);
-        for desc in Builder::get_step_descriptions(builder.kind) {
+        for desc in step_descriptions {
             should_run.kind = desc.kind;
             should_run = (desc.should_run)(should_run);
         }
         let mut help = String::from("Available paths:\n");
         let mut add_path = |path: &Path| {
-            help.push_str(&format!("    ./x.py {} {}\n", subcommand, path.display()));
+            t!(write!(help, "    ./x.py {} {}\n", kind.as_str(), path.display()));
         };
         for pathset in should_run.paths {
             match pathset {
@@ -1365,17 +1398,17 @@ pub fn cargo(
             },
         );
 
-        // `dsymutil` adds time to builds on Apple platforms for no clear benefit, and also makes
-        // it more difficult for debuggers to find debug info. The compiler currently defaults to
-        // running `dsymutil` to preserve its historical default, but when compiling the compiler
-        // itself, we skip it by default since we know it's safe to do so in that case.
-        // See https://github.com/rust-lang/rust/issues/79361 for more info on this flag.
-        if target.contains("apple") {
-            if self.config.rust_run_dsymutil {
-                rustflags.arg("-Csplit-debuginfo=packed");
-            } else {
-                rustflags.arg("-Csplit-debuginfo=unpacked");
+        // FIXME(davidtwco): #[cfg(not(bootstrap))] - #95612 needs to be in the bootstrap compiler
+        // for this conditional to be removed.
+        if !target.contains("windows") || compiler.stage >= 1 {
+            if target.contains("linux") || target.contains("windows") {
+                rustflags.arg("-Zunstable-options");
             }
+            match self.config.rust_split_debuginfo {
+                SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
+                SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
+                SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
+            };
         }
 
         if self.config.cmd.bless() {
index 7ce446876118af13244c4c914dc2dfcdf1ca525a..dca782c29c252f72ac6087787ac559541ff28cd2 100644 (file)
@@ -149,6 +149,10 @@ pub fn find(build: &mut Build) {
             build.verbose(&format!("AR_{} = {:?}", &target.triple, ar));
             build.ar.insert(target, ar);
         }
+
+        if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) {
+            build.ranlib.insert(target, ranlib);
+        }
     }
 }
 
index d7c29f6900a534028c53746ff9c1182f58380ddb..f273fb42215e95873c8e48d9b86a0e8d4fb14a87 100644 (file)
@@ -130,7 +130,7 @@ pub struct Config {
     pub rust_debuginfo_level_std: u32,
     pub rust_debuginfo_level_tools: u32,
     pub rust_debuginfo_level_tests: u32,
-    pub rust_run_dsymutil: bool,
+    pub rust_split_debuginfo: SplitDebuginfo,
     pub rust_rpath: bool,
     pub rustc_parallel: bool,
     pub rustc_default_linker: Option<String>,
@@ -221,6 +221,46 @@ fn from_str(value: &str) -> Result<Self, Self::Err> {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum SplitDebuginfo {
+    Packed,
+    Unpacked,
+    Off,
+}
+
+impl Default for SplitDebuginfo {
+    fn default() -> Self {
+        SplitDebuginfo::Off
+    }
+}
+
+impl std::str::FromStr for SplitDebuginfo {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "packed" => Ok(SplitDebuginfo::Packed),
+            "unpacked" => Ok(SplitDebuginfo::Unpacked),
+            "off" => Ok(SplitDebuginfo::Off),
+            _ => Err(()),
+        }
+    }
+}
+
+impl SplitDebuginfo {
+    /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for
+    /// `rust.split-debuginfo` in `config.toml.example`.
+    fn default_for_platform(target: &str) -> Self {
+        if target.contains("apple") {
+            SplitDebuginfo::Unpacked
+        } else if target.contains("windows") {
+            SplitDebuginfo::Packed
+        } else {
+            SplitDebuginfo::Off
+        }
+    }
+}
+
 #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct TargetSelection {
     pub triple: Interned<String>,
@@ -586,6 +626,7 @@ struct Rust {
         debuginfo_level_std: Option<u32> = "debuginfo-level-std",
         debuginfo_level_tools: Option<u32> = "debuginfo-level-tools",
         debuginfo_level_tests: Option<u32> = "debuginfo-level-tests",
+        split_debuginfo: Option<String> = "split-debuginfo",
         run_dsymutil: Option<bool> = "run-dsymutil",
         backtrace: Option<bool> = "backtrace",
         incremental: Option<bool> = "incremental",
@@ -992,7 +1033,12 @@ pub fn parse(args: &[String]) -> Config {
             debuginfo_level_std = rust.debuginfo_level_std;
             debuginfo_level_tools = rust.debuginfo_level_tools;
             debuginfo_level_tests = rust.debuginfo_level_tests;
-            config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false);
+            config.rust_split_debuginfo = rust
+                .split_debuginfo
+                .as_deref()
+                .map(SplitDebuginfo::from_str)
+                .map(|v| v.expect("invalid value for rust.split_debuginfo"))
+                .unwrap_or(SplitDebuginfo::default_for_platform(&config.build.triple));
             optimize = rust.optimize;
             ignore_git = rust.ignore_git;
             config.rust_new_symbol_mangling = rust.new_symbol_mangling;
index fdd1581d9cd95460adb5eca62b2306a3f622d65c..e3287e35227b9915cb1825f21e0dcdfb78bd15a9 100644 (file)
@@ -61,7 +61,7 @@ impl Step for Docs {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = run.builder.config.docs;
-        run.path("rust-docs").default_condition(default)
+        run.alias("rust-docs").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -94,7 +94,7 @@ impl Step for RustcDocs {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.path("rustc-docs").default_condition(builder.config.compiler_docs)
+        run.alias("rustc-docs").default_condition(builder.config.compiler_docs)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -272,7 +272,7 @@ impl Step for Mingw {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("rust-mingw")
+        run.alias("rust-mingw")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -313,7 +313,7 @@ impl Step for Rustc {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("rustc")
+        run.alias("rustc")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -456,7 +456,7 @@ impl Step for DebuggerScripts {
     type Output = ();
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/lldb_batchmode.py")
+        run.path("src/etc/lldb_batchmode.py")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -547,7 +547,7 @@ impl Step for Std {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("rust-std")
+        run.alias("rust-std")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -594,7 +594,7 @@ impl Step for RustcDev {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("rustc-dev")
+        run.alias("rustc-dev")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -653,7 +653,7 @@ impl Step for Analysis {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "analysis");
-        run.path("rust-analysis").default_condition(default)
+        run.alias("rust-analysis").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -790,7 +790,7 @@ impl Step for Src {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("rust-src")
+        run.alias("rust-src")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -848,7 +848,7 @@ impl Step for PlainSourceTarball {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.path("rustc-src").default_condition(builder.config.rust_dist_src)
+        run.alias("rustc-src").default_condition(builder.config.rust_dist_src)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -942,7 +942,7 @@ impl Step for Cargo {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "cargo");
-        run.path("cargo").default_condition(default)
+        run.alias("cargo").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -998,7 +998,7 @@ impl Step for Rls {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "rls");
-        run.path("rls").default_condition(default)
+        run.alias("rls").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1045,7 +1045,7 @@ impl Step for RustAnalyzer {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "rust-analyzer");
-        run.path("rust-analyzer").default_condition(default)
+        run.alias("rust-analyzer").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1101,7 +1101,7 @@ impl Step for Clippy {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "clippy");
-        run.path("clippy").default_condition(default)
+        run.alias("clippy").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1152,7 +1152,7 @@ impl Step for Miri {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "miri");
-        run.path("miri").default_condition(default)
+        run.alias("miri").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1212,7 +1212,7 @@ impl Step for Rustfmt {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "rustfmt");
-        run.path("rustfmt").default_condition(default)
+        run.alias("rustfmt").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1271,7 +1271,7 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         // we run the step by default when only `extended = true`, and decide whether to actually
         // run it or not later.
         let default = run.builder.config.extended;
-        run.path("rust-demangler").default_condition(default)
+        run.alias("rust-demangler").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1324,7 +1324,7 @@ impl Step for Extended {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.path("extended").default_condition(builder.config.extended)
+        run.alias("extended").default_condition(builder.config.extended)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1968,7 +1968,8 @@ impl Step for LlvmTools {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let default = should_build_extended_tool(&run.builder, "llvm-tools");
-        run.path("llvm-tools").default_condition(default)
+        // FIXME: allow using the names of the tools themselves?
+        run.alias("llvm-tools").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -2022,7 +2023,7 @@ impl Step for RustDev {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("rust-dev")
+        run.alias("rust-dev")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -2098,7 +2099,7 @@ impl Step for BuildManifest {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("build-manifest")
+        run.alias("build-manifest")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -2130,7 +2131,7 @@ impl Step for ReproducibleArtifacts {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("reproducible-artifacts")
+        run.alias("reproducible-artifacts")
     }
 
     fn make_run(run: RunConfig<'_>) {
index 1a4e6a9688803b544295aa7d1c7ba0d5d2d9c2d0..a82eb52e232b4725af9860c8768028c2e12d9ab4 100644 (file)
@@ -8,7 +8,7 @@
 
 use getopts::Options;
 
-use crate::builder::Builder;
+use crate::builder::{Builder, Kind};
 use crate::config::{Config, TargetSelection};
 use crate::setup::Profile;
 use crate::util::t;
@@ -243,27 +243,7 @@ pub fn parse(args: &[String]) -> Flags {
         // the subcommand. Therefore we must manually identify the subcommand first, so that we can
         // complete the definition of the options.  Then we can use the getopt::Matches object from
         // there on out.
-        let subcommand = args.iter().find(|&s| {
-            (s == "build")
-                || (s == "b")
-                || (s == "check")
-                || (s == "c")
-                || (s == "clippy")
-                || (s == "fix")
-                || (s == "fmt")
-                || (s == "test")
-                || (s == "t")
-                || (s == "bench")
-                || (s == "doc")
-                || (s == "d")
-                || (s == "clean")
-                || (s == "dist")
-                || (s == "install")
-                || (s == "run")
-                || (s == "r")
-                || (s == "setup")
-        });
-        let subcommand = match subcommand {
+        let subcommand = match args.iter().find_map(|s| Kind::parse(&s)) {
             Some(s) => s,
             None => {
                 // No or an invalid subcommand -- show the general usage and subcommand help
@@ -276,8 +256,8 @@ pub fn parse(args: &[String]) -> Flags {
         };
 
         // Some subcommands get extra options
-        match subcommand.as_str() {
-            "test" | "t" => {
+        match subcommand {
+            Kind::Test => {
                 opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
                 opts.optmulti(
                     "",
@@ -316,22 +296,22 @@ pub fn parse(args: &[String]) -> Flags {
                         `/<build_base>/rustfix_missing_coverage.txt`",
                 );
             }
-            "check" | "c" => {
+            Kind::Check => {
                 opts.optflag("", "all-targets", "Check all targets");
             }
-            "bench" => {
+            Kind::Bench => {
                 opts.optmulti("", "test-args", "extra arguments", "ARGS");
             }
-            "clippy" => {
+            Kind::Clippy => {
                 opts.optflag("", "fix", "automatically apply lint suggestions");
             }
-            "doc" | "d" => {
+            Kind::Doc => {
                 opts.optflag("", "open", "open the docs in a browser");
             }
-            "clean" => {
+            Kind::Clean => {
                 opts.optflag("", "all", "clean all build artifacts");
             }
-            "fmt" => {
+            Kind::Format => {
                 opts.optflag("", "check", "check formatting instead of applying.");
             }
             _ => {}
@@ -339,25 +319,22 @@ pub fn parse(args: &[String]) -> Flags {
 
         // fn usage()
         let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
-            let mut extra_help = String::new();
-
-            // All subcommands except `clean` can have an optional "Available paths" section
-            if verbose {
-                let config = Config::parse(&["build".to_string()]);
-                let build = Build::new(config);
-
-                let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
-                extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
-            } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") {
-                extra_help.push_str(
-                    format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand)
-                        .as_str(),
-                );
-            }
+            let config = Config::parse(&["build".to_string()]);
+            let build = Build::new(config);
+            let paths = Builder::get_help(&build, subcommand);
 
             println!("{}", opts.usage(subcommand_help));
-            if !extra_help.is_empty() {
-                println!("{}", extra_help);
+            if let Some(s) = paths {
+                if verbose {
+                    println!("{}", s);
+                } else {
+                    println!(
+                        "Run `./x.py {} -h -v` to see a list of available paths.",
+                        subcommand.as_str()
+                    );
+                }
+            } else if verbose {
+                panic!("No paths available for subcommand `{}`", subcommand.as_str());
             }
             process::exit(exit_code);
         };
@@ -375,7 +352,7 @@ pub fn parse(args: &[String]) -> Flags {
         //            ^-- option  ^     ^- actual subcommand
         //                        \_ arg to option could be mistaken as subcommand
         let mut pass_sanity_check = true;
-        match matches.free.get(0) {
+        match matches.free.get(0).and_then(|s| Kind::parse(&s)) {
             Some(check_subcommand) => {
                 if check_subcommand != subcommand {
                     pass_sanity_check = false;
@@ -394,8 +371,8 @@ pub fn parse(args: &[String]) -> Flags {
             process::exit(1);
         }
         // Extra help text for some commands
-        match subcommand.as_str() {
-            "build" | "b" => {
+        match subcommand {
+            Kind::Build => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -415,7 +392,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py build ",
                 );
             }
-            "check" | "c" => {
+            Kind::Check => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -427,7 +404,7 @@ pub fn parse(args: &[String]) -> Flags {
     If no arguments are passed then many artifacts are checked.",
                 );
             }
-            "clippy" => {
+            Kind::Clippy => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -438,7 +415,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py clippy library/core library/proc_macro",
                 );
             }
-            "fix" => {
+            Kind::Fix => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -449,7 +426,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py fix library/core library/proc_macro",
                 );
             }
-            "fmt" => {
+            Kind::Format => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -460,7 +437,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py fmt --check",
                 );
             }
-            "test" | "t" => {
+            Kind::Test => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -488,7 +465,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py test --stage 1",
                 );
             }
-            "doc" | "d" => {
+            Kind::Doc => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -506,7 +483,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py doc --stage 1",
                 );
             }
-            "run" | "r" => {
+            Kind::Run => {
                 subcommand_help.push_str(
                     "\n
 Arguments:
@@ -518,7 +495,7 @@ pub fn parse(args: &[String]) -> Flags {
     At least a tool needs to be called.",
                 );
             }
-            "setup" => {
+            Kind::Setup => {
                 subcommand_help.push_str(&format!(
                     "\n
 x.py setup creates a `config.toml` which changes the defaults for x.py itself.
@@ -535,7 +512,7 @@ pub fn parse(args: &[String]) -> Flags {
                     Profile::all_for_help("        ").trim_end()
                 ));
             }
-            _ => {}
+            Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install => {}
         };
         // Get any optional paths which occur after the subcommand
         let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
@@ -547,9 +524,9 @@ pub fn parse(args: &[String]) -> Flags {
             usage(0, &opts, verbose, &subcommand_help);
         }
 
-        let cmd = match subcommand.as_str() {
-            "build" | "b" => Subcommand::Build { paths },
-            "check" | "c" => {
+        let cmd = match subcommand {
+            Kind::Build => Subcommand::Build { paths },
+            Kind::Check => {
                 if matches.opt_present("all-targets") {
                     eprintln!(
                         "Warning: --all-targets is now on by default and does not need to be passed explicitly."
@@ -557,9 +534,9 @@ pub fn parse(args: &[String]) -> Flags {
                 }
                 Subcommand::Check { paths }
             }
-            "clippy" => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
-            "fix" => Subcommand::Fix { paths },
-            "test" | "t" => Subcommand::Test {
+            Kind::Clippy => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
+            Kind::Fix => Subcommand::Fix { paths },
+            Kind::Test => Subcommand::Test {
                 paths,
                 bless: matches.opt_present("bless"),
                 force_rerun: matches.opt_present("force-rerun"),
@@ -578,9 +555,9 @@ pub fn parse(args: &[String]) -> Flags {
                     DocTests::Yes
                 },
             },
-            "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
-            "doc" | "d" => Subcommand::Doc { paths, open: matches.opt_present("open") },
-            "clean" => {
+            Kind::Bench => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
+            Kind::Doc => Subcommand::Doc { paths, open: matches.opt_present("open") },
+            Kind::Clean => {
                 if !paths.is_empty() {
                     println!("\nclean does not take a path argument\n");
                     usage(1, &opts, verbose, &subcommand_help);
@@ -588,17 +565,17 @@ pub fn parse(args: &[String]) -> Flags {
 
                 Subcommand::Clean { all: matches.opt_present("all") }
             }
-            "fmt" => Subcommand::Format { check: matches.opt_present("check"), paths },
-            "dist" => Subcommand::Dist { paths },
-            "install" => Subcommand::Install { paths },
-            "run" | "r" => {
+            Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths },
+            Kind::Dist => Subcommand::Dist { paths },
+            Kind::Install => Subcommand::Install { paths },
+            Kind::Run => {
                 if paths.is_empty() {
                     println!("\nrun requires at least a path!\n");
                     usage(1, &opts, verbose, &subcommand_help);
                 }
                 Subcommand::Run { paths }
             }
-            "setup" => {
+            Kind::Setup => {
                 let profile = if paths.len() > 1 {
                     println!("\nat most one profile can be passed to setup\n");
                     usage(1, &opts, verbose, &subcommand_help)
@@ -618,9 +595,6 @@ pub fn parse(args: &[String]) -> Flags {
                 };
                 Subcommand::Setup { profile }
             }
-            _ => {
-                usage(1, &opts, verbose, &subcommand_help);
-            }
         };
 
         if let Subcommand::Check { .. } = &cmd {
index 27b9196d9868e10d23deb5cfb8682ef03f788397..08e37a16279903a8a7f080cf7f6bcdcdab1826f4 100644 (file)
@@ -93,7 +93,7 @@ fn prepare_dir(mut path: PathBuf) -> String {
 macro_rules! install {
     (($sel:ident, $builder:ident, $_config:ident),
        $($name:ident,
-       $path:expr,
+       $condition_name: ident = $path_or_alias: literal,
        $default_cond:expr,
        only_hosts: $only_hosts:expr,
        $run_item:block $(, $c:ident)*;)+) => {
@@ -108,7 +108,7 @@ impl $name {
             #[allow(dead_code)]
             fn should_build(config: &Config) -> bool {
                 config.extended && config.tools.as_ref()
-                    .map_or(true, |t| t.contains($path))
+                    .map_or(true, |t| t.contains($path_or_alias))
             }
         }
 
@@ -120,7 +120,7 @@ impl Step for $name {
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                 let $_config = &run.builder.config;
-                run.path($path).default_condition($default_cond)
+                run.$condition_name($path_or_alias).default_condition($default_cond)
             }
 
             fn make_run(run: RunConfig<'_>) {
@@ -138,11 +138,11 @@ fn run($sel, $builder: &Builder<'_>) {
 }
 
 install!((self, builder, _config),
-    Docs, "src/doc", _config.docs, only_hosts: false, {
+    Docs, path = "src/doc", _config.docs, only_hosts: false, {
         let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs");
         install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball);
     };
-    Std, "library/std", true, only_hosts: false, {
+    Std, path = "library/std", true, only_hosts: false, {
         for target in &builder.targets {
             // `expect` should be safe, only None when host != build, but this
             // only runs when host == build
@@ -153,13 +153,13 @@ fn run($sel, $builder: &Builder<'_>) {
             install_sh(builder, "std", self.compiler.stage, Some(*target), &tarball);
         }
     };
-    Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
+    Cargo, alias = "cargo", Self::should_build(_config), only_hosts: true, {
         let tarball = builder
             .ensure(dist::Cargo { compiler: self.compiler, target: self.target })
             .expect("missing cargo");
         install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball);
     };
-    Rls, "rls", Self::should_build(_config), only_hosts: true, {
+    Rls, alias = "rls", Self::should_build(_config), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }) {
             install_sh(builder, "rls", self.compiler.stage, Some(self.target), &tarball);
         } else {
@@ -168,7 +168,7 @@ fn run($sel, $builder: &Builder<'_>) {
             );
         }
     };
-    RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
+    RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), only_hosts: true, {
         if let Some(tarball) =
             builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target })
         {
@@ -179,13 +179,13 @@ fn run($sel, $builder: &Builder<'_>) {
             );
         }
     };
-    Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
+    Clippy, alias = "clippy", Self::should_build(_config), only_hosts: true, {
         let tarball = builder
             .ensure(dist::Clippy { compiler: self.compiler, target: self.target })
             .expect("missing clippy");
         install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball);
     };
-    Miri, "miri", Self::should_build(_config), only_hosts: true, {
+    Miri, alias = "miri", Self::should_build(_config), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }) {
             install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball);
         } else {
@@ -194,7 +194,7 @@ fn run($sel, $builder: &Builder<'_>) {
             );
         }
     };
-    Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
+    Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::Rustfmt {
             compiler: self.compiler,
             target: self.target
@@ -206,7 +206,7 @@ fn run($sel, $builder: &Builder<'_>) {
             );
         }
     };
-    RustDemangler, "rust-demangler", Self::should_build(_config), only_hosts: true, {
+    RustDemangler, alias = "rust-demangler", Self::should_build(_config), only_hosts: true, {
         // Note: Even though `should_build` may return true for `extended` default tools,
         // dist::RustDemangler may still return None, unless the target-dependent `profiler` config
         // is also true, or the `tools` array explicitly includes "rust-demangler".
@@ -222,7 +222,7 @@ fn run($sel, $builder: &Builder<'_>) {
             );
         }
     };
-    Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
+    Analysis, alias = "analysis", Self::should_build(_config), only_hosts: false, {
         // `expect` should be safe, only None with host != build, but this
         // only uses the `build` compiler
         let tarball = builder.ensure(dist::Analysis {
@@ -234,7 +234,7 @@ fn run($sel, $builder: &Builder<'_>) {
         }).expect("missing analysis");
         install_sh(builder, "analysis", self.compiler.stage, Some(self.target), &tarball);
     };
-    Rustc, "src/librustc", true, only_hosts: true, {
+    Rustc, path = "compiler/rustc", true, only_hosts: true, {
         let tarball = builder.ensure(dist::Rustc {
             compiler: builder.compiler(builder.top_stage, self.target),
         });
index 6d7ca9a94cfbde9432fcff3e52c30dc7e435a125..73fb2dad1e3c23ea3d39cbba0d68dd3169054d7b 100644 (file)
@@ -122,7 +122,7 @@ impl Step for Llvm {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/llvm-project").path("src/llvm-project/llvm").path("src/llvm")
+        run.path("src/llvm-project").path("src/llvm-project/llvm")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -605,7 +605,7 @@ impl Step for Lld {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/llvm-project/lld").path("src/tools/lld")
+        run.path("src/llvm-project/lld")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -771,7 +771,7 @@ impl Step for Sanitizers {
     type Output = Vec<SanitizerRuntime>;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/llvm-project/compiler-rt").path("src/sanitizers")
+        run.alias("sanitizers")
     }
 
     fn make_run(run: RunConfig<'_>) {
index f60766bde726ebc1416239005e46318a0689da9f..da4689098119f0030c01809bb7a2376846c1785a 100644 (file)
@@ -1892,7 +1892,8 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
 
     fn make_run(run: RunConfig<'_>) {
         let builder = run.builder;
-        let compiler = builder.compiler(builder.top_stage, run.build_triple());
+        let host = run.build_triple();
+        let compiler = builder.compiler_for(builder.top_stage, host, host);
         let krate = builder.crate_paths[&run.path];
         let test_kind = builder.kind.into();
 
@@ -1929,7 +1930,8 @@ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
 
     fn make_run(run: RunConfig<'_>) {
         let builder = run.builder;
-        let compiler = builder.compiler(builder.top_stage, run.build_triple());
+        let host = run.build_triple();
+        let compiler = builder.compiler_for(builder.top_stage, host, host);
         let test_kind = builder.kind.into();
         let krate = builder.crate_paths[&run.path];
 
@@ -2288,7 +2290,7 @@ impl Step for Distcheck {
     type Output = ();
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("distcheck")
+        run.alias("distcheck")
     }
 
     fn make_run(run: RunConfig<'_>) {
index c7ea254c5b1d7ac6a242493b56ebcc5bb4c5fad1..3ee6a42d987a05385ee1f9156ea86e36ae668384 100644 (file)
@@ -234,7 +234,7 @@ fn run(self, builder: &Builder<'_>) {
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("check-tools")
+        run.alias("check-tools")
     }
 
     fn make_run(run: RunConfig<'_>) {
index ea90bbaf53ba64ef4e2da9ac2352b298aec6bec8..de0dbffc5812fd885700874e8d258dd334733ac4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ea90bbaf53ba64ef4e2da9ac2352b298aec6bec8
+Subproject commit de0dbffc5812fd885700874e8d258dd334733ac4
index a6de8b6e3ea5d4f0de8b7b9a7e5c1405dc2c2ddb..f7cefbb995eec8c6148f213235e9e2e03268e775 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a6de8b6e3ea5d4f0de8b7b9a7e5c1405dc2c2ddb
+Subproject commit f7cefbb995eec8c6148f213235e9e2e03268e775
index 11f1165e8a2f5840467e748c8108dc53c948ee9a..c7d8467ca9158da58ef295ae65dbf00a308752d9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 11f1165e8a2f5840467e748c8108dc53c948ee9a
+Subproject commit c7d8467ca9158da58ef295ae65dbf00a308752d9
index c97d14fa6fed0baa9255432b8a93cb70614f80e3..b5f6c2362baf932db9440fbfcb509b309237ee85 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c97d14fa6fed0baa9255432b8a93cb70614f80e3
+Subproject commit b5f6c2362baf932db9440fbfcb509b309237ee85
index ec954f35eedf592cd173b21c05a7f80a65b61d8a..44a80e8d8bfc5881c9bd69a2cb3a570776ee4181 160000 (submodule)
@@ -1 +1 @@
-Subproject commit ec954f35eedf592cd173b21c05a7f80a65b61d8a
+Subproject commit 44a80e8d8bfc5881c9bd69a2cb3a570776ee4181
index 155126b1d2e2cb01ddb1d7ba9489b90d7cd173ad..043e60f4f191651e9f8bf52fa32df14defbb23d9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 155126b1d2e2cb01ddb1d7ba9489b90d7cd173ad
+Subproject commit 043e60f4f191651e9f8bf52fa32df14defbb23d9
diff --git a/src/doc/unstable-book/src/compiler-flags/extern-location.md b/src/doc/unstable-book/src/compiler-flags/extern-location.md
deleted file mode 100644 (file)
index 1c80d54..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-# `extern-location`
-
-MCP for this feature: [#303]
-
-[#303]: https://github.com/rust-lang/compiler-team/issues/303
-
-------------------------
-
-The `unused-extern-crates` lint reports when a crate was specified on the rustc
-command-line with `--extern name=path` but no symbols were referenced in it.
-This is useful to know, but it's hard to map that back to a specific place a user
-or tool could fix (ie, to remove the unused dependency).
-
-The `--extern-location` flag allows the build system to associate a location with
-the `--extern` option, which is then emitted as part of the diagnostics. This location
-is abstract and just round-tripped through rustc; the compiler never attempts to
-interpret it in any way.
-
-There are two supported forms of location: a bare string, or a blob of json:
-- `--extern-location foo=raw:Makefile:123` would associate the raw string `Makefile:123`
-- `--extern-location 'bar=json:{"target":"//my_project:library","dep":"//common:serde"}` would
-  associate the json structure with `--extern bar=<path>`, indicating which dependency of
-  which rule introduced the unused extern crate.
-
-This primarily intended to be used with tooling - for example a linter which can automatically
-remove unused dependencies - rather than being directly presented to users.
-
-`raw` locations are presented as part of the normal rendered diagnostics and included in
-the json form. `json` locations are only included in the json form of diagnostics,
-as a `tool_metadata` field. For `raw` locations `tool_metadata` is simply a json string,
-whereas `json` allows the rustc invoker to fully control its form and content.
index df215f318239ec9e7120a0c58d83592704166cae..269b6868e29f9a9c4bed287ba3d28c9ba4058714 100644 (file)
@@ -423,8 +423,12 @@ def check_snapshot(snapshot_name, actual_tree, normalize_to_text):
     else:
         actual_str = flatten(actual_tree)
 
+    # Conditions:
+    #  1. Is --bless
+    #  2. Are actual and expected tree different
+    #  3. Are actual and expected text different
     if not expected_str \
-        or (not normalize_to_text and
+        or (not normalize_to_text and \
             not compare_tree(make_xml(actual_str), make_xml(expected_str), stderr)) \
         or (normalize_to_text and actual_str != expected_str):
 
index cc5c583bea8e25d81dda1b114b6e96a04dffeedf..21efd040663b8aa9e848aa6ff3456f1fa864fa89 100644 (file)
@@ -22,6 +22,7 @@ regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
 tracing = "0.1"
 tracing-tree = "0.2.0"
+once_cell = "1.10.0"
 
 [dependencies.tracing-subscriber]
 version = "0.3.3"
index 21016afbf5f99369e253d179dede250e40882a7d..a070cef227252b5b3bf25001bba3fc2ebd82f249 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::ty::fold::TypeFolder;
@@ -1975,7 +1975,7 @@ fn clean_extern_crate(
     // this is the ID of the `extern crate` statement
     let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
     // this is the ID of the crate itself
-    let crate_def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+    let crate_def_id = cnum.as_def_id();
     let attrs = cx.tcx.hir().attrs(krate.hir_id());
     let ty_vis = cx.tcx.visibility(krate.def_id);
     let please_inline = ty_vis.is_public()
@@ -2094,7 +2094,7 @@ fn clean_use_statement(
     } else {
         if inline_attr.is_none() {
             if let Res::Def(DefKind::Mod, did) = path.res {
-                if !did.is_local() && did.index == CRATE_DEF_INDEX {
+                if !did.is_local() && did.is_crate_root() {
                     // if we're `pub use`ing an extern crate root, don't inline it unless we
                     // were specifically asked for it
                     denied = true;
index 4b473df155f588c925defb7a20d5062ef77d00d4..2b65b8f910c7069b74c23d24c4847a5240898dc8 100644 (file)
@@ -1,13 +1,11 @@
 use std::cell::RefCell;
 use std::default::Default;
-use std::fmt;
 use std::hash::Hash;
-use std::iter;
 use std::lazy::SyncOnceCell as OnceCell;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
-use std::vec;
+use std::{cmp, fmt, iter};
 
 use arrayvec::ArrayVec;
 
@@ -20,7 +18,7 @@
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
 use rustc_index::vec::IndexVec;
@@ -55,6 +53,9 @@
 };
 crate use self::Visibility::{Inherited, Public};
 
+#[cfg(test)]
+mod tests;
+
 crate type ItemIdSet = FxHashSet<ItemId>;
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
@@ -104,14 +105,6 @@ impl ItemId {
             ItemId::Primitive(_, krate) => krate,
         }
     }
-
-    #[inline]
-    crate fn index(self) -> Option<DefIndex> {
-        match self {
-            ItemId::DefId(id) => Some(id.index),
-            _ => None,
-        }
-    }
 }
 
 impl From<DefId> for ItemId {
@@ -160,7 +153,7 @@ impl ExternalCrate {
 
     #[inline]
     crate fn def_id(&self) -> DefId {
-        DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
+        self.crate_num.as_def_id()
     }
 
     crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
@@ -217,7 +210,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
 
         // Failing that, see if there's an attribute specifying where to find this
         // external crate
-        let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
+        let did = self.crate_num.as_def_id();
         tcx.get_attrs(did)
             .lists(sym::doc)
             .filter(|a| a.has_name(sym::html_root_url))
@@ -559,7 +552,7 @@ impl Item {
     }
 
     crate fn is_crate(&self) -> bool {
-        self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
+        self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.is_crate_root())
     }
     crate fn is_mod(&self) -> bool {
         self.type_() == ItemType::Module
@@ -1036,6 +1029,86 @@ fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
     acc
 }
 
+/// Removes excess indentation on comments in order for the Markdown
+/// to be parsed correctly. This is necessary because the convention for
+/// writing documentation is to provide a space between the /// or //! marker
+/// and the doc text, but Markdown is whitespace-sensitive. For example,
+/// a block of text with four-space indentation is parsed as a code block,
+/// so if we didn't unindent comments, these list items
+///
+/// /// A list:
+/// ///
+/// ///    - Foo
+/// ///    - Bar
+///
+/// would be parsed as if they were in a code block, which is likely not what the user intended.
+fn unindent_doc_fragments(docs: &mut Vec<DocFragment>) {
+    // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
+    // fragments kind's lines are never starting with a whitespace unless they are using some
+    // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
+    // we need to take into account the fact that the minimum indent minus one (to take this
+    // whitespace into account).
+    //
+    // For example:
+    //
+    // /// hello!
+    // #[doc = "another"]
+    //
+    // In this case, you want "hello! another" and not "hello!  another".
+    let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
+        && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
+    {
+        // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
+        // "decide" how much the minimum indent will be.
+        1
+    } else {
+        0
+    };
+
+    // `min_indent` is used to know how much whitespaces from the start of each lines must be
+    // removed. Example:
+    //
+    // ///     hello!
+    // #[doc = "another"]
+    //
+    // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
+    // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
+    // (5 - 1) whitespaces.
+    let Some(min_indent) = docs
+        .iter()
+        .map(|fragment| {
+            fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
+                if line.chars().all(|c| c.is_whitespace()) {
+                    min_indent
+                } else {
+                    // Compare against either space or tab, ignoring whether they are
+                    // mixed or not.
+                    let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
+                    cmp::min(min_indent, whitespace)
+                        + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
+                }
+            })
+        })
+        .min()
+    else {
+        return;
+    };
+
+    for fragment in docs {
+        if fragment.doc == kw::Empty {
+            continue;
+        }
+
+        let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
+            min_indent - add
+        } else {
+            min_indent
+        };
+
+        fragment.indent = min_indent;
+    }
+}
+
 /// A link that has not yet been rendered.
 ///
 /// This link will be turned into a rendered link by [`Item::links`].
@@ -1097,35 +1170,37 @@ impl Attributes {
         attrs: &[ast::Attribute],
         additional_attrs: Option<(&[ast::Attribute], DefId)>,
     ) -> Attributes {
-        let mut doc_strings: Vec<DocFragment> = vec![];
-        let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
-            if let Some((value, kind)) = attr.doc_str_and_comment_kind() {
-                trace!("got doc_str={:?}", value);
-                let value = beautify_doc_string(value, kind);
+        // Additional documentation should be shown before the original documentation.
+        let attrs1 = additional_attrs
+            .into_iter()
+            .flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id))));
+        let attrs2 = attrs.iter().map(|attr| (attr, None));
+        Attributes::from_ast_iter(attrs1.chain(attrs2), false)
+    }
+
+    crate fn from_ast_iter<'a>(
+        attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>,
+        doc_only: bool,
+    ) -> Attributes {
+        let mut doc_strings = Vec::new();
+        let mut other_attrs = Vec::new();
+        for (attr, parent_module) in attrs {
+            if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
+                trace!("got doc_str={doc_str:?}");
+                let doc = beautify_doc_string(doc_str, comment_kind);
                 let kind = if attr.is_doc_comment() {
                     DocFragmentKind::SugaredDoc
                 } else {
                     DocFragmentKind::RawDoc
                 };
-
-                let frag =
-                    DocFragment { span: attr.span, doc: value, kind, parent_module, indent: 0 };
-
-                doc_strings.push(frag);
-
-                None
-            } else {
-                Some(attr.clone())
+                let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 };
+                doc_strings.push(fragment);
+            } else if !doc_only {
+                other_attrs.push(attr.clone());
             }
-        };
+        }
 
-        // Additional documentation should be shown before the original documentation
-        let other_attrs = additional_attrs
-            .into_iter()
-            .flat_map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
-            .chain(attrs.iter().map(|attr| (attr, None)))
-            .filter_map(clean_attr)
-            .collect();
+        unindent_doc_fragments(&mut doc_strings);
 
         Attributes { doc_strings, other_attrs }
     }
@@ -1146,23 +1221,17 @@ impl Attributes {
     }
 
     /// Return the doc-comments on this item, grouped by the module they came from.
-    ///
     /// The module can be different if this is a re-export with added documentation.
-    crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
-        let mut ret = FxHashMap::default();
-        if self.doc_strings.len() == 0 {
-            return ret;
-        }
-        let last_index = self.doc_strings.len() - 1;
-
-        for (i, new_frag) in self.doc_strings.iter().enumerate() {
-            let out = ret.entry(new_frag.parent_module).or_default();
-            add_doc_fragment(out, new_frag);
-            if i == last_index {
-                out.pop();
-            }
+    ///
+    /// The last newline is not trimmed so the produced strings are reusable between
+    /// early and late doc link resolution regardless of their position.
+    crate fn prepare_to_doc_link_resolution(&self) -> FxHashMap<Option<DefId>, String> {
+        let mut res = FxHashMap::default();
+        for fragment in &self.doc_strings {
+            let out_str = res.entry(fragment.parent_module).or_default();
+            add_doc_fragment(out_str, fragment);
         }
-        ret
+        res
     }
 
     /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs
new file mode 100644 (file)
index 0000000..71eddf4
--- /dev/null
@@ -0,0 +1,70 @@
+use super::*;
+
+use crate::clean::collapse_doc_fragments;
+
+use rustc_span::create_default_session_globals_then;
+use rustc_span::source_map::DUMMY_SP;
+use rustc_span::symbol::Symbol;
+
+fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
+    vec![DocFragment {
+        span: DUMMY_SP,
+        parent_module: None,
+        doc: Symbol::intern(s),
+        kind: DocFragmentKind::SugaredDoc,
+        indent: 0,
+    }]
+}
+
+#[track_caller]
+fn run_test(input: &str, expected: &str) {
+    create_default_session_globals_then(|| {
+        let mut s = create_doc_fragment(input);
+        unindent_doc_fragments(&mut s);
+        assert_eq!(collapse_doc_fragments(&s), expected);
+    });
+}
+
+#[test]
+fn should_unindent() {
+    run_test("    line1\n    line2", "line1\nline2");
+}
+
+#[test]
+fn should_unindent_multiple_paragraphs() {
+    run_test("    line1\n\n    line2", "line1\n\nline2");
+}
+
+#[test]
+fn should_leave_multiple_indent_levels() {
+    // Line 2 is indented another level beyond the
+    // base indentation and should be preserved
+    run_test("    line1\n\n        line2", "line1\n\n    line2");
+}
+
+#[test]
+fn should_ignore_first_line_indent() {
+    run_test("line1\n    line2", "line1\n    line2");
+}
+
+#[test]
+fn should_not_ignore_first_line_indent_in_a_single_line_para() {
+    run_test("line1\n\n    line2", "line1\n\n    line2");
+}
+
+#[test]
+fn should_unindent_tabs() {
+    run_test("\tline1\n\tline2", "line1\nline2");
+}
+
+#[test]
+fn should_trim_mixed_indentation() {
+    run_test("\t    line1\n\t    line2", "line1\nline2");
+    run_test("    \tline1\n    \tline2", "line1\nline2");
+}
+
+#[test]
+fn should_not_trim() {
+    run_test("\t    line1  \n\t    line2", "line1  \nline2");
+    run_test("    \tline1  \n    \tline2", "line1  \nline2");
+}
index b9e20c41b681fbcde73f99685551116dff064070..1db6064551cae362fc30911ba5528b00e052b1c7 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
-use rustc_hir::def::Res;
+use rustc_hir::def::{Namespace, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Path, TraitCandidate};
 use crate::clean::{self, ItemId, TraitWithExtraInfo};
 use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
 use crate::formats::cache::Cache;
+use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
 use crate::passes::{self, Condition::*};
 
 crate use rustc_session::config::{DebuggingOptions, Input, Options};
 
 crate struct ResolverCaches {
+    crate markdown_links: Option<FxHashMap<String, Vec<PreprocessedMarkdownLink>>>,
+    crate doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<NodeId>>>,
     /// Traits in scope for a given module.
     /// See `collect_intra_doc_links::traits_implemented_by` for more details.
     crate traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
index 618268445743acbb10d3959b33aafffbc3d8e832..45ac16e75aa37474e81be14ddbaf9068d06375cf 100644 (file)
@@ -1174,8 +1174,6 @@ fn visit_testable<F: FnOnce(&mut Self)>(
         nested: F,
     ) {
         let ast_attrs = self.tcx.hir().attrs(hir_id);
-        let mut attrs = Attributes::from_ast(ast_attrs, None);
-
         if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
             if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
                 return;
@@ -1187,9 +1185,9 @@ fn visit_testable<F: FnOnce(&mut Self)>(
             self.collector.names.push(name);
         }
 
-        attrs.unindent_doc_comments();
         // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
         // anything else, this will combine them for us.
+        let attrs = Attributes::from_ast(ast_attrs, None);
         if let Some(doc) = attrs.collapsed_doc_value() {
             // Use the outermost invocation, so that doctest names come from where the docs were written.
             let span = ast_attrs
index e138e434c4e04f72116b0bb1e9114fb9723cc6c5..b4d2772b31da2d2ea0c860d398157fa3b777f47a 100644 (file)
@@ -1,7 +1,7 @@
 use std::mem;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::{sym, Symbol};
 /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.
 struct CacheBuilder<'a, 'tcx> {
     cache: &'a mut Cache,
+    /// This field is used to prevent duplicated impl blocks.
+    impl_ids: FxHashMap<DefId, FxHashSet<DefId>>,
     tcx: TyCtxt<'tcx>,
 }
 
@@ -170,12 +172,19 @@ impl Cache {
                 .insert(def_id, (vec![crate_name, prim.as_sym()], ItemType::Primitive));
         }
 
-        krate = CacheBuilder { tcx, cache: &mut cx.cache }.fold_crate(krate);
+        let (krate, mut impl_ids) = {
+            let mut cache_builder =
+                CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: FxHashMap::default() };
+            krate = cache_builder.fold_crate(krate);
+            (krate, cache_builder.impl_ids)
+        };
 
         for (trait_did, dids, impl_) in cx.cache.orphan_trait_impls.drain(..) {
             if cx.cache.traits.contains_key(&trait_did) {
                 for did in dids {
-                    cx.cache.impls.entry(did).or_default().push(impl_.clone());
+                    if impl_ids.entry(did).or_default().insert(impl_.def_id()) {
+                        cx.cache.impls.entry(did).or_default().push(impl_.clone());
+                    }
                 }
             }
         }
@@ -293,7 +302,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                     // A crate has a module at its root, containing all items,
                     // which should not be indexed. The crate-item itself is
                     // inserted later on when serializing the search-index.
-                    if item.item_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
+                    if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root()) {
                         let desc = item.doc_value().map_or_else(String::new, |x| {
                             short_markdown_summary(x.as_str(), &item.link_names(self.cache))
                         });
@@ -467,7 +476,13 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             let impl_item = Impl { impl_item: item };
             if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
                 for did in dids {
-                    self.cache.impls.entry(did).or_insert_with(Vec::new).push(impl_item.clone());
+                    if self.impl_ids.entry(did).or_default().insert(impl_item.def_id()) {
+                        self.cache
+                            .impls
+                            .entry(did)
+                            .or_insert_with(Vec::new)
+                            .push(impl_item.clone());
+                    }
                 }
             } else {
                 let trait_did = impl_item.trait_did().expect("no trait did");
index 4f0c5a9edee7185581c71bd1846d0151105f015a..3e36318eb71b0cb65e225a65a2bb183a2092cd1c 100644 (file)
@@ -6,7 +6,7 @@
 
 crate use renderer::{run_format, FormatRenderer};
 
-use crate::clean;
+use crate::clean::{self, ItemId};
 
 /// Specifies whether rendering directly implemented trait items or ones from a certain Deref
 /// impl.
@@ -40,4 +40,24 @@ impl Impl {
     crate fn trait_did(&self) -> Option<DefId> {
         self.inner_impl().trait_.as_ref().map(|t| t.def_id())
     }
+
+    /// This function is used to extract a `DefId` to be used as a key for the `Cache::impls` field.
+    ///
+    /// It allows to prevent having duplicated implementations showing up (the biggest issue was
+    /// with blanket impls).
+    ///
+    /// It panics if `self` is a `ItemId::Primitive`.
+    crate fn def_id(&self) -> DefId {
+        match self.impl_item.item_id {
+            ItemId::Blanket { impl_id, .. } => impl_id,
+            ItemId::Auto { trait_, .. } => trait_,
+            ItemId::DefId(def_id) => def_id,
+            ItemId::Primitive(_, _) => {
+                panic!(
+                    "Unexpected ItemId::Primitive in expect_def_id: {:?}",
+                    self.impl_item.item_id
+                )
+            }
+        }
+    }
 }
index 55b0028180f66fece8164bb2f1c903a36154e7c4..d3545236e3dfe5a0d48cbc073e13b8d835a13f54 100644 (file)
@@ -18,7 +18,6 @@
 use rustc_middle::ty;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_span::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -268,6 +267,8 @@ impl clean::Generics {
     indent: usize,
     end_newline: bool,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
+    use fmt::Write;
+
     display_fn(move |f| {
         let mut where_predicates = gens.where_predicates.iter().filter(|pred| {
             !matches!(pred, clean::WherePredicate::BoundPredicate { bounds, .. } if bounds.is_empty())
@@ -281,56 +282,44 @@ impl clean::Generics {
 
                 match pred {
                     clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
-                        let bounds = bounds;
-                        let for_prefix = if bound_params.is_empty() {
-                            String::new()
-                        } else if f.alternate() {
-                            format!(
-                                "for&lt;{:#}&gt; ",
-                                comma_sep(bound_params.iter().map(|lt| lt.print()), true)
-                            )
-                        } else {
-                            format!(
-                                "for&lt;{}&gt; ",
-                                comma_sep(bound_params.iter().map(|lt| lt.print()), true)
-                            )
-                        };
+                        let ty_cx = ty.print(cx);
+                        let generic_bounds = print_generic_bounds(bounds, cx);
 
-                        if f.alternate() {
-                            write!(
-                                f,
-                                "{}{:#}: {:#}",
-                                for_prefix,
-                                ty.print(cx),
-                                print_generic_bounds(bounds, cx)
-                            )
+                        if bound_params.is_empty() {
+                            if f.alternate() {
+                                write!(f, "{ty_cx:#}: {generic_bounds:#}")
+                            } else {
+                                write!(f, "{ty_cx}: {generic_bounds}")
+                            }
                         } else {
-                            write!(
-                                f,
-                                "{}{}: {}",
-                                for_prefix,
-                                ty.print(cx),
-                                print_generic_bounds(bounds, cx)
-                            )
+                            if f.alternate() {
+                                write!(
+                                    f,
+                                    "for<{:#}> {ty_cx:#}: {generic_bounds:#}",
+                                    comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+                                )
+                            } else {
+                                write!(
+                                    f,
+                                    "for&lt;{}&gt; {ty_cx}: {generic_bounds}",
+                                    comma_sep(bound_params.iter().map(|lt| lt.print()), true)
+                                )
+                            }
                         }
                     }
                     clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
-                        write!(
-                            f,
-                            "{}: {}",
-                            lifetime.print(),
-                            bounds
-                                .iter()
-                                .map(|b| b.print(cx).to_string())
-                                .collect::<Vec<_>>()
-                                .join(" + ")
-                        )
+                        let mut bounds_display = String::new();
+                        for bound in bounds.iter().map(|b| b.print(cx)) {
+                            write!(bounds_display, "{bound} + ")?;
+                        }
+                        bounds_display.truncate(bounds_display.len() - " + ".len());
+                        write!(f, "{}: {bounds_display}", lifetime.print())
                     }
                     clean::WherePredicate::EqPredicate { lhs, rhs } => {
                         if f.alternate() {
-                            write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx),)
+                            write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
                         } else {
-                            write!(f, "{} == {}", lhs.print(cx), rhs.print(cx),)
+                            write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
                         }
                     }
                 }
@@ -341,40 +330,43 @@ impl clean::Generics {
             return Ok(());
         }
 
-        let mut clause = String::new();
-
-        if f.alternate() {
-            clause.push_str(" where");
-        } else {
+        let where_preds = comma_sep(where_predicates, false);
+        let clause = if f.alternate() {
             if end_newline {
-                clause.push_str(" <span class=\"where fmt-newline\">where");
+                // add a space so stripping <br> tags and breaking spaces still renders properly
+                format!(" where{where_preds}, ")
             } else {
-                clause.push_str(" <span class=\"where\">where");
+                format!(" where{where_preds}")
             }
-        }
-
-        clause.push_str(&comma_sep(where_predicates, false).to_string());
-
-        if end_newline {
-            clause.push(',');
-            // add a space so stripping <br> tags and breaking spaces still renders properly
-            if f.alternate() {
-                clause.push(' ');
-            } else {
-                clause.push_str("&nbsp;");
+        } else {
+            let mut br_with_padding = String::with_capacity(6 * indent + 28);
+            br_with_padding.push_str("<br>");
+            for _ in 0..indent + 4 {
+                br_with_padding.push_str("&nbsp;");
             }
-        }
+            let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
 
-        if !f.alternate() {
-            clause.push_str("</span>");
-            let padding = "&nbsp;".repeat(indent + 4);
-            clause = clause.replace("<br>", &format!("<br>{}", padding));
-            clause.insert_str(0, &"&nbsp;".repeat(indent.saturating_sub(1)));
-            if !end_newline {
-                clause.insert_str(0, "<br>");
+            if end_newline {
+                let mut clause = "&nbsp;".repeat(indent.saturating_sub(1));
+                // add a space so stripping <br> tags and breaking spaces still renders properly
+                write!(
+                    clause,
+                    " <span class=\"where fmt-newline\">where{where_preds},&nbsp;</span>"
+                )?;
+                clause
+            } else {
+                // insert a <br> tag after a single space but before multiple spaces at the start
+                if indent == 0 {
+                    format!(" <br><span class=\"where\">where{where_preds}</span>")
+                } else {
+                    let mut clause = br_with_padding;
+                    clause.truncate(clause.len() - 5 * "&nbsp;".len());
+                    write!(clause, " <span class=\"where\">where{where_preds}</span>")?;
+                    clause
+                }
             }
-        }
-        write!(f, "{}", clause)
+        };
+        write!(f, "{clause}")
     })
 }
 
@@ -1312,7 +1304,7 @@ impl clean::Visibility {
                 //                 visibility, so it shouldn't matter.
                 let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
 
-                if vis_did.index == CRATE_DEF_INDEX {
+                if vis_did.is_crate_root() {
                     "pub(crate) ".to_owned()
                 } else if parent_module == Some(vis_did) {
                     // `pub(in foo)` where `foo` is the parent module
@@ -1360,7 +1352,7 @@ impl clean::Visibility {
                 //                 visibility, so it shouldn't matter.
                 let parent_module = find_nearest_parent_module(tcx, item_did);
 
-                if vis_did.index == CRATE_DEF_INDEX {
+                if vis_did.is_crate_root() {
                     "pub(crate) ".to_owned()
                 } else if parent_module == Some(vis_did) {
                     // `pub(in foo)` where `foo` is the parent module
index 1ebb41b5933d0b0350165494ce61bbe4198cd7d9..9e76af982985416563472f544b8f21c13c89e443 100644 (file)
@@ -32,6 +32,7 @@
 use rustc_span::edition::Edition;
 use rustc_span::Span;
 
+use once_cell::sync::Lazy;
 use std::borrow::Cow;
 use std::cell::RefCell;
 use std::collections::VecDeque;
@@ -1255,7 +1256,7 @@ fn markdown_summary_with_limit(
     pub range: Range<usize>,
 }
 
-crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
+crate fn markdown_links<R>(md: &str, filter_map: impl Fn(MarkdownLink) -> Option<R>) -> Vec<R> {
     if md.is_empty() {
         return vec![];
     }
@@ -1295,11 +1296,12 @@ fn markdown_summary_with_limit(
 
     let mut push = |link: BrokenLink<'_>| {
         let span = span_for_link(&link.reference, link.span);
-        links.borrow_mut().push(MarkdownLink {
+        filter_map(MarkdownLink {
             kind: LinkType::ShortcutUnknown,
             link: link.reference.to_string(),
             range: span,
-        });
+        })
+        .map(|link| links.borrow_mut().push(link));
         None
     };
     let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push))
@@ -1311,10 +1313,23 @@ fn markdown_summary_with_limit(
     let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1));
 
     for ev in iter {
-        if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {
+        if let Event::Start(Tag::Link(
+            // `<>` links cannot be intra-doc links so we skip them.
+            kind @ (LinkType::Inline
+            | LinkType::Reference
+            | LinkType::ReferenceUnknown
+            | LinkType::Collapsed
+            | LinkType::CollapsedUnknown
+            | LinkType::Shortcut
+            | LinkType::ShortcutUnknown),
+            dest,
+            _,
+        )) = ev.0
+        {
             debug!("found link: {dest}");
             let span = span_for_link(&dest, ev.1);
-            links.borrow_mut().push(MarkdownLink { kind, link: dest.into_string(), range: span });
+            filter_map(MarkdownLink { kind, link: dest.into_string(), range: span })
+                .map(|link| links.borrow_mut().push(link));
         }
     }
 
@@ -1415,62 +1430,65 @@ fn markdown_summary_with_limit(
 
 #[derive(Clone, Default, Debug)]
 pub struct IdMap {
-    map: FxHashMap<String, usize>,
+    map: FxHashMap<Cow<'static, str>, usize>,
 }
 
-fn init_id_map() -> FxHashMap<String, usize> {
+// The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly.
+static DEFAULT_ID_MAP: Lazy<FxHashMap<Cow<'static, str>, usize>> = Lazy::new(|| init_id_map());
+
+fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     let mut map = FxHashMap::default();
     // This is the list of IDs used in Javascript.
-    map.insert("help".to_owned(), 1);
+    map.insert("help".into(), 1);
     // This is the list of IDs used in HTML generated in Rust (including the ones
     // used in tera template files).
-    map.insert("mainThemeStyle".to_owned(), 1);
-    map.insert("themeStyle".to_owned(), 1);
-    map.insert("theme-picker".to_owned(), 1);
-    map.insert("theme-choices".to_owned(), 1);
-    map.insert("settings-menu".to_owned(), 1);
-    map.insert("help-button".to_owned(), 1);
-    map.insert("main-content".to_owned(), 1);
-    map.insert("search".to_owned(), 1);
-    map.insert("crate-search".to_owned(), 1);
-    map.insert("render-detail".to_owned(), 1);
-    map.insert("toggle-all-docs".to_owned(), 1);
-    map.insert("all-types".to_owned(), 1);
-    map.insert("default-settings".to_owned(), 1);
-    map.insert("rustdoc-vars".to_owned(), 1);
-    map.insert("sidebar-vars".to_owned(), 1);
-    map.insert("copy-path".to_owned(), 1);
-    map.insert("TOC".to_owned(), 1);
+    map.insert("mainThemeStyle".into(), 1);
+    map.insert("themeStyle".into(), 1);
+    map.insert("theme-picker".into(), 1);
+    map.insert("theme-choices".into(), 1);
+    map.insert("settings-menu".into(), 1);
+    map.insert("help-button".into(), 1);
+    map.insert("main-content".into(), 1);
+    map.insert("search".into(), 1);
+    map.insert("crate-search".into(), 1);
+    map.insert("render-detail".into(), 1);
+    map.insert("toggle-all-docs".into(), 1);
+    map.insert("all-types".into(), 1);
+    map.insert("default-settings".into(), 1);
+    map.insert("rustdoc-vars".into(), 1);
+    map.insert("sidebar-vars".into(), 1);
+    map.insert("copy-path".into(), 1);
+    map.insert("TOC".into(), 1);
     // This is the list of IDs used by rustdoc sections (but still generated by
     // rustdoc).
-    map.insert("fields".to_owned(), 1);
-    map.insert("variants".to_owned(), 1);
-    map.insert("implementors-list".to_owned(), 1);
-    map.insert("synthetic-implementors-list".to_owned(), 1);
-    map.insert("foreign-impls".to_owned(), 1);
-    map.insert("implementations".to_owned(), 1);
-    map.insert("trait-implementations".to_owned(), 1);
-    map.insert("synthetic-implementations".to_owned(), 1);
-    map.insert("blanket-implementations".to_owned(), 1);
-    map.insert("required-associated-types".to_owned(), 1);
-    map.insert("provided-associated-types".to_owned(), 1);
-    map.insert("provided-associated-consts".to_owned(), 1);
-    map.insert("required-associated-consts".to_owned(), 1);
-    map.insert("required-methods".to_owned(), 1);
-    map.insert("provided-methods".to_owned(), 1);
-    map.insert("implementors".to_owned(), 1);
-    map.insert("synthetic-implementors".to_owned(), 1);
-    map.insert("implementations-list".to_owned(), 1);
-    map.insert("trait-implementations-list".to_owned(), 1);
-    map.insert("synthetic-implementations-list".to_owned(), 1);
-    map.insert("blanket-implementations-list".to_owned(), 1);
-    map.insert("deref-methods".to_owned(), 1);
+    map.insert("fields".into(), 1);
+    map.insert("variants".into(), 1);
+    map.insert("implementors-list".into(), 1);
+    map.insert("synthetic-implementors-list".into(), 1);
+    map.insert("foreign-impls".into(), 1);
+    map.insert("implementations".into(), 1);
+    map.insert("trait-implementations".into(), 1);
+    map.insert("synthetic-implementations".into(), 1);
+    map.insert("blanket-implementations".into(), 1);
+    map.insert("required-associated-types".into(), 1);
+    map.insert("provided-associated-types".into(), 1);
+    map.insert("provided-associated-consts".into(), 1);
+    map.insert("required-associated-consts".into(), 1);
+    map.insert("required-methods".into(), 1);
+    map.insert("provided-methods".into(), 1);
+    map.insert("implementors".into(), 1);
+    map.insert("synthetic-implementors".into(), 1);
+    map.insert("implementations-list".into(), 1);
+    map.insert("trait-implementations-list".into(), 1);
+    map.insert("synthetic-implementations-list".into(), 1);
+    map.insert("blanket-implementations-list".into(), 1);
+    map.insert("deref-methods".into(), 1);
     map
 }
 
 impl IdMap {
     pub fn new() -> Self {
-        IdMap { map: init_id_map() }
+        IdMap { map: DEFAULT_ID_MAP.clone() }
     }
 
     crate fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
@@ -1483,7 +1501,7 @@ pub fn new() -> Self {
             }
         };
 
-        self.map.insert(id.clone(), 1);
+        self.map.insert(id.clone().into(), 1);
         id
     }
 }
index 629f90728d2f61cfaa952de308a3c613079a31af..0fe0fdadbd21050b3c27aa51331e81797a5a74b5 100644 (file)
@@ -8,10 +8,34 @@ function initSearch(searchIndex){}
 
 /**
  * @typedef {{
- *   raw: string,
- *   query: string,
- *   type: string,
- *   id: string,
+ *     name: string,
+ *     fullPath: Array<string>,
+ *     pathWithoutLast: Array<string>,
+ *     pathLast: string,
+ *     generics: Array<QueryElement>,
+ * }}
+ */
+var QueryElement;
+
+/**
+ * @typedef {{
+ *      pos: number,
+ *      totalElems: number,
+ *      typeFilter: (null|string),
+ *      userQuery: string,
+ * }}
+ */
+var ParserState;
+
+/**
+ * @typedef {{
+ *     original: string,
+ *     userQuery: string,
+ *     typeFilter: number,
+ *     elems: Array<QueryElement>,
+ *     args: Array<QueryElement>,
+ *     returned: Array<QueryElement>,
+ *     foundElems: number,
  * }}
  */
 var ParsedQuery;
@@ -30,3 +54,30 @@ var ParsedQuery;
  * }}
  */
 var Row;
+
+/**
+ * @typedef {{
+ *    in_args: Array<Object>,
+ *    returned: Array<Object>,
+ *    others: Array<Object>,
+ *    query: ParsedQuery,
+ * }}
+ */
+var ResultsTable;
+
+/**
+ * @typedef {{
+ *     desc: string,
+ *     displayPath: string,
+ *     fullPath: string,
+ *     href: string,
+ *     id: number,
+ *     lev: number,
+ *     name: string,
+ *     normalizedName: string,
+ *     parent: (Object|undefined),
+ *     path: string,
+ *     ty: number,
+ * }}
+ */
+var Results;
index ab52304491a2bc17841d3515f9227f9c916a57a2..0d4e0a0b3289dac7f763875b074733448725459c 100644 (file)
@@ -61,15 +61,6 @@ function printTab(nb) {
     });
 }
 
-function removeEmptyStringsFromArray(x) {
-    for (var i = 0, len = x.length; i < len; ++i) {
-        if (x[i] === "") {
-            x.splice(i, 1);
-            i -= 1;
-        }
-    }
-}
-
 /**
  * A function to compute the Levenshtein distance between two strings
  * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
@@ -133,11 +124,436 @@ window.initSearch = function(rawSearchIndex) {
         searchState.input.value = params.search || "";
     }
 
+    function isWhitespace(c) {
+        return " \t\n\r".indexOf(c) !== -1;
+    }
+
+    function isSpecialStartCharacter(c) {
+        return "<\"".indexOf(c) !== -1;
+    }
+
+    function isEndCharacter(c) {
+        return ",>-".indexOf(c) !== -1;
+    }
+
+    function isStopCharacter(c) {
+        return isWhitespace(c) || isEndCharacter(c);
+    }
+
+    function isErrorCharacter(c) {
+        return "()".indexOf(c) !== -1;
+    }
+
+    function itemTypeFromName(typename) {
+        for (var i = 0, len = itemTypes.length; i < len; ++i) {
+            if (itemTypes[i] === typename) {
+                return i;
+            }
+        }
+
+        throw new Error("Unknown type filter `" + typename + "`");
+    }
+
+    /**
+     * If we encounter a `"`, then we try to extract the string from it until we find another `"`.
+     *
+     * This function will throw an error in the following cases:
+     * * There is already another string element.
+     * * We are parsing a generic argument.
+     * * There is more than one element.
+     * * There is no closing `"`.
+     *
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {boolean} isInGenerics
+     */
+    function getStringElem(query, parserState, isInGenerics) {
+        if (isInGenerics) {
+            throw new Error("`\"` cannot be used in generics");
+        } else if (query.literalSearch) {
+            throw new Error("Cannot have more than one literal search element");
+        } else if (parserState.totalElems - parserState.genericsElems > 0) {
+            throw new Error("Cannot use literal search when there is more than one element");
+        }
+        parserState.pos += 1;
+        var start = parserState.pos;
+        var end = getIdentEndPosition(parserState);
+        if (parserState.pos >= parserState.length) {
+            throw new Error("Unclosed `\"`");
+        } else if (parserState.userQuery[end] !== "\"") {
+            throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`);
+        } else if (start === end) {
+            throw new Error("Cannot have empty string element");
+        }
+        // To skip the quote at the end.
+        parserState.pos += 1;
+        query.literalSearch = true;
+    }
+
+    /**
+     * Returns `true` if the current parser position is starting with "::".
+     *
+     * @param {ParserState} parserState
+     *
+     * @return {boolean}
+     */
+    function isPathStart(parserState) {
+        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
+    }
+
+    /**
+     * Returns `true` if the current parser position is starting with "->".
+     *
+     * @param {ParserState} parserState
+     *
+     * @return {boolean}
+     */
+    function isReturnArrow(parserState) {
+        return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
+    }
+
+    /**
+     * Returns `true` if the given `c` character is valid for an ident.
+     *
+     * @param {string} c
+     *
+     * @return {boolean}
+     */
+    function isIdentCharacter(c) {
+        return (
+            c === '_' ||
+            (c >= '0' && c <= '9') ||
+            (c >= 'a' && c <= 'z') ||
+            (c >= 'A' && c <= 'Z'));
+    }
+
+    /**
+     * Returns `true` if the given `c` character is a separator.
+     *
+     * @param {string} c
+     *
+     * @return {boolean}
+     */
+    function isSeparatorCharacter(c) {
+        return c === "," || isWhitespaceCharacter(c);
+    }
+
+    /**
+     * Returns `true` if the given `c` character is a whitespace.
+     *
+     * @param {string} c
+     *
+     * @return {boolean}
+     */
+    function isWhitespaceCharacter(c) {
+        return c === " " || c === "\t";
+    }
+
+    /**
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {string} name                  - Name of the query element.
+     * @param {Array<QueryElement>} generics - List of generics of this query element.
+     *
+     * @return {QueryElement}                - The newly created `QueryElement`.
+     */
+    function createQueryElement(query, parserState, name, generics, isInGenerics) {
+        if (name === '*' || (name.length === 0 && generics.length === 0)) {
+            return;
+        }
+        if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
+            throw new Error("You cannot have more than one element if you use quotes");
+        }
+        var pathSegments = name.split("::");
+        if (pathSegments.length > 1) {
+            for (var i = 0, len = pathSegments.length; i < len; ++i) {
+                var pathSegment = pathSegments[i];
+
+                if (pathSegment.length === 0) {
+                    if (i === 0) {
+                        throw new Error("Paths cannot start with `::`");
+                    } else if (i + 1 === len) {
+                        throw new Error("Paths cannot end with `::`");
+                    }
+                    throw new Error("Unexpected `::::`");
+                }
+            }
+        }
+        // In case we only have something like `<p>`, there is no name.
+        if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) {
+            throw new Error("Found generics without a path");
+        }
+        parserState.totalElems += 1;
+        if (isInGenerics) {
+            parserState.genericsElems += 1;
+        }
+        return {
+            name: name,
+            fullPath: pathSegments,
+            pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
+            pathLast: pathSegments[pathSegments.length - 1],
+            generics: generics,
+        };
+    }
+
+    /**
+     * This function goes through all characters until it reaches an invalid ident character or the
+     * end of the query. It returns the position of the last character of the ident.
+     *
+     * @param {ParserState} parserState
+     *
+     * @return {integer}
+     */
+    function getIdentEndPosition(parserState) {
+        var end = parserState.pos;
+        while (parserState.pos < parserState.length) {
+            var c = parserState.userQuery[parserState.pos];
+            if (!isIdentCharacter(c)) {
+                if (isErrorCharacter(c)) {
+                    throw new Error(`Unexpected \`${c}\``);
+                } else if (
+                    isStopCharacter(c) ||
+                    isSpecialStartCharacter(c) ||
+                    isSeparatorCharacter(c))
+                {
+                    break;
+                }
+                // If we allow paths ("str::string" for example).
+                else if (c === ":") {
+                    if (!isPathStart(parserState)) {
+                        break;
+                    }
+                    // Skip current ":".
+                    parserState.pos += 1;
+                } else {
+                    throw new Error(`Unexpected \`${c}\``);
+                }
+            }
+            parserState.pos += 1;
+            end = parserState.pos;
+        }
+        return end;
+    }
+
+    /**
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+     * @param {boolean} isInGenerics
+     */
+    function getNextElem(query, parserState, elems, isInGenerics) {
+        var generics = [];
+
+        var start = parserState.pos;
+        var end;
+        // We handle the strings on their own mostly to make code easier to follow.
+        if (parserState.userQuery[parserState.pos] === "\"") {
+            start += 1;
+            getStringElem(query, parserState, isInGenerics);
+            end = parserState.pos - 1;
+        } else {
+            end = getIdentEndPosition(parserState);
+        }
+        if (parserState.pos < parserState.length &&
+            parserState.userQuery[parserState.pos] === "<")
+        {
+            if (isInGenerics) {
+                throw new Error("Unexpected `<` after `<`");
+            } else if (start >= end) {
+                throw new Error("Found generics without a path");
+            }
+            parserState.pos += 1;
+            getItemsBefore(query, parserState, generics, ">");
+        }
+        if (start >= end && generics.length === 0) {
+            return;
+        }
+        elems.push(
+            createQueryElement(
+                query,
+                parserState,
+                parserState.userQuery.slice(start, end),
+                generics,
+                isInGenerics
+            )
+        );
+    }
+
+    /**
+     * This function parses the next query element until it finds `endChar`, calling `getNextElem`
+     * to collect each element.
+     *
+     * If there is no `endChar`, this function will implicitly stop at the end without raising an
+     * error.
+     *
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+     * @param {string} endChar            - This function will stop when it'll encounter this
+     *                                      character.
+     */
+    function getItemsBefore(query, parserState, elems, endChar) {
+        var foundStopChar = true;
+
+        while (parserState.pos < parserState.length) {
+            var c = parserState.userQuery[parserState.pos];
+            if (c === endChar) {
+                break;
+            } else if (isSeparatorCharacter(c)) {
+                parserState.pos += 1;
+                foundStopChar = true;
+                continue;
+            } else if (c === ":" && isPathStart(parserState)) {
+                throw new Error("Unexpected `::`: paths cannot start with `::`");
+            } else if (c === ":" || isEndCharacter(c)) {
+                var extra = "";
+                if (endChar === ">") {
+                    extra = "`<`";
+                } else if (endChar === "") {
+                    extra = "`->`";
+                }
+                throw new Error("Unexpected `" + c + "` after " + extra);
+            }
+            if (!foundStopChar) {
+                if (endChar !== "") {
+                    throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
+                }
+                throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
+            }
+            var posBefore = parserState.pos;
+            getNextElem(query, parserState, elems, endChar === ">");
+            // This case can be encountered if `getNextElem` encounted a "stop character" right from
+            // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
+            // current position to continue the parsing.
+            if (posBefore === parserState.pos) {
+                parserState.pos += 1;
+            }
+            foundStopChar = false;
+        }
+        // We are either at the end of the string or on the `endChar`` character, let's move forward
+        // in any case.
+        parserState.pos += 1;
+    }
+
+    /**
+     * Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
+     * if empty).
+     *
+     * @param {ParserState} parserState
+     */
+    function checkExtraTypeFilterCharacters(parserState) {
+        var query = parserState.userQuery;
+
+        for (var pos = 0; pos < parserState.pos; ++pos) {
+            if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
+                throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
+            }
+        }
+    }
+
+    /**
+     * Parses the provided `query` input to fill `parserState`. If it encounters an error while
+     * parsing `query`, it'll throw an error.
+     *
+     * @param {ParsedQuery} query
+     * @param {ParserState} parserState
+     */
+    function parseInput(query, parserState) {
+        var c, before;
+        var foundStopChar = true;
+
+        while (parserState.pos < parserState.length) {
+            c = parserState.userQuery[parserState.pos];
+            if (isStopCharacter(c)) {
+                foundStopChar = true;
+                if (isSeparatorCharacter(c)) {
+                    parserState.pos += 1;
+                    continue;
+                } else if (c === "-" || c === ">") {
+                    if (isReturnArrow(parserState)) {
+                        break;
+                    }
+                    throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
+                }
+                throw new Error(`Unexpected \`${c}\``);
+            } else if (c === ":" && !isPathStart(parserState)) {
+                if (parserState.typeFilter !== null) {
+                    throw new Error("Unexpected `:`");
+                }
+                if (query.elems.length === 0) {
+                    throw new Error("Expected type filter before `:`");
+                } else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
+                    throw new Error("Unexpected `:`");
+                } else if (query.literalSearch) {
+                    throw new Error("You cannot use quotes on type filter");
+                }
+                checkExtraTypeFilterCharacters(parserState);
+                // The type filter doesn't count as an element since it's a modifier.
+                parserState.typeFilter = query.elems.pop().name;
+                parserState.pos += 1;
+                parserState.totalElems = 0;
+                query.literalSearch = false;
+                foundStopChar = true;
+                continue;
+            }
+            if (!foundStopChar) {
+                if (parserState.typeFilter !== null) {
+                    throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
+                }
+                throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
+            }
+            before = query.elems.length;
+            getNextElem(query, parserState, query.elems, false);
+            if (query.elems.length === before) {
+                // Nothing was added, weird... Let's increase the position to not remain stuck.
+                parserState.pos += 1;
+            }
+            foundStopChar = false;
+        }
+        while (parserState.pos < parserState.length) {
+            c = parserState.userQuery[parserState.pos];
+            if (isReturnArrow(parserState)) {
+                parserState.pos += 2;
+                // Get returned elements.
+                getItemsBefore(query, parserState, query.returned, "");
+                // Nothing can come afterward!
+                if (query.returned.length === 0) {
+                    throw new Error("Expected at least one item after `->`");
+                }
+                break;
+            } else {
+                parserState.pos += 1;
+            }
+        }
+    }
+
+    /**
+     * Takes the user search input and returns an empty `ParsedQuery`.
+     *
+     * @param {string} userQuery
+     *
+     * @return {ParsedQuery}
+     */
+    function newParsedQuery(userQuery) {
+        return {
+            original: userQuery,
+            userQuery: userQuery.toLowerCase(),
+            typeFilter: NO_TYPE_FILTER,
+            elems: [],
+            returned: [],
+            // Total number of "top" elements (does not include generics).
+            foundElems: 0,
+            literalSearch: false,
+            error: null,
+        };
+    }
+
     /**
      * Build an URL with search parameters.
      *
      * @param {string} search            - The current search being performed.
      * @param {string|null} filterCrates - The current filtering crate (if any).
+     *
      * @return {string}
      */
     function buildUrl(search, filterCrates) {
@@ -167,33 +583,139 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     /**
-     * Executes the query and returns a list of results for each results tab.
-     * @param  {Object}        query          - The user query
-     * @param  {Array<string>} searchWords    - The list of search words to query against
-     * @param  {string}        [filterCrates] - Crate to search in
-     * @return {{
-     *   in_args: Array<?>,
-     *   returned: Array<?>,
-     *   others: Array<?>
-     * }}
+     * Parses the query.
+     *
+     * The supported syntax by this parser is as follow:
+     *
+     * ident = *(ALPHA / DIGIT / "_")
+     * path = ident *(DOUBLE-COLON ident)
+     * arg = path [generics]
+     * arg-without-generic = path
+     * type-sep = COMMA/WS *(COMMA/WS)
+     * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
+     * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
+     *                                      *(type-sep arg-without-generic) *(type-sep)
+     * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
+     *            CLOSE-ANGLE-BRACKET/EOF
+     * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
+     *
+     * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
+     * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
+     *
+     * query = *WS (exact-search / type-search) *WS
+     *
+     * type-filter = (
+     *     "mod" /
+     *     "externcrate" /
+     *     "import" /
+     *     "struct" /
+     *     "enum" /
+     *     "fn" /
+     *     "type" /
+     *     "static" /
+     *     "trait" /
+     *     "impl" /
+     *     "tymethod" /
+     *     "method" /
+     *     "structfield" /
+     *     "variant" /
+     *     "macro" /
+     *     "primitive" /
+     *     "associatedtype" /
+     *     "constant" /
+     *     "associatedconstant" /
+     *     "union" /
+     *     "foreigntype" /
+     *     "keyword" /
+     *     "existential" /
+     *     "attr" /
+     *     "derive" /
+     *     "traitalias")
+     *
+     * OPEN-ANGLE-BRACKET = "<"
+     * CLOSE-ANGLE-BRACKET = ">"
+     * COLON = ":"
+     * DOUBLE-COLON = "::"
+     * QUOTE = %x22
+     * COMMA = ","
+     * RETURN-ARROW = "->"
+     *
+     * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+     * DIGIT = %x30-39
+     * WS = %x09 / " "
+     *
+     * @param  {string} val     - The user query
+     *
+     * @return {ParsedQuery}    - The parsed query
      */
-    function execQuery(query, searchWords, filterCrates) {
-        function itemTypeFromName(typename) {
-            for (var i = 0, len = itemTypes.length; i < len; ++i) {
-                if (itemTypes[i] === typename) {
-                    return i;
+    function parseQuery(userQuery) {
+        userQuery = userQuery.trim();
+        var parserState = {
+            length: userQuery.length,
+            pos: 0,
+            // Total number of elements (includes generics).
+            totalElems: 0,
+            genericsElems: 0,
+            typeFilter: null,
+            userQuery: userQuery.toLowerCase(),
+        };
+        var query = newParsedQuery(userQuery);
+
+        try {
+            parseInput(query, parserState);
+            if (parserState.typeFilter !== null) {
+                var typeFilter = parserState.typeFilter;
+                if (typeFilter === "const") {
+                    typeFilter = "constant";
                 }
+                query.typeFilter = itemTypeFromName(typeFilter);
             }
-            return NO_TYPE_FILTER;
+        } catch (err) {
+            query = newParsedQuery(userQuery);
+            query.error = err.message;
+            query.typeFilter = -1;
+            return query;
         }
 
-        var valLower = query.query.toLowerCase(),
-            val = valLower,
-            typeFilter = itemTypeFromName(query.type),
-            results = {}, results_in_args = {}, results_returned = {},
-            split = valLower.split("::");
+        if (!query.literalSearch) {
+            // If there is more than one element in the query, we switch to literalSearch in any
+            // case.
+            query.literalSearch = parserState.totalElems > 1;
+        }
+        query.foundElems = query.elems.length + query.returned.length;
+        return query;
+    }
 
-        removeEmptyStringsFromArray(split);
+    /**
+     * Creates the query results.
+     *
+     * @param {Array<Result>} results_in_args
+     * @param {Array<Result>} results_returned
+     * @param {Array<Result>} results_in_args
+     * @param {ParsedQuery} parsedQuery
+     *
+     * @return {ResultsTable}
+     */
+    function createQueryResults(results_in_args, results_returned, results_others, parsedQuery) {
+        return {
+            "in_args": results_in_args,
+            "returned": results_returned,
+            "others": results_others,
+            "query": parsedQuery,
+        };
+    }
+
+    /**
+     * Executes the parsed query and builds a {ResultsTable}.
+     *
+     * @param  {ParsedQuery} parsedQuery - The parsed user query
+     * @param  {Object} searchWords      - The list of search words to query against
+     * @param  {Object} [filterCrates]   - Crate to search in if defined
+     *
+     * @return {ResultsTable}
+     */
+    function execQuery(parsedQuery, searchWords, filterCrates) {
+        var results_others = {}, results_in_args = {}, results_returned = {};
 
         function transformResults(results) {
             var duplicates = {};
@@ -227,6 +749,7 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function sortResults(results, isType) {
+            var userQuery = parsedQuery.userQuery;
             var ar = [];
             for (var entry in results) {
                 if (hasOwnPropertyRustdoc(results, entry)) {
@@ -246,8 +769,8 @@ window.initSearch = function(rawSearchIndex) {
                 var a, b;
 
                 // sort by exact match with regard to the last word (mismatch goes later)
-                a = (aaa.word !== val);
-                b = (bbb.word !== val);
+                a = (aaa.word !== userQuery);
+                b = (bbb.word !== userQuery);
                 if (a !== b) { return a - b; }
 
                 // Sort by non levenshtein results and then levenshtein results by the distance
@@ -309,6 +832,12 @@ window.initSearch = function(rawSearchIndex) {
                 return 0;
             });
 
+            var nameSplit = null;
+            if (parsedQuery.elems.length === 1) {
+                var hasPath = typeof parsedQuery.elems[0].path === "undefined";
+                nameSplit = hasPath ? null : parsedQuery.elems[0].path;
+            }
+
             for (var i = 0, len = results.length; i < len; ++i) {
                 result = results[i];
 
@@ -320,215 +849,222 @@ window.initSearch = function(rawSearchIndex) {
                     path = result.item.path.toLowerCase(),
                     parent = result.item.parent;
 
-                if (!isType && !validateResult(name, path, split, parent)) {
+                if (!isType && !validateResult(name, path, nameSplit, parent)) {
                     result.id = -1;
                 }
             }
             return transformResults(results);
         }
 
-        function extractGenerics(val) {
-            val = val.toLowerCase();
-            if (val.indexOf("<") !== -1) {
-                var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
-                return {
-                    name: val.substring(0, val.indexOf("<")),
-                    generics: values.split(/\s*,\s*/),
-                };
+        /**
+         * This function checks if the object (`row`) generics match the given type (`elem`)
+         * generics. If there are no generics on `row`, `defaultLev` is returned.
+         *
+         * @param {Row} row            - The object to check.
+         * @param {QueryElement} elem  - The element from the parsed query.
+         * @param {integer} defaultLev - This is the value to return in case there are no generics.
+         *
+         * @return {integer}           - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
+         */
+        function checkGenerics(row, elem, defaultLev) {
+            if (row.length <= GENERICS_DATA || row[GENERICS_DATA].length === 0) {
+                return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
+            } else if (row[GENERICS_DATA].length > 0 && row[GENERICS_DATA][0][NAME] === "") {
+                if (row.length > GENERICS_DATA) {
+                    return checkGenerics(row[GENERICS_DATA][0], elem, defaultLev);
+                }
+                return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
             }
-            return {
-                name: val,
-                generics: [],
-            };
-        }
-
-        function checkGenerics(obj, val) {
             // The names match, but we need to be sure that all generics kinda
             // match as well.
-            var tmp_lev, elem_name;
-            if (val.generics.length > 0) {
-                if (obj.length > GENERICS_DATA &&
-                      obj[GENERICS_DATA].length >= val.generics.length) {
-                    var elems = Object.create(null);
-                    var elength = obj[GENERICS_DATA].length;
-                    for (var x = 0; x < elength; ++x) {
-                        if (!elems[obj[GENERICS_DATA][x][NAME]]) {
-                            elems[obj[GENERICS_DATA][x][NAME]] = 0;
+            var elem_name;
+            if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
+                var elems = Object.create(null);
+                for (var x = 0, length = row[GENERICS_DATA].length; x < length; ++x) {
+                    elem_name = row[GENERICS_DATA][x][NAME];
+                    if (elem_name === "") {
+                        // Pure generic, needs to check into it.
+                        if (checkGenerics(
+                                row[GENERICS_DATA][x], elem, MAX_LEV_DISTANCE + 1) !== 0) {
+                            return MAX_LEV_DISTANCE + 1;
                         }
-                        elems[obj[GENERICS_DATA][x][NAME]] += 1;
+                        continue;
+                    }
+                    if (elems[elem_name] === undefined) {
+                        elems[elem_name] = 0;
                     }
-                    var total = 0;
-                    var done = 0;
-                    // We need to find the type that matches the most to remove it in order
-                    // to move forward.
-                    var vlength = val.generics.length;
-                    for (x = 0; x < vlength; ++x) {
-                        var lev = MAX_LEV_DISTANCE + 1;
-                        var firstGeneric = val.generics[x];
-                        var match = null;
-                        if (elems[firstGeneric]) {
-                            match = firstGeneric;
-                            lev = 0;
-                        } else {
-                            for (elem_name in elems) {
-                                tmp_lev = levenshtein(elem_name, firstGeneric);
-                                if (tmp_lev < lev) {
-                                    lev = tmp_lev;
-                                    match = elem_name;
-                                }
+                    elems[elem_name] += 1;
+                }
+                // We need to find the type that matches the most to remove it in order
+                // to move forward.
+                for (x = 0, length = elem.generics.length; x < length; ++x) {
+                    var generic = elem.generics[x];
+                    var match = null;
+                    if (elems[generic.name]) {
+                        match = generic.name;
+                    } else {
+                        for (elem_name in elems) {
+                            if (!hasOwnPropertyRustdoc(elems, elem_name)) {
+                                continue;
                             }
-                        }
-                        if (match !== null) {
-                            elems[match] -= 1;
-                            if (elems[match] == 0) {
-                                delete elems[match];
+                            if (elem_name === generic) {
+                                match = elem_name;
+                                break;
                             }
-                            total += lev;
-                            done += 1;
-                        } else {
-                            return MAX_LEV_DISTANCE + 1;
                         }
                     }
-                    return Math.ceil(total / done);
+                    if (match === null) {
+                        return MAX_LEV_DISTANCE + 1;
+                    }
+                    elems[match] -= 1;
+                    if (elems[match] === 0) {
+                        delete elems[match];
+                    }
                 }
+                return 0;
             }
             return MAX_LEV_DISTANCE + 1;
         }
 
         /**
-          * This function checks if the object (`obj`) matches the given type (`val`) and its
+          * This function checks if the object (`row`) matches the given type (`elem`) and its
+          * generics (if any).
+          *
+          * @param {Row} row
+          * @param {QueryElement} elem    - The element from the parsed query.
+          *
+          * @return {integer} - Returns a Levenshtein distance to the best match.
+          */
+        function checkIfInGenerics(row, elem) {
+            var lev = MAX_LEV_DISTANCE + 1;
+            for (var x = 0, length = row[GENERICS_DATA].length; x < length && lev !== 0; ++x) {
+                lev = Math.min(
+                    checkType(row[GENERICS_DATA][x], elem, true),
+                    lev
+                );
+            }
+            return lev;
+        }
+
+        /**
+          * This function checks if the object (`row`) matches the given type (`elem`) and its
           * generics (if any).
           *
-          * @param {Object} obj
-          * @param {string} val
+          * @param {Row} row
+          * @param {QueryElement} elem      - The element from the parsed query.
           * @param {boolean} literalSearch
           *
           * @return {integer} - Returns a Levenshtein distance to the best match. If there is
           *                     no match, returns `MAX_LEV_DISTANCE + 1`.
           */
-        function checkType(obj, val, literalSearch) {
-            var lev_distance = MAX_LEV_DISTANCE + 1;
-            var tmp_lev = MAX_LEV_DISTANCE + 1;
-            var len, x, firstGeneric;
-            if (obj[NAME] === val.name) {
-                if (literalSearch) {
-                    if (val.generics && val.generics.length !== 0) {
-                        if (obj.length > GENERICS_DATA &&
-                             obj[GENERICS_DATA].length > 0) {
-                            var elems = Object.create(null);
-                            len = obj[GENERICS_DATA].length;
-                            for (x = 0; x < len; ++x) {
-                                if (!elems[obj[GENERICS_DATA][x][NAME]]) {
-                                    elems[obj[GENERICS_DATA][x][NAME]] = 0;
-                                }
-                                elems[obj[GENERICS_DATA][x][NAME]] += 1;
-                            }
+        function checkType(row, elem, literalSearch) {
+            if (row[NAME].length === 0) {
+                // This is a pure "generic" search, no need to run other checks.
+                if (row.length > GENERICS_DATA) {
+                    return checkIfInGenerics(row, elem);
+                }
+                return MAX_LEV_DISTANCE + 1;
+            }
 
-                            len = val.generics.length;
-                            for (x = 0; x < len; ++x) {
-                                firstGeneric = val.generics[x];
-                                if (elems[firstGeneric]) {
-                                    elems[firstGeneric] -= 1;
-                                } else {
-                                    // Something wasn't found and this is a literal search so
-                                    // abort and return a "failing" distance.
-                                    return MAX_LEV_DISTANCE + 1;
-                                }
-                            }
-                            // Everything was found, success!
+            var lev = levenshtein(row[NAME], elem.name);
+            if (literalSearch) {
+                if (lev !== 0) {
+                    // The name didn't match, let's try to check if the generics do.
+                    if (elem.generics.length === 0) {
+                        var checkGeneric = (row.length > GENERICS_DATA &&
+                            row[GENERICS_DATA].length > 0);
+                        if (checkGeneric && row[GENERICS_DATA].findIndex(function(tmp_elem) {
+                            return tmp_elem[NAME] === elem.name;
+                        }) !== -1) {
                             return 0;
                         }
-                        return MAX_LEV_DISTANCE + 1;
                     }
-                    return 0;
-                } else {
-                    // If the type has generics but don't match, then it won't return at this point.
-                    // Otherwise, `checkGenerics` will return 0 and it'll return.
-                    if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
-                        tmp_lev = checkGenerics(obj, val);
-                        if (tmp_lev <= MAX_LEV_DISTANCE) {
-                            return tmp_lev;
-                        }
-                    }
-                }
-            } else if (literalSearch) {
-                var found = false;
-                if ((!val.generics || val.generics.length === 0) &&
-                      obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
-                    found = obj[GENERICS_DATA].some(
-                        function(gen) {
-                            return gen[NAME] === val.name;
-                        });
-                }
-                return found ? 0 : MAX_LEV_DISTANCE + 1;
-            }
-            lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
-            if (lev_distance <= MAX_LEV_DISTANCE) {
-                // The generics didn't match but the name kinda did so we give it
-                // a levenshtein distance value that isn't *this* good so it goes
-                // into the search results but not too high.
-                lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
-            }
-            if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
-                // We can check if the type we're looking for is inside the generics!
-                var olength = obj[GENERICS_DATA].length;
-                for (x = 0; x < olength; ++x) {
-                    tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
+                    return MAX_LEV_DISTANCE + 1;
+                } else if (elem.generics.length > 0) {
+                    return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
                 }
-                if (tmp_lev !== 0) {
-                    // If we didn't find a good enough result, we go check inside the generics of
-                    // the generics.
-                    for (x = 0; x < olength && tmp_lev !== 0; ++x) {
-                        tmp_lev = Math.min(
-                            checkType(obj[GENERICS_DATA][x], val, literalSearch),
-                            tmp_lev
-                        );
+                return 0;
+            } else if (row.length > GENERICS_DATA) {
+                if (elem.generics.length === 0) {
+                    if (lev === 0) {
+                        return 0;
+                    }
+                    // The name didn't match so we now check if the type we're looking for is inside
+                    // the generics!
+                    lev = checkIfInGenerics(row, elem);
+                    // Now whatever happens, the returned distance is "less good" so we should mark
+                    // it as such, and so we add 0.5 to the distance to make it "less good".
+                    return lev + 0.5;
+                } else if (lev > MAX_LEV_DISTANCE) {
+                    // So our item's name doesn't match at all and has generics.
+                    //
+                    // Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
+                    // looking for "B<C>", we'll need to go down.
+                    return checkIfInGenerics(row, elem);
+                } else {
+                    // At this point, the name kinda match and we have generics to check, so
+                    // let's go!
+                    var tmp_lev = checkGenerics(row, elem, lev);
+                    if (tmp_lev > MAX_LEV_DISTANCE) {
+                        return MAX_LEV_DISTANCE + 1;
                     }
+                    // We compute the median value of both checks and return it.
+                    return (tmp_lev + lev) / 2;
                 }
+            } else if (elem.generics.length > 0) {
+                // In this case, we were expecting generics but there isn't so we simply reject this
+                // one.
+                return MAX_LEV_DISTANCE + 1;
             }
-            // Now whatever happens, the returned distance is "less good" so we should mark it
-            // as such, and so we add 1 to the distance to make it "less good".
-            return Math.min(lev_distance, tmp_lev) + 1;
+            // No generics on our query or on the target type so we can return without doing
+            // anything else.
+            return lev;
         }
 
         /**
-         * This function checks if the object (`obj`) has an argument with the given type (`val`).
+         * This function checks if the object (`row`) has an argument with the given type (`elem`).
          *
-         * @param {Object} obj
-         * @param {string} val
-         * @param {boolean} literalSearch
+         * @param {Row} row
+         * @param {QueryElement} elem    - The element from the parsed query.
          * @param {integer} typeFilter
          *
          * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
          *                      match, returns `MAX_LEV_DISTANCE + 1`.
          */
-        function findArg(obj, val, literalSearch, typeFilter) {
-            var lev_distance = MAX_LEV_DISTANCE + 1;
+        function findArg(row, elem, typeFilter) {
+            var lev = MAX_LEV_DISTANCE + 1;
 
-            if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
-                var length = obj.type[INPUTS_DATA].length;
+            if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
+                var length = row.type[INPUTS_DATA].length;
                 for (var i = 0; i < length; i++) {
-                    var tmp = obj.type[INPUTS_DATA][i];
+                    var tmp = row.type[INPUTS_DATA][i];
                     if (!typePassesFilter(typeFilter, tmp[1])) {
                         continue;
                     }
-                    tmp = checkType(tmp, val, literalSearch);
-                    if (tmp === 0) {
+                    lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
+                    if (lev === 0) {
                         return 0;
-                    } else if (literalSearch) {
-                        continue;
                     }
-                    lev_distance = Math.min(tmp, lev_distance);
                 }
             }
-            return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
+            return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
         }
 
-        function checkReturned(obj, val, literalSearch, typeFilter) {
-            var lev_distance = MAX_LEV_DISTANCE + 1;
+        /**
+         * This function checks if the object (`row`) returns the given type (`elem`).
+         *
+         * @param {Row} row
+         * @param {QueryElement} elem   - The element from the parsed query.
+         * @param {integer} typeFilter
+         *
+         * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
+         *                      match, returns `MAX_LEV_DISTANCE + 1`.
+         */
+        function checkReturned(row, elem, typeFilter) {
+            var lev = MAX_LEV_DISTANCE + 1;
 
-            if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
-                var ret = obj.type[OUTPUT_DATA];
+            if (row && row.type && row.type.length > OUTPUT_DATA) {
+                var ret = row.type[OUTPUT_DATA];
                 if (typeof ret[0] === "string") {
                     ret = [ret];
                 }
@@ -537,16 +1073,13 @@ window.initSearch = function(rawSearchIndex) {
                     if (!typePassesFilter(typeFilter, tmp[1])) {
                         continue;
                     }
-                    tmp = checkType(tmp, val, literalSearch);
-                    if (tmp === 0) {
+                    lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
+                    if (lev === 0) {
                         return 0;
-                    } else if (literalSearch) {
-                        continue;
                     }
-                    lev_distance = Math.min(tmp, lev_distance);
                 }
             }
-            return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
+            return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
         }
 
         function checkPath(contains, lastElem, ty) {
@@ -621,13 +1154,14 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function handleAliases(ret, query, filterCrates) {
+            var lowerQuery = query.toLowerCase();
             // We separate aliases and crate aliases because we want to have current crate
             // aliases to be before the others in the displayed results.
             var aliases = [];
             var crateAliases = [];
             if (filterCrates !== null) {
-                if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
-                    var query_aliases = ALIASES[filterCrates][query.search];
+                if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
+                    var query_aliases = ALIASES[filterCrates][lowerQuery];
                     var len = query_aliases.length;
                     for (var i = 0; i < len; ++i) {
                         aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
@@ -635,9 +1169,9 @@ window.initSearch = function(rawSearchIndex) {
                 }
             } else {
                 Object.keys(ALIASES).forEach(function(crate) {
-                    if (ALIASES[crate][query.search]) {
+                    if (ALIASES[crate][lowerQuery]) {
                         var pushTo = crate === window.currentCrate ? crateAliases : aliases;
-                        var query_aliases = ALIASES[crate][query.search];
+                        var query_aliases = ALIASES[crate][lowerQuery];
                         var len = query_aliases.length;
                         for (var i = 0; i < len; ++i) {
                             pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
@@ -658,7 +1192,7 @@ window.initSearch = function(rawSearchIndex) {
             aliases.sort(sortFunc);
 
             var pushFunc = function(alias) {
-                alias.alias = query.raw;
+                alias.alias = query;
                 var res = buildHrefAndPath(alias);
                 alias.displayPath = pathSplitter(res[0]);
                 alias.fullPath = alias.displayPath + alias.name;
@@ -674,208 +1208,237 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         /**
-         * This function adds the given result into the provided `res` map if it matches the
+         * This function adds the given result into the provided `results` map if it matches the
          * following condition:
          *
-         * * If it is a "literal search" (`isExact`), then `lev` must be 0.
+         * * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
          * * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
          *
-         * The `res` map contains information which will be used to sort the search results:
+         * The `results` map contains information which will be used to sort the search results:
          *
-         * * `fullId` is a `string`` used as the key of the object we use for the `res` map.
+         * * `fullId` is a `string`` used as the key of the object we use for the `results` map.
          * * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
          * * `index` is an `integer`` used to sort by the position of the word in the item's name.
          * * `lev` is the main metric used to sort the search results.
          *
-         * @param {boolean} isExact
-         * @param {Object} res
+         * @param {Results} results
          * @param {string} fullId
          * @param {integer} id
          * @param {integer} index
          * @param {integer} lev
          */
-        function addIntoResults(isExact, res, fullId, id, index, lev) {
-            if (lev === 0 || (!isExact && lev <= MAX_LEV_DISTANCE)) {
-                if (res[fullId] !== undefined) {
-                    var result = res[fullId];
+        function addIntoResults(results, fullId, id, index, lev) {
+            if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
+                if (results[fullId] !== undefined) {
+                    var result = results[fullId];
                     if (result.dontValidate || result.lev <= lev) {
                         return;
                     }
                 }
-                res[fullId] = {
+                results[fullId] = {
                     id: id,
                     index: index,
-                    dontValidate: isExact,
+                    dontValidate: parsedQuery.literalSearch,
                     lev: lev,
                 };
             }
         }
 
-        // quoted values mean literal search
-        var nSearchWords = searchWords.length;
-        var i, it;
-        var ty;
-        var fullId;
-        var returned;
-        var in_args;
-        var len;
-        if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
-            val.charAt(val.length - 1) === val.charAt(0))
-        {
-            val = extractGenerics(val.substr(1, val.length - 2));
-            for (i = 0; i < nSearchWords; ++i) {
-                if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
-                    continue;
+        /**
+         * This function is called in case the query is only one element (with or without generics).
+         * This element will be compared to arguments' and returned values' items and also to items.
+         *
+         * Other important thing to note: since there is only one element, we use levenshtein
+         * distance for name comparisons.
+         *
+         * @param {Row} row
+         * @param {integer} pos              - Position in the `searchIndex`.
+         * @param {QueryElement} elem        - The element from the parsed query.
+         * @param {Results} results_others   - Unqualified results (not in arguments nor in
+         *                                     returned values).
+         * @param {Results} results_in_args  - Matching arguments results.
+         * @param {Results} results_returned - Matching returned arguments results.
+         */
+        function handleSingleArg(
+            row,
+            pos,
+            elem,
+            results_others,
+            results_in_args,
+            results_returned
+        ) {
+            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+                return;
+            }
+            var lev, lev_add = 0, index = -1;
+            var fullId = row.id;
+
+            var in_args = findArg(row, elem, parsedQuery.typeFilter);
+            var returned = checkReturned(row, elem, parsedQuery.typeFilter);
+
+            addIntoResults(results_in_args, fullId, pos, index, in_args);
+            addIntoResults(results_returned, fullId, pos, index, returned);
+
+            if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
+                return;
+            }
+            var searchWord = searchWords[pos];
+
+            if (parsedQuery.literalSearch) {
+                if (searchWord === elem.name) {
+                    addIntoResults(results_others, fullId, pos, -1, 0);
                 }
-                in_args = findArg(searchIndex[i], val, true, typeFilter);
-                returned = checkReturned(searchIndex[i], val, true, typeFilter);
-                ty = searchIndex[i];
-                fullId = ty.id;
-
-                if (searchWords[i] === val.name
-                    && typePassesFilter(typeFilter, searchIndex[i].ty)) {
-                    addIntoResults(true, results, fullId, i, -1, 0);
+                return;
+            }
+
+            // No need to check anything else if it's a "pure" generics search.
+            if (elem.name.length === 0) {
+                if (row.type !== null) {
+                    lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
+                    addIntoResults(results_others, fullId, pos, index, lev);
                 }
-                addIntoResults(true, results_in_args, fullId, i, -1, in_args);
-                addIntoResults(true, results_returned, fullId, i, -1, returned);
-            }
-            query.inputs = [val];
-            query.output = val;
-            query.search = val;
-        // searching by type
-        } else if (val.search("->") > -1) {
-            var trimmer = function(s) { return s.trim(); };
-            var parts = val.split("->").map(trimmer);
-            var input = parts[0];
-            // sort inputs so that order does not matter
-            var inputs = input.split(",").map(trimmer).sort();
-            for (i = 0, len = inputs.length; i < len; ++i) {
-                inputs[i] = extractGenerics(inputs[i]);
-            }
-            var output = extractGenerics(parts[1]);
-
-            for (i = 0; i < nSearchWords; ++i) {
-                if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
-                    continue;
+                return;
+            }
+
+            if (elem.fullPath.length > 1) {
+                lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
+                if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
+                    return;
+                } else if (lev > 0) {
+                    lev_add = lev / 10;
                 }
-                var type = searchIndex[i].type;
-                ty = searchIndex[i];
-                if (!type) {
-                    continue;
+            }
+
+            if (searchWord.indexOf(elem.pathLast) > -1 ||
+                row.normalizedName.indexOf(elem.pathLast) > -1)
+            {
+                // filter type: ... queries
+                if (!results_others[fullId] !== undefined) {
+                    index = row.normalizedName.indexOf(elem.pathLast);
                 }
-                fullId = ty.id;
+            }
+            lev = levenshtein(searchWord, elem.pathLast);
+            lev += lev_add;
+            if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
+            {
+                if (elem.pathLast.length < 6) {
+                    lev = 1;
+                } else {
+                    lev = 0;
+                }
+            }
+            if (lev > MAX_LEV_DISTANCE) {
+                return;
+            } else if (index !== -1 && elem.fullPath.length < 2) {
+                lev -= 1;
+            }
+            if (lev < 0) {
+                lev = 0;
+            }
+            addIntoResults(results_others, fullId, pos, index, lev);
+        }
 
-                returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
-                if (output.name === "*" || returned === 0) {
-                    in_args = false;
-                    var is_module = false;
+        /**
+         * This function is called in case the query has more than one element. In this case, it'll
+         * try to match the items which validates all the elements. For `aa -> bb` will look for
+         * functions which have a parameter `aa` and has `bb` in its returned values.
+         *
+         * @param {Row} row
+         * @param {integer} pos      - Position in the `searchIndex`.
+         * @param {Object} results
+         */
+        function handleArgs(row, pos, results) {
+            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+                return;
+            }
 
-                    if (input === "*") {
-                        is_module = true;
+            var totalLev = 0;
+            var nbLev = 0;
+            var lev;
+
+            // If the result is too "bad", we return false and it ends this search.
+            function checkArgs(elems, callback) {
+                for (var i = 0, len = elems.length; i < len; ++i) {
+                    var elem = elems[i];
+                    // There is more than one parameter to the query so all checks should be "exact"
+                    lev = callback(row, elem, NO_TYPE_FILTER);
+                    if (lev <= 1) {
+                        nbLev += 1;
+                        totalLev += lev;
                     } else {
-                        var firstNonZeroDistance = 0;
-                        for (it = 0, len = inputs.length; it < len; it++) {
-                            var distance = checkType(type, inputs[it], true);
-                            if (distance > 0) {
-                                firstNonZeroDistance = distance;
-                                break;
-                            }
-                        }
-                        in_args = firstNonZeroDistance;
-                    }
-                    addIntoResults(true, results_in_args, fullId, i, -1, in_args);
-                    addIntoResults(true, results_returned, fullId, i, -1, returned);
-                    if (is_module) {
-                        addIntoResults(true, results, fullId, i, -1, 0);
+                        return false;
                     }
                 }
+                return true;
+            }
+            if (!checkArgs(parsedQuery.elems, findArg)) {
+                return;
+            }
+            if (!checkArgs(parsedQuery.returned, checkReturned)) {
+                return;
             }
-            query.inputs = inputs.map(function(input) {
-                return input.name;
-            });
-            query.output = output.name;
-        } else {
-            query.inputs = [val];
-            query.output = val;
-            query.search = val;
-            // gather matching search results up to a certain maximum
-            val = val.replace(/_/g, "");
-
-            var valGenerics = extractGenerics(val);
-
-            var paths = valLower.split("::");
-            removeEmptyStringsFromArray(paths);
-            val = paths[paths.length - 1];
-            var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
-
-            var lev, j;
-            for (j = 0; j < nSearchWords; ++j) {
-                ty = searchIndex[j];
-                if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
-                    continue;
-                }
-                var lev_add = 0;
-                if (paths.length > 1) {
-                    lev = checkPath(contains, paths[paths.length - 1], ty);
-                    if (lev > MAX_LEV_DISTANCE) {
-                        continue;
-                    } else if (lev > 0) {
-                        lev_add = lev / 10;
-                    }
-                }
 
-                returned = MAX_LEV_DISTANCE + 1;
-                in_args = MAX_LEV_DISTANCE + 1;
-                var index = -1;
-                // we want lev results to go lower than others
-                lev = MAX_LEV_DISTANCE + 1;
-                fullId = ty.id;
+            if (nbLev === 0) {
+                return;
+            }
+            lev = Math.round(totalLev / nbLev);
+            addIntoResults(results, row.id, pos, 0, lev);
+        }
 
-                if (searchWords[j].indexOf(split[i]) > -1 ||
-                    searchWords[j].indexOf(val) > -1 ||
-                    ty.normalizedName.indexOf(val) > -1)
-                {
-                    // filter type: ... queries
-                    if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
-                        index = ty.normalizedName.indexOf(val);
+        function innerRunQuery() {
+            var elem, i, nSearchWords, in_returned, row;
+
+            if (parsedQuery.foundElems === 1) {
+                if (parsedQuery.elems.length === 1) {
+                    elem = parsedQuery.elems[0];
+                    for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+                        // It means we want to check for this element everywhere (in names, args and
+                        // returned).
+                        handleSingleArg(
+                            searchIndex[i],
+                            i,
+                            elem,
+                            results_others,
+                            results_in_args,
+                            results_returned
+                        );
                     }
-                }
-                if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
-                    if (typePassesFilter(typeFilter, ty.ty)) {
-                        lev += 1;
-                    } else {
-                        lev = MAX_LEV_DISTANCE + 1;
+                } else if (parsedQuery.returned.length === 1) {
+                    // We received one returned argument to check, so looking into returned values.
+                    elem = parsedQuery.returned[0];
+                    for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+                        row = searchIndex[i];
+                        in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
+                        addIntoResults(results_returned, row.id, i, -1, in_returned);
                     }
                 }
-                in_args = findArg(ty, valGenerics, false, typeFilter);
-                returned = checkReturned(ty, valGenerics, false, typeFilter);
-
-                lev += lev_add;
-                if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
-                    if (val.length < 6) {
-                        lev -= 1;
-                    } else {
-                        lev = 0;
-                    }
+            } else if (parsedQuery.foundElems > 0) {
+                var container = results_others;
+                // In the special case where only a "returned" information is available, we want to
+                // put the information into the "results_returned" dict.
+                if (parsedQuery.returned.length !== 0 && parsedQuery.elems.length === 0) {
+                    container = results_returned;
                 }
-                addIntoResults(false, results_in_args, fullId, j, index, in_args);
-                addIntoResults(false, results_returned, fullId, j, index, returned);
-                if (typePassesFilter(typeFilter, ty.ty) &&
-                        (index !== -1 || lev <= MAX_LEV_DISTANCE)) {
-                    if (index !== -1 && paths.length < 2) {
-                        lev = 0;
-                    }
-                    addIntoResults(false, results, fullId, j, index, lev);
+                for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+                    handleArgs(searchIndex[i], i, container);
                 }
             }
         }
 
-        var ret = {
-            "in_args": sortResults(results_in_args, true),
-            "returned": sortResults(results_returned, true),
-            "others": sortResults(results, false),
-        };
-        handleAliases(ret, query, filterCrates);
+        if (parsedQuery.error === null) {
+            innerRunQuery();
+        }
+
+        var ret = createQueryResults(
+            sortResults(results_in_args, true),
+            sortResults(results_returned, true),
+            sortResults(results_others, false),
+            parsedQuery);
+        handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
+        if (parsedQuery.error !== null && ret.others.length !== 0) {
+            // It means some doc aliases were found so let's "remove" the error!
+            ret.query.error = null;
+        }
         return ret;
     }
 
@@ -892,9 +1455,13 @@ window.initSearch = function(rawSearchIndex) {
      * @param  {string} path   - The path of the result
      * @param  {string} keys   - The keys to be used (["file", "open"])
      * @param  {Object} parent - The parent of the result
+     *
      * @return {boolean}       - Whether the result is valid or not
      */
     function validateResult(name, path, keys, parent) {
+        if (!keys || !keys.length) {
+            return true;
+        }
         for (var i = 0, len = keys.length; i < len; ++i) {
             // each check is for validation so we negate the conditions and invalidate
             if (!(
@@ -913,30 +1480,6 @@ window.initSearch = function(rawSearchIndex) {
         return true;
     }
 
-    /**
-     * Parse a string into a query object.
-     *
-     * @param {string} raw - The text that the user typed.
-     * @returns {ParsedQuery}
-     */
-    function getQuery(raw) {
-        var matches, type = "", query;
-        query = raw;
-
-        matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
-        if (matches) {
-            type = matches[1].replace(/^const$/, "constant");
-            query = query.substring(matches[0].length);
-        }
-
-        return {
-            raw: raw,
-            query: query,
-            type: type,
-            id: query + type
-        };
-    }
-
     function nextTab(direction) {
         var next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
         searchState.focusedByTab[searchState.currentTab] = document.activeElement;
@@ -1088,11 +1631,11 @@ window.initSearch = function(rawSearchIndex) {
                 link.appendChild(wrapper);
                 output.appendChild(link);
             });
-        } else {
+        } else if (query.error === null) {
             output.className = "search-failed" + extraClass;
             output.innerHTML = "No results :(<br/>" +
                 "Try on <a href=\"https://duckduckgo.com/?q=" +
-                encodeURIComponent("rust " + query.query) +
+                encodeURIComponent("rust " + query.userQuery) +
                 "\">DuckDuckGo</a>?<br/><br/>" +
                 "Or try looking in one of these:<ul><li>The <a " +
                 "href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
@@ -1115,6 +1658,11 @@ window.initSearch = function(rawSearchIndex) {
         return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
     }
 
+    /**
+     * @param {ResultsTable} results
+     * @param {boolean} go_to_first
+     * @param {string} filterCrates
+     */
     function showResults(results, go_to_first, filterCrates) {
         var search = searchState.outputElement();
         if (go_to_first || (results.others.length === 1
@@ -1132,13 +1680,15 @@ window.initSearch = function(rawSearchIndex) {
             elem.click();
             return;
         }
-        var query = getQuery(searchState.input.value);
+        if (results.query === undefined) {
+            results.query = parseQuery(searchState.input.value);
+        }
 
-        currentResults = query.id;
+        currentResults = results.query.userQuery;
 
-        var ret_others = addTab(results.others, query, true);
-        var ret_in_args = addTab(results.in_args, query, false);
-        var ret_returned = addTab(results.returned, query, false);
+        var ret_others = addTab(results.others, results.query, true);
+        var ret_in_args = addTab(results.in_args, results.query, false);
+        var ret_returned = addTab(results.returned, results.query, false);
 
         // Navigate to the relevant tab if the current tab is empty, like in case users search
         // for "-> String". If they had selected another tab previously, they have to click on
@@ -1164,11 +1714,19 @@ window.initSearch = function(rawSearchIndex) {
             }
             crates += `</select>`;
         }
-        var output = `<div id="search-settings">
-            <h1 class="search-results-title">Results for ${escape(query.query)} ` +
-            (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
-            crates +
-            `</div><div id="titles">` +
+
+        var typeFilter = "";
+        if (results.query.typeFilter !== NO_TYPE_FILTER) {
+            typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+        }
+
+        var output = `<div id="search-settings">` +
+            `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
+            `${typeFilter}</h1> in ${crates} </div>`;
+        if (results.query.error !== null) {
+            output += `<h3>Query parser error: "${results.query.error}".</h3>`;
+        }
+        output += `<div id="titles">` +
             makeTabHeader(0, "In Names", ret_others[1]) +
             makeTabHeader(1, "In Parameters", ret_in_args[1]) +
             makeTabHeader(2, "In Return Types", ret_returned[1]) +
@@ -1196,28 +1754,6 @@ window.initSearch = function(rawSearchIndex) {
         printTab(currentTab);
     }
 
-    function execSearch(query, searchWords, filterCrates) {
-        query = query.raw.trim();
-        var results = {
-            "in_args": [],
-            "returned": [],
-            "others": [],
-        };
-
-        if (query.length !== 0) {
-            var tmp = execQuery(getQuery(query), searchWords, filterCrates);
-
-            results.in_args.push(tmp.in_args);
-            results.returned.push(tmp.returned);
-            results.others.push(tmp.others);
-        }
-        return {
-            "in_args": results.in_args[0],
-            "returned": results.returned[0],
-            "others": results.others[0],
-        };
-    }
-
     /**
      * Perform a search based on the current state of the search input element
      * and display the results.
@@ -1226,17 +1762,14 @@ window.initSearch = function(rawSearchIndex) {
      */
     function search(e, forced) {
         var params = searchState.getQueryStringParams();
-        var query = getQuery(searchState.input.value.trim());
+        var query = parseQuery(searchState.input.value.trim());
 
         if (e) {
             e.preventDefault();
         }
 
-        if (query.query.length === 0) {
-            return;
-        }
-        if (!forced && query.id === currentResults) {
-            if (query.query.length > 0) {
+        if (!forced && query.userQuery === currentResults) {
+            if (query.userQuery.length > 0) {
                 putBackSearch();
             }
             return;
@@ -1251,13 +1784,12 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         // Update document title to maintain a meaningful browser history
-        searchState.title = "Results for " + query.query + " - Rust";
+        searchState.title = "Results for " + query.original + " - Rust";
 
         // Because searching is incremental by character, only the most
         // recent search query is added to the browser history.
         if (searchState.browserSupportsHistoryApi()) {
-            var newURL = buildUrl(query.raw, filterCrates);
-
+            var newURL = buildUrl(query.original, filterCrates);
             if (!history.state && !params.search) {
                 history.pushState(null, "", newURL);
             } else {
@@ -1265,8 +1797,10 @@ window.initSearch = function(rawSearchIndex) {
             }
         }
 
-        showResults(execSearch(query, searchWords, filterCrates),
-            params["go_to_first"], filterCrates);
+        showResults(
+            execQuery(query, searchWords, filterCrates),
+            params.go_to_first,
+            filterCrates);
     }
 
     function buildIndex(rawSearchIndex) {
index 0b5fb480595797a3fbc96264fd079961371e0f45..56b02cd848041236e30fab13cfc70fa0de4f62ff 100644 (file)
@@ -10,7 +10,6 @@
 use rustc_ast::ast;
 use rustc_hir::{def::CtorKind, def_id::DefId};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_span::Pos;
 use rustc_target::spec::abi::Abi as RustcAbi;
 
@@ -83,7 +82,7 @@ fn convert_visibility(&self, v: clean::Visibility) -> Visibility {
         match v {
             Public => Visibility::Public,
             Inherited => Visibility::Default,
-            Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
+            Restricted(did) if did.is_crate_root() => Visibility::Crate,
             Restricted(did) => Visibility::Restricted {
                 parent: from_item_id(did.into()),
                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
index 0fcfabba4c0a12bec4075833fbad95ba14ed0ddc..cd196a01847991d108335f367f35fe0f28b7e68b 100644 (file)
@@ -795,6 +795,7 @@ fn main_options(options: config::Options) -> MainResult {
                 let resolver_caches = resolver.borrow_mut().access(|resolver| {
                     collect_intra_doc_links::early_resolve_intra_doc_links(
                         resolver,
+                        sess,
                         krate,
                         externs,
                         document_private,
index c48f8bd0c7cc5a0cced4aa8341630a5157369718..42e87f3f9610b1b54cb855fce0679998e7cce810 100644 (file)
@@ -3,6 +3,7 @@
 //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
 
 use pulldown_cmark::LinkType;
+use rustc_ast::util::comments::may_have_doc_links;
 use rustc_data_structures::{fx::FxHashMap, intern::Interned, stable_set::FxHashSet};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::def::Namespace::*;
@@ -159,7 +160,7 @@ fn try_from(res: ResolveRes) -> Result<Self, ()> {
 }
 
 /// A link failed to resolve.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 enum ResolutionFailure<'a> {
     /// This resolved, but with the wrong namespace.
     WrongNamespace {
@@ -199,7 +200,7 @@ enum ResolutionFailure<'a> {
     Dummy,
 }
 
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 enum MalformedGenerics {
     /// This link has unbalanced angle brackets.
     ///
@@ -252,6 +253,7 @@ fn full_res(&self) -> Option<Res> {
     }
 }
 
+#[derive(Clone, Copy)]
 enum AnchorFailure {
     /// User error: `[std#x#y]` is not valid
     MultipleAnchors,
@@ -556,7 +558,15 @@ fn resolve_path(
         // Resolver doesn't know about true, false, and types that aren't paths (e.g. `()`).
         let result = self
             .cx
-            .enter_resolver(|resolver| resolver.resolve_rustdoc_path(path_str, ns, module_id))
+            .resolver_caches
+            .doc_link_resolutions
+            .get(&(Symbol::intern(path_str), ns, module_id))
+            .copied()
+            .unwrap_or_else(|| {
+                self.cx.enter_resolver(|resolver| {
+                    resolver.resolve_rustdoc_path(path_str, ns, module_id)
+                })
+            })
             .and_then(|res| res.try_into().ok())
             .or_else(|| resolve_primitive(path_str, ns))
             .or_else(|| self.resolve_macro_rules(path_str, ns));
@@ -1040,17 +1050,30 @@ fn visit_item(&mut self, item: &Item) {
         // In the presence of re-exports, this is not the same as the module of the item.
         // Rather than merging all documentation into one, resolve it one attribute at a time
         // so we know which module it came from.
-        for (parent_module, doc) in item.attrs.collapsed_doc_value_by_module_level() {
+        for (parent_module, doc) in item.attrs.prepare_to_doc_link_resolution() {
+            if !may_have_doc_links(&doc) {
+                continue;
+            }
             debug!("combined_docs={}", doc);
             // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
             // This is a degenerate case and it's not supported by rustdoc.
             let parent_node = parent_module.or(parent_node);
-            for md_link in markdown_links(&doc) {
+            let mut tmp_links = self
+                .cx
+                .resolver_caches
+                .markdown_links
+                .take()
+                .expect("`markdown_links` are already borrowed");
+            if !tmp_links.contains_key(&doc) {
+                tmp_links.insert(doc.clone(), preprocessed_markdown_links(&doc));
+            }
+            for md_link in &tmp_links[&doc] {
                 let link = self.resolve_link(&item, &doc, parent_node, md_link);
                 if let Some(link) = link {
                     self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link);
                 }
             }
+            self.cx.resolver_caches.markdown_links = Some(tmp_links);
         }
 
         if item.is_mod() {
@@ -1066,18 +1089,19 @@ fn visit_item(&mut self, item: &Item) {
     }
 }
 
-enum PreprocessingError<'a> {
+enum PreprocessingError {
     Anchor(AnchorFailure),
     Disambiguator(Range<usize>, String),
-    Resolution(ResolutionFailure<'a>, String, Option<Disambiguator>),
+    Resolution(ResolutionFailure<'static>, String, Option<Disambiguator>),
 }
 
-impl From<AnchorFailure> for PreprocessingError<'_> {
+impl From<AnchorFailure> for PreprocessingError {
     fn from(err: AnchorFailure) -> Self {
         Self::Anchor(err)
     }
 }
 
+#[derive(Clone)]
 struct PreprocessingInfo {
     path_str: String,
     disambiguator: Option<Disambiguator>,
@@ -1085,15 +1109,18 @@ struct PreprocessingInfo {
     link_text: String,
 }
 
+// Not a typedef to avoid leaking several private structures from this module.
+crate struct PreprocessedMarkdownLink(Result<PreprocessingInfo, PreprocessingError>, MarkdownLink);
+
 /// Returns:
 /// - `None` if the link should be ignored.
 /// - `Some(Err)` if the link should emit an error
 /// - `Some(Ok)` if the link is valid
 ///
 /// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
-fn preprocess_link<'a>(
-    ori_link: &'a MarkdownLink,
-) -> Option<Result<PreprocessingInfo, PreprocessingError<'a>>> {
+fn preprocess_link(
+    ori_link: &MarkdownLink,
+) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
     // [] is mostly likely not supposed to be a link
     if ori_link.link.is_empty() {
         return None;
@@ -1172,6 +1199,12 @@ fn preprocess_link<'a>(
     }))
 }
 
+fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
+    markdown_links(s, |link| {
+        preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link))
+    })
+}
+
 impl LinkCollector<'_, '_> {
     /// This is the entry point for resolving an intra-doc link.
     ///
@@ -1181,8 +1214,9 @@ fn resolve_link(
         item: &Item,
         dox: &str,
         parent_node: Option<DefId>,
-        ori_link: MarkdownLink,
+        link: &PreprocessedMarkdownLink,
     ) -> Option<ItemLink> {
+        let PreprocessedMarkdownLink(pp_link, ori_link) = link;
         trace!("considering link '{}'", ori_link.link);
 
         let diag_info = DiagnosticInfo {
@@ -1192,28 +1226,29 @@ fn resolve_link(
             link_range: ori_link.range.clone(),
         };
 
-        let PreprocessingInfo { ref path_str, disambiguator, extra_fragment, link_text } =
-            match preprocess_link(&ori_link)? {
-                Ok(x) => x,
-                Err(err) => {
-                    match err {
-                        PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, err),
-                        PreprocessingError::Disambiguator(range, msg) => {
-                            disambiguator_error(self.cx, diag_info, range, &msg)
-                        }
-                        PreprocessingError::Resolution(err, path_str, disambiguator) => {
-                            resolution_failure(
-                                self,
-                                diag_info,
-                                &path_str,
-                                disambiguator,
-                                smallvec![err],
-                            );
-                        }
+        let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = match pp_link
+        {
+            Ok(x) => x,
+            Err(err) => {
+                match err {
+                    PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, *err),
+                    PreprocessingError::Disambiguator(range, msg) => {
+                        disambiguator_error(self.cx, diag_info, range.clone(), msg)
+                    }
+                    PreprocessingError::Resolution(err, path_str, disambiguator) => {
+                        resolution_failure(
+                            self,
+                            diag_info,
+                            path_str,
+                            *disambiguator,
+                            smallvec![err.clone()],
+                        );
                     }
-                    return None;
                 }
-            };
+                return None;
+            }
+        };
+        let disambiguator = *disambiguator;
 
         let inner_docs = item.inner_docs(self.cx.tcx);
 
@@ -1250,7 +1285,7 @@ fn resolve_link(
                 module_id,
                 dis: disambiguator,
                 path_str: path_str.to_owned(),
-                extra_fragment,
+                extra_fragment: extra_fragment.clone(),
             },
             diag_info.clone(), // this struct should really be Copy, but Range is not :(
             matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
@@ -1320,8 +1355,8 @@ fn resolve_link(
                 }
 
                 Some(ItemLink {
-                    link: ori_link.link,
-                    link_text,
+                    link: ori_link.link.clone(),
+                    link_text: link_text.clone(),
                     did: res.def_id(self.cx.tcx),
                     fragment,
                 })
@@ -1343,7 +1378,12 @@ fn resolve_link(
                     &diag_info,
                 )?;
                 let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
-                Some(ItemLink { link: ori_link.link, link_text, did: id, fragment })
+                Some(ItemLink {
+                    link: ori_link.link.clone(),
+                    link_text: link_text.clone(),
+                    did: id,
+                    fragment,
+                })
             }
         }
     }
index dffceff045d0b6d6e2cc239c422f6e97ff6f8655..68e10e3a18c7ec40b6e7acf2b1d2a5bb0c12f664 100644 (file)
@@ -1,33 +1,39 @@
 use crate::clean::Attributes;
 use crate::core::ResolverCaches;
-use crate::html::markdown::markdown_links;
-use crate::passes::collect_intra_doc_links::preprocess_link;
+use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
+use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, ItemKind};
 use rustc_ast_lowering::ResolverAstLowering;
-use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def::{DefKind, Res};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::Namespace::*;
+use rustc_hir::def::{DefKind, Namespace, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::TraitCandidate;
 use rustc_middle::ty::{DefIdTree, Visibility};
 use rustc_resolve::{ParentScope, Resolver};
 use rustc_session::config::Externs;
-use rustc_span::SyntaxContext;
+use rustc_session::Session;
+use rustc_span::{Symbol, SyntaxContext};
 
 use std::collections::hash_map::Entry;
 use std::mem;
 
 crate fn early_resolve_intra_doc_links(
     resolver: &mut Resolver<'_>,
+    sess: &Session,
     krate: &ast::Crate,
     externs: Externs,
     document_private_items: bool,
 ) -> ResolverCaches {
     let mut link_resolver = EarlyDocLinkResolver {
         resolver,
+        sess,
         current_mod: CRATE_DEF_ID,
         visited_mods: Default::default(),
+        markdown_links: Default::default(),
+        doc_link_resolutions: Default::default(),
         traits_in_scope: Default::default(),
         all_traits: Default::default(),
         all_trait_impls: Default::default(),
@@ -36,7 +42,7 @@
 
     // Overridden `visit_item` below doesn't apply to the crate root,
     // so we have to visit its attributes and reexports separately.
-    link_resolver.load_links_in_attrs(&krate.attrs);
+    link_resolver.resolve_doc_links_local(&krate.attrs);
     link_resolver.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id());
     visit::walk_crate(&mut link_resolver, krate);
     link_resolver.process_extern_impls();
@@ -50,6 +56,8 @@
     }
 
     ResolverCaches {
+        markdown_links: Some(link_resolver.markdown_links),
+        doc_link_resolutions: link_resolver.doc_link_resolutions,
         traits_in_scope: link_resolver.traits_in_scope,
         all_traits: Some(link_resolver.all_traits),
         all_trait_impls: Some(link_resolver.all_trait_impls),
     }
 }
 
+fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes {
+    Attributes::from_ast_iter(attrs.map(|attr| (attr, None)), true)
+}
+
 struct EarlyDocLinkResolver<'r, 'ra> {
     resolver: &'r mut Resolver<'ra>,
+    sess: &'r Session,
     current_mod: LocalDefId,
     visited_mods: DefIdSet,
+    markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
+    doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>,
     traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
     all_traits: Vec<DefId>,
     all_trait_impls: Vec<DefId>,
@@ -92,18 +107,11 @@ fn add_traits_in_scope(&mut self, def_id: DefId) {
         }
     }
 
-    fn add_traits_in_parent_scope(&mut self, def_id: DefId) {
-        if let Some(module_id) = self.resolver.parent(def_id) {
-            self.add_traits_in_scope(module_id);
-        }
-    }
-
     /// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass.
     /// That pass filters impls using type-based information, but we don't yet have such
     /// information here, so we just conservatively calculate traits in scope for *all* modules
     /// having impls in them.
     fn process_extern_impls(&mut self) {
-        // FIXME: Need to resolve doc links on all these impl and trait items below.
         // Resolving links in already existing crates may trigger loading of new crates.
         let mut start_cnum = 0;
         loop {
@@ -124,7 +132,7 @@ fn process_extern_impls(&mut self) {
                 // the current crate, and links in their doc comments are not resolved.
                 for &def_id in &all_traits {
                     if self.resolver.cstore().visibility_untracked(def_id) == Visibility::Public {
-                        self.add_traits_in_parent_scope(def_id);
+                        self.resolve_doc_links_extern_impl(def_id, false);
                     }
                 }
                 for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
@@ -135,17 +143,17 @@ fn process_extern_impls(&mut self) {
                                 == Visibility::Public
                         })
                     {
-                        self.add_traits_in_parent_scope(impl_def_id);
+                        self.resolve_doc_links_extern_impl(impl_def_id, false);
                     }
                 }
                 for (ty_def_id, impl_def_id) in all_inherent_impls {
                     if self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public
                     {
-                        self.add_traits_in_parent_scope(impl_def_id);
+                        self.resolve_doc_links_extern_impl(impl_def_id, true);
                     }
                 }
-                for def_id in all_incoherent_impls {
-                    self.add_traits_in_parent_scope(def_id);
+                for impl_def_id in all_incoherent_impls {
+                    self.resolve_doc_links_extern_impl(impl_def_id, true);
                 }
 
                 self.all_traits.extend(all_traits);
@@ -161,16 +169,63 @@ fn process_extern_impls(&mut self) {
         }
     }
 
-    fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute]) {
+    fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) {
+        self.resolve_doc_links_extern_outer(def_id, def_id);
+        let assoc_item_def_ids = Vec::from_iter(
+            self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess),
+        );
+        for assoc_def_id in assoc_item_def_ids {
+            if !is_inherent
+                || self.resolver.cstore().visibility_untracked(assoc_def_id) == Visibility::Public
+            {
+                self.resolve_doc_links_extern_outer(assoc_def_id, def_id);
+            }
+        }
+    }
+
+    fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) {
+        if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+            return;
+        }
+        // FIXME: actually resolve links, not just add traits in scope.
+        if let Some(parent_id) = self.resolver.parent(scope_id) {
+            self.add_traits_in_scope(parent_id);
+        }
+    }
+
+    fn resolve_doc_links_extern_inner(&mut self, def_id: DefId) {
+        if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+            return;
+        }
+        // FIXME: actually resolve links, not just add traits in scope.
+        self.add_traits_in_scope(def_id);
+    }
+
+    fn resolve_doc_links_local(&mut self, attrs: &[ast::Attribute]) {
+        if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
+            return;
+        }
         let module_id = self.current_mod.to_def_id();
+        self.resolve_doc_links(doc_attrs(attrs.iter()), module_id);
+    }
+
+    fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) {
         let mut need_traits_in_scope = false;
-        for (doc_module, doc) in
-            Attributes::from_ast(attrs, None).collapsed_doc_value_by_module_level()
-        {
+        for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() {
             assert_eq!(doc_module, None);
-            for link in markdown_links(&doc.as_str()) {
-                if let Some(Ok(pinfo)) = preprocess_link(&link) {
-                    self.resolver.resolve_rustdoc_path(&pinfo.path_str, TypeNS, module_id);
+            let links = self
+                .markdown_links
+                .entry(doc)
+                .or_insert_with_key(|doc| preprocessed_markdown_links(doc));
+            for PreprocessedMarkdownLink(pp_link, _) in links {
+                if let Ok(pinfo) = pp_link {
+                    // FIXME: Resolve the path in all namespaces and resolve its prefixes too.
+                    let ns = TypeNS;
+                    self.doc_link_resolutions
+                        .entry((Symbol::intern(&pinfo.path_str), ns, module_id))
+                        .or_insert_with_key(|(path, ns, module_id)| {
+                            self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *module_id)
+                        });
                     need_traits_in_scope = true;
                 }
             }
@@ -197,15 +252,13 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
                     && module_id.is_local()
             {
                 if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
-                    // FIXME: Need to resolve doc links on all these extern items
-                    // reached through reexports.
                     let scope_id = match child.res {
                         Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id).unwrap(),
                         _ => def_id,
                     };
-                    self.add_traits_in_parent_scope(scope_id); // Outer attribute scope
+                    self.resolve_doc_links_extern_outer(def_id, scope_id); // Outer attribute scope
                     if let Res::Def(DefKind::Mod, ..) = child.res {
-                        self.add_traits_in_scope(def_id); // Inner attribute scope
+                        self.resolve_doc_links_extern_inner(def_id); // Inner attribute scope
                     }
                     // Traits are processed in `add_extern_traits_in_scope`.
                     if let Res::Def(DefKind::Mod | DefKind::Enum, ..) = child.res {
@@ -219,10 +272,10 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
 
 impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
     fn visit_item(&mut self, item: &ast::Item) {
-        self.load_links_in_attrs(&item.attrs); // Outer attribute scope
+        self.resolve_doc_links_local(&item.attrs); // Outer attribute scope
         if let ItemKind::Mod(..) = item.kind {
             let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
-            self.load_links_in_attrs(&item.attrs); // Inner attribute scope
+            self.resolve_doc_links_local(&item.attrs); // Inner attribute scope
             self.process_module_children_or_reexports(self.current_mod.to_def_id());
             visit::walk_item(self, item);
             self.current_mod = old_mod;
@@ -241,22 +294,22 @@ fn visit_item(&mut self, item: &ast::Item) {
     }
 
     fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
-        self.load_links_in_attrs(&item.attrs);
+        self.resolve_doc_links_local(&item.attrs);
         visit::walk_assoc_item(self, item, ctxt)
     }
 
     fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
-        self.load_links_in_attrs(&item.attrs);
+        self.resolve_doc_links_local(&item.attrs);
         visit::walk_foreign_item(self, item)
     }
 
     fn visit_variant(&mut self, v: &ast::Variant) {
-        self.load_links_in_attrs(&v.attrs);
+        self.resolve_doc_links_local(&v.attrs);
         visit::walk_variant(self, v)
     }
 
     fn visit_field_def(&mut self, field: &ast::FieldDef) {
-        self.load_links_in_attrs(&field.attrs);
+        self.resolve_doc_links_local(&field.attrs);
         visit::walk_field_def(self, field)
     }
 
index 5db2d0747c83bb7f9de930dae440fac140f95d75..97a436c7500701f626c4136227d91759ddaffea2 100644 (file)
@@ -24,9 +24,6 @@
 mod strip_priv_imports;
 crate use self::strip_priv_imports::STRIP_PRIV_IMPORTS;
 
-mod unindent_comments;
-crate use self::unindent_comments::UNINDENT_COMMENTS;
-
 mod propagate_doc_cfg;
 crate use self::propagate_doc_cfg::PROPAGATE_DOC_CFG;
 
@@ -81,7 +78,6 @@
 crate const PASSES: &[Pass] = &[
     CHECK_DOC_TEST_VISIBILITY,
     STRIP_HIDDEN,
-    UNINDENT_COMMENTS,
     STRIP_PRIVATE,
     STRIP_PRIV_IMPORTS,
     PROPAGATE_DOC_CFG,
@@ -96,7 +92,6 @@
 /// The list of passes run by default.
 crate const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(COLLECT_TRAIT_IMPLS),
-    ConditionalPass::always(UNINDENT_COMMENTS),
     ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY),
     ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
     ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
deleted file mode 100644 (file)
index 0f60415..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-//! Removes excess indentation on comments in order for the Markdown
-//! to be parsed correctly. This is necessary because the convention for
-//! writing documentation is to provide a space between the /// or //! marker
-//! and the doc text, but Markdown is whitespace-sensitive. For example,
-//! a block of text with four-space indentation is parsed as a code block,
-//! so if we didn't unindent comments, these list items
-//!
-//! /// A list:
-//! ///
-//! ///    - Foo
-//! ///    - Bar
-//!
-//! would be parsed as if they were in a code block, which is likely not what the user intended.
-use std::cmp;
-
-use rustc_span::symbol::kw;
-
-use crate::clean::{self, DocFragment, DocFragmentKind, Item};
-use crate::core::DocContext;
-use crate::fold::{self, DocFolder};
-use crate::passes::Pass;
-
-#[cfg(test)]
-mod tests;
-
-crate const UNINDENT_COMMENTS: Pass = Pass {
-    name: "unindent-comments",
-    run: unindent_comments,
-    description: "removes excess indentation on comments in order for markdown to like it",
-};
-
-crate fn unindent_comments(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
-    CommentCleaner.fold_crate(krate)
-}
-
-struct CommentCleaner;
-
-impl fold::DocFolder for CommentCleaner {
-    fn fold_item(&mut self, mut i: Item) -> Option<Item> {
-        i.attrs.unindent_doc_comments();
-        Some(self.fold_item_recur(i))
-    }
-}
-
-impl clean::Attributes {
-    crate fn unindent_doc_comments(&mut self) {
-        unindent_fragments(&mut self.doc_strings);
-    }
-}
-
-fn unindent_fragments(docs: &mut Vec<DocFragment>) {
-    // `add` is used in case the most common sugared doc syntax is used ("/// "). The other
-    // fragments kind's lines are never starting with a whitespace unless they are using some
-    // markdown formatting requiring it. Therefore, if the doc block have a mix between the two,
-    // we need to take into account the fact that the minimum indent minus one (to take this
-    // whitespace into account).
-    //
-    // For example:
-    //
-    // /// hello!
-    // #[doc = "another"]
-    //
-    // In this case, you want "hello! another" and not "hello!  another".
-    let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind)
-        && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc)
-    {
-        // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to
-        // "decide" how much the minimum indent will be.
-        1
-    } else {
-        0
-    };
-
-    // `min_indent` is used to know how much whitespaces from the start of each lines must be
-    // removed. Example:
-    //
-    // ///     hello!
-    // #[doc = "another"]
-    //
-    // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum
-    // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4
-    // (5 - 1) whitespaces.
-    let Some(min_indent) = docs
-        .iter()
-        .map(|fragment| {
-            fragment.doc.as_str().lines().fold(usize::MAX, |min_indent, line| {
-                if line.chars().all(|c| c.is_whitespace()) {
-                    min_indent
-                } else {
-                    // Compare against either space or tab, ignoring whether they are
-                    // mixed or not.
-                    let whitespace = line.chars().take_while(|c| *c == ' ' || *c == '\t').count();
-                    cmp::min(min_indent, whitespace)
-                        + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add }
-                }
-            })
-        })
-        .min()
-    else {
-        return;
-    };
-
-    for fragment in docs {
-        if fragment.doc == kw::Empty {
-            continue;
-        }
-
-        let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 {
-            min_indent - add
-        } else {
-            min_indent
-        };
-
-        fragment.indent = min_indent;
-    }
-}
diff --git a/src/librustdoc/passes/unindent_comments/tests.rs b/src/librustdoc/passes/unindent_comments/tests.rs
deleted file mode 100644 (file)
index baff839..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-use super::*;
-
-use crate::clean::collapse_doc_fragments;
-
-use rustc_span::create_default_session_globals_then;
-use rustc_span::source_map::DUMMY_SP;
-use rustc_span::symbol::Symbol;
-
-fn create_doc_fragment(s: &str) -> Vec<DocFragment> {
-    vec![DocFragment {
-        span: DUMMY_SP,
-        parent_module: None,
-        doc: Symbol::intern(s),
-        kind: DocFragmentKind::SugaredDoc,
-        indent: 0,
-    }]
-}
-
-#[track_caller]
-fn run_test(input: &str, expected: &str) {
-    create_default_session_globals_then(|| {
-        let mut s = create_doc_fragment(input);
-        unindent_fragments(&mut s);
-        assert_eq!(collapse_doc_fragments(&s), expected);
-    });
-}
-
-#[test]
-fn should_unindent() {
-    run_test("    line1\n    line2", "line1\nline2");
-}
-
-#[test]
-fn should_unindent_multiple_paragraphs() {
-    run_test("    line1\n\n    line2", "line1\n\nline2");
-}
-
-#[test]
-fn should_leave_multiple_indent_levels() {
-    // Line 2 is indented another level beyond the
-    // base indentation and should be preserved
-    run_test("    line1\n\n        line2", "line1\n\n    line2");
-}
-
-#[test]
-fn should_ignore_first_line_indent() {
-    run_test("line1\n    line2", "line1\n    line2");
-}
-
-#[test]
-fn should_not_ignore_first_line_indent_in_a_single_line_para() {
-    run_test("line1\n\n    line2", "line1\n\n    line2");
-}
-
-#[test]
-fn should_unindent_tabs() {
-    run_test("\tline1\n\tline2", "line1\nline2");
-}
-
-#[test]
-fn should_trim_mixed_indentation() {
-    run_test("\t    line1\n\t    line2", "line1\nline2");
-    run_test("    \tline1\n    \tline2", "line1\nline2");
-}
-
-#[test]
-fn should_not_trim() {
-    run_test("\t    line1  \n\t    line2", "line1  \nline2");
-    run_test("    \tline1  \n    \tline2", "line1  \nline2");
-}
index 5bcec779bc0e7d130be976f1cb17ba9d660b13ed..9723cdbe3345f3e1fc572f4c0cea5919de4b9457 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
 use rustc_middle::ty::TyCtxt;
 
@@ -29,7 +29,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
     }
 
     crate fn visit_lib(&mut self, cnum: CrateNum) {
-        let did = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+        let did = cnum.as_def_id();
         self.update(did, Some(AccessLevel::Public));
         self.visit_mod(did);
     }
index 9168e236c548d1d0e9938ee6dd4cdbd308fdfd72..fd336816c3a6d228dcef22171c43140f6fa7656f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9168e236c548d1d0e9938ee6dd4cdbd308fdfd72
+Subproject commit fd336816c3a6d228dcef22171c43140f6fa7656f
index 69e35270266555d0f0cdf8f583cda8d63a382217..a87152e0321b9b4a658f53e1772894c8e471b904 100644 (file)
@@ -6,21 +6,21 @@
 use std::arch::asm;
 
 // CHECK-LABEL: @clobber_sysv64
-// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_sysv64() {
     asm!("", clobber_abi("sysv64"));
 }
 
 // CHECK-LABEL: @clobber_win64
-// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_win64() {
     asm!("", clobber_abi("win64"));
 }
 
 // CHECK-LABEL: @clobber_sysv64
-// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_sysv64_edx() {
     let foo: i32;
@@ -28,7 +28,7 @@ pub unsafe fn clobber_sysv64_edx() {
 }
 
 // CHECK-LABEL: @clobber_win64
-// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
 #[no_mangle]
 pub unsafe fn clobber_win64_edx() {
     let foo: i32;
index d9614f062b7e96e8ab3d2af71e4a2c3b635214e0..bccb9e4c7586254462e1164cb29b2d81fe4a5261 100644 (file)
@@ -28,7 +28,7 @@ impl IntoError<Error> for Api
     #[no_mangle]
     fn into_error(self, error: Self::Source) -> Error {
         Error::Api {
-            source: (|v| v)(error),
+            source: error,
         }
     }
 }
index a656c9e6f656a8f01db6717e3bfff5ec27d5d3bc..13c41f7d4a9061f3715dc4af80e15ce328d8b577 100644 (file)
@@ -1,13 +1,72 @@
+// min-llvm-version: 14.0
 // ignore-debug: the debug assertions get in the way
-// compile-flags: -O
+// compile-flags: -O -Z merge-functions=disabled
 #![crate_type = "lib"]
 
 // Ensure that trivial casts of vec elements are O(1)
 
-// CHECK-LABEL: @vec_iterator_cast
+pub struct Wrapper<T>(T);
+
+#[repr(C)]
+pub struct Foo {
+    a: u64,
+    b: u64,
+    c: u64,
+    d: u64,
+}
+
+// Going from an aggregate struct to another type currently requires Copy to
+// enable the TrustedRandomAccess specialization. Without it optimizations do not yet
+// reliably recognize the loops as noop for for repr(C) or non-Copy structs.
+#[derive(Copy, Clone)]
+pub struct Bar {
+    a: u64,
+    b: u64,
+    c: u64,
+    d: u64,
+}
+
+// CHECK-LABEL: @vec_iterator_cast_primitive
+#[no_mangle]
+pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    vec.into_iter().map(|e| e as u8).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_wrapper
+#[no_mangle]
+pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    vec.into_iter().map(|e| Wrapper(e)).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_unwrap
+#[no_mangle]
+pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+    vec.into_iter().map(|e| e.0).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_aggregate
 #[no_mangle]
-pub fn vec_iterator_cast(vec: Vec<isize>) -> Vec<usize> {
+pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
     // CHECK-NOT: loop
     // CHECK-NOT: call
-    vec.into_iter().map(|e| e as usize).collect()
+    vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_deaggregate
+#[no_mangle]
+pub fn vec_iterator_cast_deaggregate(vec: Vec<Bar>) -> Vec<[u64; 4]> {
+    // CHECK-NOT: loop
+    // CHECK-NOT: call
+
+    // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
+    // This currently is not guaranteed for repr(Rust) types, but it happens to work here and
+    // the UCG may add additional guarantees for homogenous types in the future that would make this
+    // correct.
+    vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
 }
index bea33073366f733e63a08450723fee0fdb890890..3b890e4be2e290f4ce98f0f44797418eed439191 100644 (file)
@@ -4,21 +4,22 @@
   fn h() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12
       let _1: (!, !);                      // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+     let mut _2: fn() -> ! {sleep};       // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+     let mut _9: ();                      // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
-+     let mut _10: ();                     // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
++     let mut _2: (!, !);                  // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++     let mut _3: fn() -> ! {sleep};       // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++     let mut _10: ();                     // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
++     let mut _11: ();                     // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
 +     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22
-+         debug f => _2;                   // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
-+         let _3: !;                       // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+         let mut _4: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+         let mut _6: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
-+         let mut _7: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
-+         let mut _8: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
++         debug f => _3;                   // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
++         let _4: !;                       // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
++         let mut _5: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++         let mut _7: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
++         let mut _8: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
++         let mut _9: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
 +         scope 2 {
-+             debug a => _3;               // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
-+             let _5: !;                   // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
++             debug a => _4;               // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
++             let _6: !;                   // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
 +             scope 3 {
-+                 debug b => _5;           // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
++                 debug b => _6;           // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
 +             }
 +             scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16
 +                 scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
--         _1 = call_twice::<!, fn() -> ! {sleep}>(sleep) -> bb1; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+-         call_twice::<!, fn() -> ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
 +         StorageLive(_2);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+         _2 = sleep;                      // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++         StorageLive(_3);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++         _3 = sleep;                      // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
                                            // mir::Constant
 -                                          // + span: $DIR/inline-diverging.rs:22:5: 22:15
 -                                          // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(Scalar(<ZST>)) }
 -                                          // mir::Constant
                                            // + span: $DIR/inline-diverging.rs:22:16: 22:21
                                            // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
-+         StorageLive(_3);                 // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+         StorageLive(_4);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+         _4 = &_2;                        // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+         StorageLive(_9);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
-+         _9 = const ();                   // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++         StorageLive(_4);                 // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
++         StorageLive(_5);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++         _5 = &_3;                        // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++         StorageLive(_10);                // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++         _10 = const ();                  // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
 +         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
-      }
-  
-      bb1: {
--         StorageDead(_1);                 // scope 0 at $DIR/inline-diverging.rs:22:22: 22:23
--         _0 = const ();                   // scope 0 at $DIR/inline-diverging.rs:21:12: 23:2
--         return;                          // scope 0 at $DIR/inline-diverging.rs:23:2: 23:2
++     }
++ 
++     bb1: {
 +         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
       }
   }
index 5fb57c285becac09f46b5cc6ee447bc308bc6ce5..4aff4445158098efdaa023a3393314f1d9e207d6 100644 (file)
@@ -21,7 +21,7 @@ fn main() -> () {
         StorageLive(_2);                 // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
         StorageLive(_3);                 // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
         _3 = ();                         // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
-        _2 = transmute::<(), Void>(move _3) -> [return: bb1, unwind: bb4]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
+        transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
                                          // mir::Constant
                                          // + span: $DIR/issue-72181-1.rs:17:9: 17:40
                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
index 9f235248ca59f9a2c61112c005979684576aa0a5..8423128123ab76e108fcee5a8866a21ff2d1287d 100644 (file)
 | '_#2r live at {bb0[0..=1]}
 | '_#3r live at {bb0[0..=1]}
 | '_#4r live at {bb0[0..=1]}
-| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
-| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
-| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
-| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
-| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
-| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
-| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
-| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
+| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
+| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
 |
 fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool {
     debug w => _1;                       // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27
index ed94a1ecf006252f79da61898d048595d549c779..f79e2705ad29cce82115f971e7ec67ee98567dff 100644 (file)
@@ -18,8 +18,8 @@
 | '_#3r live at {bb1[0]}
 | '_#4r live at {bb1[1..=3]}
 | '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0])
-| '_#4r: '_#5r due to Assignment at Single(bb1[3])
+| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
index 95997b2070172d955de39b41256af0eec0df2c76..162cacef8a54afab04bf2bc554858e6cbb6fb96f 100644 (file)
@@ -18,8 +18,8 @@
 | '_#3r live at {bb1[0]}
 | '_#4r live at {bb1[1..=3]}
 | '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0])
-| '_#4r: '_#5r due to Assignment at Single(bb1[3])
+| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
index e02580135af38f3f9a02d8745b52b024052d91c9..b383c5ec9dc60a173fc9a8391828a6467faa3d86 100644 (file)
@@ -16,7 +16,7 @@
 | '_#1r live at {bb0[0..=22]}
 | '_#3r live at {bb0[10]}
 | '_#4r live at {bb0[11]}
-| '_#3r: '_#4r due to Assignment at Single(bb0[10])
+| '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11
index 2e0330c449721153bc3c57d08d8b61694828e38b..b47a1fefa41d00d7e8646c32bdf38d1016733914 100644 (file)
@@ -1,6 +1,6 @@
 // exact-check
 
-const QUERY = 'hashmap';
+const QUERY = '"hashmap"';
 const FILTER_CRATE = 'core';
 
 const EXPECTED = {
diff --git a/src/test/rustdoc-js-std/parser-errors.js b/src/test/rustdoc-js-std/parser-errors.js
new file mode 100644 (file)
index 0000000..779ab86
--- /dev/null
@@ -0,0 +1,365 @@
+const QUERY = [
+    '<P>',
+    '-> <P>',
+    'a<"P">',
+    '"P" "P"',
+    'P "P"',
+    '"p" p',
+    '"const": p',
+    "a<:a>",
+    "a<::a>",
+    "((a))",
+    "(p -> p",
+    "::a::b",
+    "a::::b",
+    "a::b::",
+    ":a",
+    "a b:",
+    "a (b:",
+    "_:",
+    "a-bb",
+    "a>bb",
+    "ab'",
+    "a->",
+    '"p" <a>',
+    '"p" a<a>',
+    "a,<",
+    "aaaaa<>b",
+    "fn:aaaaa<>b",
+    "->a<>b",
+    "a<->",
+    "a:: a",
+    "a ::a",
+    "a<a>:",
+    "a<>:",
+    "a,:",
+    "  a<>  :",
+    "mod : :",
+];
+
+const PARSED = [
+    {
+        elems: [],
+        foundElems: 0,
+        original: "<P>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "<p>",
+        error: "Found generics without a path",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "-> <P>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "-> <p>",
+        error: "Found generics without a path",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<\"P\">",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<\"p\">",
+        error: "`\"` cannot be used in generics",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "\"P\" \"P\"",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "\"p\" \"p\"",
+        error: "Cannot have more than one literal search element",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "P \"P\"",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "p \"p\"",
+        error: "Cannot use literal search when there is more than one element",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "\"p\" p",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "\"p\" p",
+        error: "You cannot have more than one element if you use quotes",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "\"const\": p",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "\"const\": p",
+        error: "You cannot use quotes on type filter",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<:a>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<:a>",
+        error: "Unexpected `:` after `<`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<::a>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<::a>",
+        error: "Unexpected `::`: paths cannot start with `::`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "((a))",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "((a))",
+        error: "Unexpected `(`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "(p -> p",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "(p -> p",
+        error: "Unexpected `(`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "::a::b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "::a::b",
+        error: "Paths cannot start with `::`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a::::b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a::::b",
+        error: "Unexpected `::::`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a::b::",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a::b::",
+        error: "Paths cannot end with `::`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: ":a",
+        returned: [],
+        typeFilter: -1,
+        userQuery: ":a",
+        error: "Expected type filter before `:`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a b:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a b:",
+        error: "Unexpected `:`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a (b:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a (b:",
+        error: "Unexpected `(`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "_:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "_:",
+        error: "Unknown type filter `_`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a-bb",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a-bb",
+        error: "Unexpected `-` (did you mean `->`?)",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a>bb",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a>bb",
+        error: "Unexpected `>` (did you mean `->`?)",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "ab'",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "ab'",
+        error: "Unexpected `'`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a->",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a->",
+        error: "Expected at least one item after `->`",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"p" <a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p" <a>',
+        error: "Found generics without a path",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"p" a<a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p" a<a>',
+        error: "You cannot have more than one element if you use quotes",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a,<',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a,<',
+        error: 'Found generics without a path',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'aaaaa<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'aaaaa<>b',
+        error: 'Expected `,`, ` `, `:` or `->`, found `b`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'fn:aaaaa<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'fn:aaaaa<>b',
+        error: 'Expected `,`, ` ` or `->`, found `b`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '->a<>b',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '->a<>b',
+        error: 'Expected `,` or ` `, found `b`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a<->',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a<->',
+        error: 'Unexpected `-` after `<`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a:: a',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a:: a',
+        error: 'Paths cannot end with `::`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'a ::a',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a ::a',
+        error: 'Paths cannot start with `::`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<a>:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<a>:",
+        error: 'Unexpected `:`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<>:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<>:",
+        error: 'Unexpected `<` in type filter',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a,:",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a,:",
+        error: 'Unexpected `,` in type filter',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a<>  :",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<>  :",
+        error: 'Unexpected `<` in type filter',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "mod : :",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "mod : :",
+        error: 'Unexpected `:`',
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-filter.js b/src/test/rustdoc-js-std/parser-filter.js
new file mode 100644 (file)
index 0000000..e5a87a4
--- /dev/null
@@ -0,0 +1,43 @@
+const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo'];
+
+const PARSED = [
+    {
+        elems: [{
+            name: "foo",
+            fullPath: ["foo"],
+            pathWithoutLast: [],
+            pathLast: "foo",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "fn:foo",
+        returned: [],
+        typeFilter: 5,
+        userQuery: "fn:foo",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "foo",
+            fullPath: ["foo"],
+            pathWithoutLast: [],
+            pathLast: "foo",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "enum : foo",
+        returned: [],
+        typeFilter: 4,
+        userQuery: "enum : foo",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "macro<f>:foo",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "macro<f>:foo",
+        error: "Unexpected `:`",
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-generics.js b/src/test/rustdoc-js-std/parser-generics.js
new file mode 100644 (file)
index 0000000..0cf7f50
--- /dev/null
@@ -0,0 +1,62 @@
+const QUERY = ['A<B<C<D>,  E>', 'p<> u8', '"p"<a>'];
+
+const PARSED = [
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'A<B<C<D>,  E>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a<b<c<d>,  e>',
+        error: 'Unexpected `<` after `<`',
+    },
+    {
+        elems: [
+            {
+                name: "p",
+                fullPath: ["p"],
+                pathWithoutLast: [],
+                pathLast: "p",
+                generics: [],
+            },
+            {
+                name: "u8",
+                fullPath: ["u8"],
+                pathWithoutLast: [],
+                pathLast: "u8",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "p<> u8",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "p<> u8",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: "p",
+                fullPath: ["p"],
+                pathWithoutLast: [],
+                pathLast: "p",
+                generics: [
+                    {
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: '"p"<a>',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p"<a>',
+        error: null,
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-literal.js b/src/test/rustdoc-js-std/parser-literal.js
new file mode 100644 (file)
index 0000000..87b3baf
--- /dev/null
@@ -0,0 +1,27 @@
+const QUERY = ['R<P>'];
+
+const PARSED = [
+    {
+        elems: [{
+            name: "r",
+            fullPath: ["r"],
+            pathWithoutLast: [],
+            pathLast: "r",
+            generics: [
+                {
+                    name: "p",
+                    fullPath: ["p"],
+                    pathWithoutLast: [],
+                    pathLast: "p",
+                    generics: [],
+                },
+            ],
+        }],
+        foundElems: 1,
+        original: "R<P>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "r<p>",
+        error: null,
+    }
+];
diff --git a/src/test/rustdoc-js-std/parser-paths.js b/src/test/rustdoc-js-std/parser-paths.js
new file mode 100644 (file)
index 0000000..9f823f9
--- /dev/null
@@ -0,0 +1,90 @@
+const QUERY = ['A::B', 'A::B,C',  'A::B<f>,C', 'mod::a'];
+
+const PARSED = [
+    {
+        elems: [{
+            name: "a::b",
+            fullPath: ["a", "b"],
+            pathWithoutLast: ["a"],
+            pathLast: "b",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "A::B",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a::b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: "a::b",
+                fullPath: ["a", "b"],
+                pathWithoutLast: ["a"],
+                pathLast: "b",
+                generics: [],
+            },
+            {
+                name: "c",
+                fullPath: ["c"],
+                pathWithoutLast: [],
+                pathLast: "c",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: 'A::B,C',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a::b,c',
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: "a::b",
+                fullPath: ["a", "b"],
+                pathWithoutLast: ["a"],
+                pathLast: "b",
+                generics: [
+                    {
+                        name: "f",
+                        fullPath: ["f"],
+                        pathWithoutLast: [],
+                        pathLast: "f",
+                        generics: [],
+                    },
+                ],
+            },
+            {
+                name: "c",
+                fullPath: ["c"],
+                pathWithoutLast: [],
+                pathLast: "c",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: 'A::B<f>,C',
+        returned: [],
+        typeFilter: -1,
+        userQuery: 'a::b<f>,c',
+        error: null,
+    },
+    {
+        elems: [{
+            name: "mod::a",
+            fullPath: ["mod", "a"],
+            pathWithoutLast: ["mod"],
+            pathLast: "a",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: "mod::a",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "mod::a",
+        error: null,
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-quote.js b/src/test/rustdoc-js-std/parser-quote.js
new file mode 100644 (file)
index 0000000..1e16c90
--- /dev/null
@@ -0,0 +1,87 @@
+const QUERY = [
+    '-> "p"',
+    '"p",',
+    '"p" -> a',
+    '"a" -> "p"',
+    '->"-"',
+    '"a',
+    '""',
+];
+
+const PARSED = [
+    {
+        elems: [],
+        foundElems: 1,
+        original: '-> "p"',
+        returned: [{
+            name: "p",
+            fullPath: ["p"],
+            pathWithoutLast: [],
+            pathLast: "p",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: '-> "p"',
+        error: null,
+    },
+    {
+        elems: [{
+            name: "p",
+            fullPath: ["p"],
+            pathWithoutLast: [],
+            pathLast: "p",
+            generics: [],
+        }],
+        foundElems: 1,
+        original: '"p",',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p",',
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"p" -> a',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"p" -> a',
+        error: "You cannot have more than one element if you use quotes",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"a" -> "p"',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"a" -> "p"',
+        error: "Cannot have more than one literal search element",
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '->"-"',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '->"-"',
+        error: 'Unexpected `-` in a string element',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '"a',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '"a',
+        error: 'Unclosed `"`',
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: '""',
+        returned: [],
+        typeFilter: -1,
+        userQuery: '""',
+        error: 'Cannot have empty string element',
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-returned.js b/src/test/rustdoc-js-std/parser-returned.js
new file mode 100644 (file)
index 0000000..b45466a
--- /dev/null
@@ -0,0 +1,78 @@
+const QUERY = ['-> F<P>', '-> P', '->,a', 'aaaaa->a'];
+
+const PARSED = [
+    {
+        elems: [],
+        foundElems: 1,
+        original: "-> F<P>",
+        returned: [{
+            name: "f",
+            fullPath: ["f"],
+            pathWithoutLast: [],
+            pathLast: "f",
+            generics: [
+                {
+                    name: "p",
+                    fullPath: ["p"],
+                    pathWithoutLast: [],
+                    pathLast: "p",
+                    generics: [],
+                },
+            ],
+        }],
+        typeFilter: -1,
+        userQuery: "-> f<p>",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "-> P",
+        returned: [{
+            name: "p",
+            fullPath: ["p"],
+            pathWithoutLast: [],
+            pathLast: "p",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: "-> p",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 1,
+        original: "->,a",
+        returned: [{
+            name: "a",
+            fullPath: ["a"],
+            pathWithoutLast: [],
+            pathLast: "a",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: "->,a",
+        error: null,
+    },
+    {
+        elems: [{
+            name: "aaaaa",
+            fullPath: ["aaaaa"],
+            pathWithoutLast: [],
+            pathLast: "aaaaa",
+            generics: [],
+        }],
+        foundElems: 2,
+        original: "aaaaa->a",
+        returned: [{
+            name: "a",
+            fullPath: ["a"],
+            pathWithoutLast: [],
+            pathLast: "a",
+            generics: [],
+        }],
+        typeFilter: -1,
+        userQuery: "aaaaa->a",
+        error: null,
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-separators.js b/src/test/rustdoc-js-std/parser-separators.js
new file mode 100644 (file)
index 0000000..5b7abdf
--- /dev/null
@@ -0,0 +1,206 @@
+// ignore-tidy-tab
+
+const QUERY = [
+    'aaaaaa    b',
+    'a b',
+    'a,b',
+    'a\tb',
+    'a<b c>',
+    'a<b,c>',
+    'a<b\tc>',
+];
+
+const PARSED = [
+    {
+        elems: [
+            {
+                name: 'aaaaaa',
+                fullPath: ['aaaaaa'],
+                pathWithoutLast: [],
+                pathLast: 'aaaaaa',
+                generics: [],
+            },
+            {
+                name: 'b',
+                fullPath: ['b'],
+                pathWithoutLast: [],
+                pathLast: 'b',
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "aaaaaa      b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "aaaaaa     b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [],
+            },
+            {
+                name: 'b',
+                fullPath: ['b'],
+                pathWithoutLast: [],
+                pathLast: 'b',
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [],
+            },
+            {
+                name: 'b',
+                fullPath: ['b'],
+                pathWithoutLast: [],
+                pathLast: 'b',
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a,b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a,b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [],
+            },
+            {
+                name: 'b',
+                fullPath: ['b'],
+                pathWithoutLast: [],
+                pathLast: 'b',
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a\tb",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a\tb",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [
+                    {
+                        name: 'b',
+                        fullPath: ['b'],
+                        pathWithoutLast: [],
+                        pathLast: 'b',
+                        generics: [],
+                    },
+                    {
+                        name: 'c',
+                        fullPath: ['c'],
+                        pathWithoutLast: [],
+                        pathLast: 'c',
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: "a<b c>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<b c>",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [
+                    {
+                        name: 'b',
+                        fullPath: ['b'],
+                        pathWithoutLast: [],
+                        pathLast: 'b',
+                        generics: [],
+                    },
+                    {
+                        name: 'c',
+                        fullPath: ['c'],
+                        pathWithoutLast: [],
+                        pathLast: 'c',
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: "a<b,c>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<b,c>",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: 'a',
+                fullPath: ['a'],
+                pathWithoutLast: [],
+                pathLast: 'a',
+                generics: [
+                    {
+                        name: 'b',
+                        fullPath: ['b'],
+                        pathWithoutLast: [],
+                        pathLast: 'b',
+                        generics: [],
+                    },
+                    {
+                        name: 'c',
+                        fullPath: ['c'],
+                        pathWithoutLast: [],
+                        pathLast: 'c',
+                        generics: [],
+                    },
+                ],
+            },
+        ],
+        foundElems: 1,
+        original: "a<b\tc>",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a<b\tc>",
+        error: null,
+    },
+];
diff --git a/src/test/rustdoc-js-std/parser-weird-queries.js b/src/test/rustdoc-js-std/parser-weird-queries.js
new file mode 100644 (file)
index 0000000..a3d85ae
--- /dev/null
@@ -0,0 +1,123 @@
+// This test is mostly to check that the parser still kinda outputs something
+// (and doesn't enter an infinite loop!) even though the query is completely
+// invalid.
+const QUERY = [
+    'a b',
+    'a   b',
+    'a,b(c)',
+    'aaa,a',
+    ',,,,',
+    'mod    :',
+    'mod\t:',
+];
+
+const PARSED = [
+    {
+        elems: [
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+            },
+            {
+                name: "b",
+                fullPath: ["b"],
+                pathWithoutLast: [],
+                pathLast: "b",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a b",
+        error: null,
+    },
+    {
+        elems: [
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+            },
+            {
+                name: "b",
+                fullPath: ["b"],
+                pathWithoutLast: [],
+                pathLast: "b",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "a   b",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a   b",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: "a,b(c)",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "a,b(c)",
+        error: "Unexpected `(`",
+    },
+    {
+        elems: [
+            {
+                name: "aaa",
+                fullPath: ["aaa"],
+                pathWithoutLast: [],
+                pathLast: "aaa",
+                generics: [],
+            },
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+            },
+        ],
+        foundElems: 2,
+        original: "aaa,a",
+        returned: [],
+        typeFilter: -1,
+        userQuery: "aaa,a",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: ",,,,",
+        returned: [],
+        typeFilter: -1,
+        userQuery: ",,,,",
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'mod    :',
+        returned: [],
+        typeFilter: 0,
+        userQuery: 'mod    :',
+        error: null,
+    },
+    {
+        elems: [],
+        foundElems: 0,
+        original: 'mod\t:',
+        returned: [],
+        typeFilter: 0,
+        userQuery: 'mod\t:',
+        error: null,
+    },
+];
index 924129f86c8680214c07e2569cbea02aa2bc2a63..aec8484a41f6dcb6e27ad2cee6a0247163bdc4d3 100644 (file)
@@ -1,4 +1,7 @@
+// ignore-order
+
 const QUERY = '"error"';
+const FILTER_CRATE = 'std';
 
 const EXPECTED = {
     'others': [
@@ -6,7 +9,12 @@ const EXPECTED = {
         { 'path': 'std::fmt', 'name': 'Error' },
         { 'path': 'std::io', 'name': 'Error' },
     ],
-    'in_args': [],
+    'in_args': [
+        { 'path': 'std::fmt::Error', 'name': 'eq' },
+        { 'path': 'std::fmt::Error', 'name': 'cmp' },
+        { 'path': 'std::fmt::Error', 'name': 'partial_cmp' },
+
+    ],
     'returned': [
         { 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
     ],
index 2c808143bae67fb434fda6307c5da81ef57d71c3..29609904b1957a52f893b9de8f097f796d399a49 100644 (file)
@@ -1,8 +1,8 @@
-const QUERY = 'struct:Vec';
+const QUERY = 'struct:VecD';
 
 const EXPECTED = {
     'others': [
-        { 'path': 'std::vec', 'name': 'Vec' },
         { 'path': 'std::collections', 'name': 'VecDeque' },
+        { 'path': 'std::vec', 'name': 'Vec' },
     ],
 };
index 3915ee7dc5d23196249c8499452744471076cfbb..25efbad26954003233d959692152f34888221bd7 100644 (file)
@@ -1,6 +1,7 @@
 // exact-check
 
 const QUERY = 'macro:print';
+const FILTER_CRATE = 'std';
 
 const EXPECTED = {
     'others': [
@@ -9,6 +10,8 @@ const EXPECTED = {
         { 'path': 'std', 'name': 'println' },
         { 'path': 'std', 'name': 'eprintln' },
         { 'path': 'std::pin', 'name': 'pin' },
-        { 'path': 'core::pin', 'name': 'pin' },
+        { 'path': 'std::future', 'name': 'join' },
+        { 'path': 'std', 'name': 'line' },
+        { 'path': 'std', 'name': 'write' },
     ],
 };
index e1a3256876bde15af94274c65d1ab29a71c6ce62..cd0e8e7b4a9eb41524adbb55fc8d9c931a8d20d4 100644 (file)
@@ -4,6 +4,6 @@ const EXPECTED = {
     'others': [
         { 'path': 'std::vec::Vec', 'name': 'new' },
         { 'path': 'std::vec::Vec', 'name': 'ne' },
-        { 'path': 'std::rc::Rc', 'name': 'ne' },
+        { 'path': 'alloc::vec::Vec', 'name': 'ne' },
     ],
 };
index 4b1e2e2970479d386c87370b03e783017937f588..e06047ba7606e78b8de5591ec8ecbbda03993a9d 100644 (file)
@@ -1,6 +1,6 @@
 // exact-check
 
-const QUERY = 'true';
+const QUERY = '"true"';
 
 const FILTER_CRATE = 'doc_alias_filter';
 
index ff188d5145801ad127793bf1094137b6cadb743f..7bb0cbe388fee1c8d7626b2d4aa74edd9ac80d10 100644 (file)
@@ -27,6 +27,7 @@ const QUERY = [
 
 const EXPECTED = [
     {
+        // StructItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -38,6 +39,7 @@ const EXPECTED = [
         ],
     },
     {
+        // StructFieldItem
         'others': [
             {
                 'path': 'doc_alias::Struct',
@@ -49,6 +51,7 @@ const EXPECTED = [
         ],
     },
     {
+        // StructMethodItem
         'others': [
             {
                 'path': 'doc_alias::Struct',
@@ -76,6 +79,7 @@ const EXPECTED = [
         ],
     },
     {
+        // ImplTraitFunction
         'others': [
             {
                 'path': 'doc_alias::Struct',
@@ -87,6 +91,7 @@ const EXPECTED = [
         ],
     },
     {
+        // EnumItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -98,6 +103,7 @@ const EXPECTED = [
         ],
     },
     {
+        // VariantItem
         'others': [
             {
                 'path': 'doc_alias::Enum',
@@ -109,6 +115,7 @@ const EXPECTED = [
         ],
     },
     {
+        // EnumMethodItem
         'others': [
             {
                 'path': 'doc_alias::Enum',
@@ -120,6 +127,7 @@ const EXPECTED = [
         ],
     },
     {
+        // TypedefItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -131,6 +139,7 @@ const EXPECTED = [
         ],
     },
     {
+        // TraitItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -142,6 +151,7 @@ const EXPECTED = [
         ],
     },
     {
+        // TraitTypeItem
         'others': [
             {
                 'path': 'doc_alias::Trait',
@@ -153,6 +163,7 @@ const EXPECTED = [
         ],
     },
     {
+        // AssociatedConstItem
         'others': [
             {
                 'path': 'doc_alias::Trait',
@@ -164,6 +175,7 @@ const EXPECTED = [
         ],
     },
     {
+        // TraitFunctionItem
         'others': [
             {
                 'path': 'doc_alias::Trait',
@@ -175,6 +187,7 @@ const EXPECTED = [
         ],
     },
     {
+        // FunctionItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -186,6 +199,7 @@ const EXPECTED = [
         ],
     },
     {
+        // ModuleItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -197,6 +211,7 @@ const EXPECTED = [
         ],
     },
     {
+        // ConstItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -212,6 +227,7 @@ const EXPECTED = [
         ],
     },
     {
+        // StaticItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -223,6 +239,7 @@ const EXPECTED = [
         ],
     },
     {
+        // UnionItem
         'others': [
             {
                 'path': 'doc_alias',
@@ -240,6 +257,7 @@ const EXPECTED = [
         ],
     },
     {
+        // UnionFieldItem
         'others': [
             {
                 'path': 'doc_alias::Union',
@@ -251,6 +269,7 @@ const EXPECTED = [
         ],
     },
     {
+        // UnionMethodItem
         'others': [
             {
                 'path': 'doc_alias::Union',
@@ -262,6 +281,7 @@ const EXPECTED = [
         ],
     },
     {
+        // MacroItem
         'others': [
             {
                 'path': 'doc_alias',
index 63a9ad5381244c635e80674ea8eafc11e04bd839..5e5ba7cd9ac8f55c35c4525e182390592ae6c335 100644 (file)
@@ -1,16 +1,18 @@
 // exact-check
 
 const QUERY = [
-    '"R<P>"',
+    'R<P>',
     '"P"',
     'P',
-    '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+    'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
     'TraitCat',
     'TraitDog',
+    'Result<String>',
 ];
 
 const EXPECTED = [
     {
+        // R<P>
         'returned': [
             { 'path': 'generics', 'name': 'alef' },
         ],
@@ -19,6 +21,7 @@ const EXPECTED = [
         ],
     },
     {
+        // "P"
         'others': [
             { 'path': 'generics', 'name': 'P' },
         ],
@@ -30,29 +33,41 @@ const EXPECTED = [
         ],
     },
     {
+        // P
         'returned': [
             { 'path': 'generics', 'name': 'alef' },
-            { 'path': 'generics', 'name': 'bet' },
         ],
         'in_args': [
             { 'path': 'generics', 'name': 'alpha' },
-            { 'path': 'generics', 'name': 'beta' },
         ],
     },
     {
+        // "ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
         'in_args': [
             { 'path': 'generics', 'name': 'extracreditlabhomework' },
         ],
         'returned': [],
     },
     {
+        // TraitCat
         'in_args': [
             { 'path': 'generics', 'name': 'gamma' },
         ],
     },
     {
+        // TraitDog
         'in_args': [
             { 'path': 'generics', 'name': 'gamma' },
         ],
     },
+    {
+        // Result<String>
+        'others': [],
+        'returned': [
+            { 'path': 'generics', 'name': 'super_soup' },
+        ],
+        'in_args': [
+            { 'path': 'generics', 'name': 'super_soup' },
+        ],
+    },
 ];
index 5e11a6d6018856f75daaa7e73cc43fe7cd03764e..055c51c7ec5781f819196bbf9e1907b5ff61194b 100644 (file)
@@ -24,3 +24,5 @@ pub trait TraitCat {}
 pub trait TraitDog {}
 
 pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
+
+pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s }
index 9465e8e7ab99649bfff1c0a9fe6f64c3f267ca03..7a5156e81c4c875fbd0a5d58bb216ff0b7074b8e 100644 (file)
@@ -1,7 +1,7 @@
 // normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+// check-pass
 #![deny(warnings)]
 
 //! Email me at <hello@localhost>.
-//~^ ERROR unknown disambiguator `hello`
 
 //! This should *not* warn: <hello@example.com>.
diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr
deleted file mode 100644 (file)
index 1b07828..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error: unknown disambiguator `hello`
-  --> $DIR/email-address-localhost.rs:4:18
-   |
-LL | //! Email me at <hello@localhost>.
-   |                  ^^^^^
-   |
-note: the lint level is defined here
-  --> $DIR/email-address-localhost.rs:2:9
-   |
-LL | #![deny(warnings)]
-   |         ^^^^^^^^
-   = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
-   = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
-
-error: aborting due to previous error
-
index d0372d4945f3a4598043fea06c2565c2f5ae8373..a19e452b459e19c85d84fb048b34a3b03cac84fc 100644 (file)
@@ -1,7 +1,6 @@
 Available passes for running rustdoc:
 check_doc_test_visibility - run various visibility-related lints on doctests
         strip-hidden - strips all `#[doc(hidden)]` items from the output
-   unindent-comments - removes excess indentation on comments in order for markdown to like it
        strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
   strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
    propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
@@ -14,7 +13,6 @@ check-invalid-html-tags - detects invalid HTML tags in doc comments
 
 Default passes for rustdoc:
  collect-trait-impls
-   unindent-comments
 check_doc_test_visibility
         strip-hidden  (when not --document-hidden-items)
        strip-private  (when not --document-private-items)
diff --git a/src/test/rustdoc/duplicated_impl.rs b/src/test/rustdoc/duplicated_impl.rs
new file mode 100644 (file)
index 0000000..4e901b3
--- /dev/null
@@ -0,0 +1,14 @@
+// This test ensures that the same implementation doesn't show more than once.
+// It's a regression test for https://github.com/rust-lang/rust/issues/96036.
+
+#![crate_name = "foo"]
+
+// We check that there is only one "impl<T> Something<Whatever> for T" listed in the
+// blanket implementations.
+
+// @has 'foo/struct.Whatever.html'
+// @count - '//*[@id="blanket-implementations-list"]/section[@class="impl has-srclink"]' 1
+
+pub trait Something<T> { }
+pub struct Whatever;
+impl<T> Something<Whatever> for T {}
diff --git a/src/test/rustdoc/early-unindent.rs b/src/test/rustdoc/early-unindent.rs
new file mode 100644 (file)
index 0000000..791a452
--- /dev/null
@@ -0,0 +1,26 @@
+// This is a regression for https://github.com/rust-lang/rust/issues/96079.
+
+#![crate_name = "foo"]
+
+pub mod app {
+    pub struct S;
+
+    impl S {
+        // @has 'foo/app/struct.S.html'
+        // @has - '//a[@href="../enums/enum.Foo.html#method.by_name"]' 'Foo::by_name'
+        /**
+        Doc comment hello! [`Foo::by_name`](`crate::enums::Foo::by_name`).
+        */
+        pub fn whatever(&self) {}
+    }
+}
+
+pub mod enums {
+    pub enum Foo {
+        Bar,
+    }
+
+    impl Foo {
+        pub fn by_name(&self) {}
+    }
+}
diff --git a/src/test/rustdoc/where.SWhere_Simd_item-decl.html b/src/test/rustdoc/where.SWhere_Simd_item-decl.html
new file mode 100644 (file)
index 0000000..0133bca
--- /dev/null
@@ -0,0 +1 @@
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Simd&lt;T&gt;(_) <br /><span class="where">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div>
\ No newline at end of file
diff --git a/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html
new file mode 100644 (file)
index 0000000..54026ff
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait TraitWhere {
+    type <a href="#associatedtype.Item" class="associatedtype">Item</a>&lt;'a&gt;<br />&#160;&#160;&#160; <span class="where">where<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Self: 'a</span>;
+}</code></pre></div>
\ No newline at end of file
index 549cfff96cb6dc37e5c56aa7f06c99ff778e60dd..50a5722fbaff6926e5feec51c6ffd18d531bac5a 100644 (file)
@@ -1,3 +1,4 @@
+#![feature(generic_associated_types)]
 #![crate_name = "foo"]
 
 pub trait MyTrait { fn dummy(&self) { } }
@@ -19,6 +20,18 @@ pub fn delta() {}
 
 pub struct Echo<E>(E);
 
+// @has 'foo/struct.Simd.html'
+// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]'
+pub struct Simd<T>([T; 1])
+where
+    T: MyTrait;
+
+// @has 'foo/trait.TraitWhere.html'
+// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]'
+pub trait TraitWhere {
+    type Item<'a> where Self: 'a;
+}
+
 // @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
 //          "impl<E> MyTrait for Echo<E> where E: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
index 4c4ce8b5e9e493ecd6f22fcc9bd70a9d036b4038..272372ebedc1d01c5f716badcc5c7a6b2c08dffd 100644 (file)
@@ -29,13 +29,13 @@ fn main() {
         //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
         asm!("", in("ip") foo);
         //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
-        asm!("", in("k0") foo);
-        //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
 
         asm!("", in("st(2)") foo);
         //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
         asm!("", in("mm0") foo);
         //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+        asm!("", in("k0") foo);
+        //~^ ERROR register class `kreg0` can only be used as a clobber, not as an input or output
         asm!("", out("st(2)") _);
         asm!("", out("mm0") _);
         asm!("{}", in(x87_reg) foo);
index f8b024e1acd62c3b7d8891d4cc80ce558a312f63..84b8b5ec2850b77d81505c0b3754e3a20d4f2777 100644 (file)
@@ -64,24 +64,24 @@ error: invalid register `ip`: the instruction pointer cannot be used as an opera
 LL |         asm!("", in("ip") foo);
    |                  ^^^^^^^^^^^^
 
-error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:32:18
-   |
-LL |         asm!("", in("k0") foo);
-   |                  ^^^^^^^^^^^^
-
 error: register class `x87_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:35:18
+  --> $DIR/bad-reg.rs:33:18
    |
 LL |         asm!("", in("st(2)") foo);
    |                  ^^^^^^^^^^^^^^^
 
 error: register class `mmx_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:37:18
+  --> $DIR/bad-reg.rs:35:18
    |
 LL |         asm!("", in("mm0") foo);
    |                  ^^^^^^^^^^^^^
 
+error: register class `kreg0` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:37:18
+   |
+LL |         asm!("", in("k0") foo);
+   |                  ^^^^^^^^^^^^
+
 error: register class `x87_reg` can only be used as a clobber, not as an input or output
   --> $DIR/bad-reg.rs:41:20
    |
index 3d18d9c4125962970e090809b4b12016320b02b1..5e0c8c299891093d2067028a0bd25e7ad30bab06 100644 (file)
@@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
   --> $DIR/async-fn-path-elision.rs:5:20
    |
 LL | async fn error(lt: HasLifetime) {
-   |                    ^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                    ^^^^^^^^^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | async fn error(lt: HasLifetime<'_>) {
+   |                               ++++
 
 error: aborting due to previous error
 
index 8b53408d758e110ef55992fc4f94c42390e4f5cd..d73772e5fa0d9b3616287e11efad261464f9dfbf 100644 (file)
@@ -7,5 +7,5 @@ fn g(_: impl Send) {}
 
 fn main() {
     g(issue_67893::run())
-    //~^ ERROR generator cannot be sent between threads safely
+    //~^ ERROR future cannot be sent between threads safely
 }
index 0aa0d5d7ccdde9c30840aaf7f6239a26d456412b..316b6d06f932ac1189cbbe6370beb920c259a178 100644 (file)
@@ -1,10 +1,22 @@
-error: generator cannot be sent between threads safely
+error: future cannot be sent between threads safely
   --> $DIR/issue-67893.rs:9:7
    |
 LL |     g(issue_67893::run())
-   |       ^^^^^^^^^^^^^^^^^^ generator is not `Send`
+   |       ^^^^^^^^^^^^^^^^^^ future is not `Send`
    |
    = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/auxiliary/issue_67893.rs:9:26
+   |
+LL |     f(*x.lock().unwrap()).await;
+   |        ----------------- ^^^^^^ await occurs here, with `x.lock().unwrap()` maybe used later
+   |        |
+   |        has type `MutexGuard<'_, ()>` which is not `Send`
+note: `x.lock().unwrap()` is later dropped here
+  --> $DIR/auxiliary/issue_67893.rs:9:32
+   |
+LL |     f(*x.lock().unwrap()).await;
+   |                                ^
 note: required by a bound in `g`
   --> $DIR/issue-67893.rs:6:14
    |
index 8f92eeaffd19db4cf60f2a0e6a4a97e75c7025bb..f998c1187d810eb7f73e5631663bb5d7396cb69c 100644 (file)
@@ -13,7 +13,7 @@ error[E0107]: this trait takes 0 generic arguments but 1 generic argument was su
   --> $DIR/issue-87493.rs:8:8
    |
 LL |     T: MyTrait<Assoc == S::Assoc>,
-   |        ^^^^^^^------------------- help: remove these generics
+   |        ^^^^^^^ ----------------- help: replace the generic bound with the associated type: `Assoc = Assoc == S::Assoc`
    |        |
    |        expected 0 generic arguments
    |
index 111d243959a13257b9f9049be77ba4ad96f82ef2..b60bac541f4c815fe892d0a02d491a4cf4d72881 100644 (file)
@@ -119,27 +119,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
                78 00 00 00 ff ff ff ff                         â”‚ x.......
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:92:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-enum.rs:92:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 00 00 00 00                         â”‚ ........
-           }
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:94:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-enum.rs:94:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 00 00 00 00                         â”‚ ........
-           }
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 error: aborting due to 13 previous errors
 
index eee132bae00bc4ab032b3b66ac497cc598c97ac8..1d81e2b3eed86564cf23f96ad99f702a69577dec 100644 (file)
@@ -119,27 +119,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
                78 00 00 00 ff ff ff ff                         â”‚ x.......
            }
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:92:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-enum.rs:92:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 00 00 00 00                         â”‚ ........
-           }
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/ub-enum.rs:94:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/ub-enum.rs:94:77
    |
 LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 8, align: 4) {
-               00 00 00 00 00 00 00 00                         â”‚ ........
-           }
+   |                                                                             ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 error: aborting due to 13 previous errors
 
index e408d8ec072e318c6faa652c31204789affec2e3..86288685303cab71d3d733a3d6cfda0311fead9d 100644 (file)
@@ -90,9 +90,9 @@ enum UninhDiscriminant {
 // All variants are uninhabited but also have data.
 // Use `0` as constant to make behavior endianess-independent.
 const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-//~^ ERROR is undefined behavior
+//~^ ERROR evaluation of constant value failed
 const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-//~^ ERROR is undefined behavior
+//~^ ERROR evaluation of constant value failed
 
 fn main() {
 }
index 7dc1ec865af8a60a371ef1f4c1bd73d5aa0e2479..bbb8511a65410ca89b838f36a7d1871415867cf8 100644 (file)
@@ -10,14 +10,11 @@ LL |     unsafe { std::mem::transmute(()) }
 LL | const FOO: [Empty; 3] = [foo(); 3];
    |                          ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_uninhabited_zsts.rs:16:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/validate_uninhabited_zsts.rs:16:35
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 0, align: 1) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 warning: the type `!` does not permit zero-initialization
   --> $DIR/validate_uninhabited_zsts.rs:4:14
index 7dc1ec865af8a60a371ef1f4c1bd73d5aa0e2479..bbb8511a65410ca89b838f36a7d1871415867cf8 100644 (file)
@@ -10,14 +10,11 @@ LL |     unsafe { std::mem::transmute(()) }
 LL | const FOO: [Empty; 3] = [foo(); 3];
    |                          ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/validate_uninhabited_zsts.rs:16:1
+error[E0080]: evaluation of constant value failed
+  --> $DIR/validate_uninhabited_zsts.rs:16:35
    |
 LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 0, align: 1) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 warning: the type `!` does not permit zero-initialization
   --> $DIR/validate_uninhabited_zsts.rs:4:14
index 346504845561dc5144198bd3ee3881b0ceef390d..990d5a308238ffda3a8baf0ee06805d156a7f43a 100644 (file)
@@ -14,7 +14,7 @@ enum Empty { }
 
 #[warn(const_err)]
 const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-//~^ ERROR it is undefined behavior to use this value
+//~^ ERROR evaluation of constant value failed
 //~| WARN the type `Empty` does not permit zero-initialization
 
 fn main() {
index 840700c9cc6d6526c76de8063a501e21ef27af36..d369fc2a5658b28e3d8ce41d9189084fa4460f89 100644 (file)
@@ -47,4 +47,14 @@ struct Baz<'a, 'b, 'c> {
     //~| HELP remove this lifetime argument
 }
 
+pub trait T {
+    type A;
+    type B;
+}
+
+fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
+    //~^ ERROR this trait takes 0 generic arguments
+    //~| HELP replace the generic bounds with the associated types
+}
+
 fn main() {}
index c90f85df967413b9ffbeae9e271d320ade216124..5ca03b45d82b3851e294cc5d8d62b2fdc6747f41 100644 (file)
@@ -128,6 +128,22 @@ note: struct defined here, with 0 lifetime parameters
 LL | struct Quux<T>(T);
    |        ^^^^
 
-error: aborting due to 9 previous errors
+error[E0107]: this trait takes 0 generic arguments but 2 generic arguments were supplied
+  --> $DIR/E0107.rs:55:27
+   |
+LL | fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
+   |                           ^ expected 0 generic arguments
+   |
+note: trait defined here, with 0 generic parameters
+  --> $DIR/E0107.rs:50:11
+   |
+LL | pub trait T {
+   |           ^
+help: replace the generic bounds with the associated types
+   |
+LL | fn trait_bound_generic<I: T<A = u8, B = u16>>(_i: I) {
+   |                             ~~~~~~  ~~~~~~~
+
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
index 9988acbcb73e198918e324cee34336a730b42374..92305609c835c6248b50d13477d9fd0c0cec387a 100644 (file)
@@ -1,5 +1,6 @@
 // edition:2021
 // run-pass
+// compile-flags: -Zdrop-tracking
 
 #![feature(never_type)]
 
@@ -32,7 +33,7 @@ fn never() -> Never {
 }
 
 async fn includes_never(crash: bool, x: u32) -> u32 {
-    let mut result = async { x * x }.await;
+    let result = async { x * x }.await;
     if !crash {
         return result;
     }
index 317897ae70f72c9037aa5123a067968d2d423605..1792d8db292c47ee798f144a1973477bcb6c1297 100644 (file)
@@ -2,9 +2,17 @@ error[E0261]: use of undeclared lifetime name `'x`
   --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:35
    |
 LL |   fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
-   |        -                          ^^ undeclared lifetime
-   |        |
-   |        help: consider introducing lifetime `'x` here: `<'x>`
+   |                                   ^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'x` lifetime
+   |
+LL |   fn _f(arg : Box<dyn for<'x, 'a> X<Y<'x> = &'a [u32]>>) {}
+   |                           +++
+help: consider introducing lifetime `'x` here
+   |
+LL |   fn _f<'x>(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {}
+   |        ++++
 
 error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types
   --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:33
index bf0ca8715036b130e46c9aa7da8f5d7564e65b1b..a4bb361900fe166f61a1adbc88d2d8af4f7160cb 100644 (file)
@@ -4,14 +4,19 @@ error[E0261]: use of undeclared lifetime name `'b`
 LL |         + Deref<Target = Self::Item<'b>>;
    |                                     ^^ undeclared lifetime
    |
-help: consider introducing lifetime `'b` here
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
    |
-LL | trait Iterable<'b> {
-   |               ++++
+LL |         + for<'b> Deref<Target = Self::Item<'b>>;
+   |           +++++++
 help: consider introducing lifetime `'b` here
    |
 LL |     type Iter<'b, 'a>: Iterator<Item = Self::Item<'a>>
    |               +++
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Iterable<'b> {
+   |               ++++
 
 error[E0261]: use of undeclared lifetime name `'undeclared`
   --> $DIR/generic_associated_type_undeclared_lifetimes.rs:11:41
@@ -21,12 +26,12 @@ LL |     fn iter<'a>(&'a self) -> Self::Iter<'undeclared>;
    |
 help: consider introducing lifetime `'undeclared` here
    |
-LL | trait Iterable<'undeclared> {
-   |               +++++++++++++
-help: consider introducing lifetime `'undeclared` here
-   |
 LL |     fn iter<'undeclared, 'a>(&'a self) -> Self::Iter<'undeclared>;
    |             ++++++++++++
+help: consider introducing lifetime `'undeclared` here
+   |
+LL | trait Iterable<'undeclared> {
+   |               +++++++++++++
 
 error: aborting due to 2 previous errors
 
index e81a5b231a0015f34f267b32f8324f04718bf61e..5725b660ab2342505f0e8aead790ab2081be77e4 100644 (file)
@@ -4,9 +4,9 @@ trait X {
     type Y<'a>;
 }
 
-fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
-  //~^ ERROR: use of undeclared lifetime name `'a`
-  //~| ERROR: use of undeclared lifetime name `'a`
-
+fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+//~^ ERROR: use of undeclared lifetime name `'a`
+//~| ERROR: use of undeclared lifetime name `'a`
+//~| ERROR: the trait `X` cannot be made into an object [E0038]
 
 fn main() {}
index abc02b33e0e6a115635876ba33c9a4cc2f998d4d..8aeda22bad75ffc1a853a844c88ccc78409a6916 100644 (file)
@@ -1,19 +1,50 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/issue-67510.rs:7:21
    |
-LL | fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
-   |     -               ^^ undeclared lifetime
-   |     |
-   |     help: consider introducing lifetime `'a` here: `<'a>`
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |                     ^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL | fn f(x: Box<dyn for<'a> X<Y<'a> = &'a ()>>) {}
+   |                 +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | fn f<'a>(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |     ++++
 
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/issue-67510.rs:7:26
+  --> $DIR/issue-67510.rs:7:28
+   |
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |                            ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL | fn f(x: Box<dyn for<'a> X<Y<'a> = &'a ()>>) {}
+   |                 +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | fn f<'a>(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |     ++++
+
+error[E0038]: the trait `X` cannot be made into an object
+  --> $DIR/issue-67510.rs:7:13
+   |
+LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |             ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-67510.rs:4:10
    |
-LL | fn f(x: Box<dyn X<Y<'a>=&'a ()>>) {}
-   |     -                    ^^ undeclared lifetime
-   |     |
-   |     help: consider introducing lifetime `'a` here: `<'a>`
+LL | trait X {
+   |       - this trait cannot be made into an object...
+LL |     type Y<'a>;
+   |          ^ ...because it contains the generic associated type `Y`
+   = help: consider moving `Y` to another trait
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0038, E0261.
+For more information about an error, try `rustc --explain E0038`.
index ae64f9310d112912fb24bf32deaba3943153d377..448d7ec2873955bb67aaf6b7da37d509c59e3b01 100644 (file)
@@ -12,13 +12,10 @@ impl Document for DocumentImpl {
     type Cursor<'a> = DocCursorImpl<'a>;
 
     fn cursor(&self) -> Self::Cursor<'_> {
-        DocCursorImpl {
-            document: &self,
-        }
+        DocCursorImpl { document: &self }
     }
 }
 
-
 trait DocCursor<'a> {}
 
 struct DocCursorImpl<'a> {
@@ -35,7 +32,6 @@ struct Lexer<'d, Cursor>
     _phantom: std::marker::PhantomData<&'d ()>,
 }
 
-
 impl<'d, Cursor> Lexer<'d, Cursor>
 where
     Cursor: DocCursor<'d>,
@@ -44,15 +40,12 @@ pub fn from<Doc>(document: &'d Doc) -> Lexer<'d, Cursor>
     where
         Doc: Document<Cursor<'d> = Cursor>,
     {
-        Lexer {
-            cursor: document.cursor(),
-            _phantom: std::marker::PhantomData,
-        }
+        Lexer { cursor: document.cursor(), _phantom: std::marker::PhantomData }
     }
 }
 
 fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
-                                       //~^ ERROR: missing lifetime specifier
+    //~^ ERROR: missing lifetime specifier
     DocumentImpl {}
 }
 
index c53dbf63a3c5b98c2891a316cfa2462159fe79ef..c5f59a24057d24747704ea38c570f0d2950ecd87 100644 (file)
@@ -1,5 +1,5 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-70304.rs:54:41
+  --> $DIR/issue-70304.rs:47:41
    |
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
    |                                         ^^ expected named lifetime parameter
index 909848604ec8a5048fad45f055cf8c20ac393d6c..33332e760f5823f3ec4ac018cb8f55426a43f2cb 100644 (file)
@@ -2,7 +2,9 @@ error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/generic-extern-lifetime.rs:6:26
    |
 LL |     pub fn life2<'b>(x: &'a i32, y: &'b i32);
-   |                          ^^ undeclared lifetime
+   |                  -       ^^ undeclared lifetime
+   |                  |
+   |                  help: consider introducing lifetime `'a` here: `'a,`
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/generic-extern-lifetime.rs:8:37
@@ -13,8 +15,12 @@ LL |     pub fn life4<'b>(x: for<'c> fn(&'a i32));
    = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
 help: consider making the type lifetime-generic with a new `'a` lifetime
    |
-LL |     pub fn life4<'b>(x: for<'c, 'a> fn(&'a i32));
-   |                               ++++
+LL |     pub fn life4<'b>(x: for<'a, 'c> fn(&'a i32));
+   |                             +++
+help: consider introducing lifetime `'a` here
+   |
+LL |     pub fn life4<'a, 'b>(x: for<'c> fn(&'a i32));
+   |                  +++
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/generic-extern-lifetime.rs:11:39
@@ -22,11 +28,14 @@ error[E0261]: use of undeclared lifetime name `'a`
 LL |     pub fn life7<'b>() -> for<'c> fn(&'a i32);
    |                                       ^^ undeclared lifetime
    |
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
 help: consider making the type lifetime-generic with a new `'a` lifetime
    |
-LL |     pub fn life7<'b>() -> for<'c, 'a> fn(&'a i32);
-   |                                 ++++
+LL |     pub fn life7<'b>() -> for<'a, 'c> fn(&'a i32);
+   |                               +++
+help: consider introducing lifetime `'a` here
+   |
+LL |     pub fn life7<'a, 'b>() -> for<'c> fn(&'a i32);
+   |                  +++
 
 error: aborting due to 3 previous errors
 
index 90522a885ab90d3df8c8d0f0a905e94645a68dbf..0b7d3f1e851e385785915daa7eee142e45e1bea0 100644 (file)
@@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
   --> $DIR/path-elided.rs:7:18
    |
 LL | impl MyTrait for Foo {
-   |                  ^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                  ^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | impl MyTrait for Foo<'_> {
+   |                     ++++
 
 error: aborting due to previous error
 
index 102d259b0c87ab5e9976df924dce3951c6448e77..c3e76d9cb5a030d3a5fa557df3ae1d6dfdb061ff 100644 (file)
@@ -1,9 +1,8 @@
 #![allow(warnings)]
 
-trait MyTrait<'a> { }
+trait MyTrait<'a> {}
 
-impl MyTrait for u32 {
-    //~^ ERROR implicit elided lifetime not allowed here
-}
+impl MyTrait for u32 {}
+//~^ ERROR implicit elided lifetime not allowed here
 
 fn main() {}
index 15bc3f106b9c48169fed5d56eb8af8fe6307fff0..412bba6be7167a2af0c5ca8cf1d8c7a9daa8b0fb 100644 (file)
@@ -1,10 +1,14 @@
 error[E0726]: implicit elided lifetime not allowed here
   --> $DIR/trait-elided.rs:5:6
    |
-LL | impl MyTrait for u32 {
-   |      ^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
+LL | impl MyTrait for u32 {}
+   |      ^^^^^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | impl MyTrait<'_> for u32 {}
+   |             ++++
 
 error: aborting due to previous error
 
index 020585136856bd35070624c7a0e54bcb44a019fe..0de170161b514a06b0a3576a2ab9c309be34c7a3 100644 (file)
@@ -1,16 +1,20 @@
-trait Serializable<'self, T> { //~ ERROR lifetimes cannot use keyword names
-    fn serialize(val : &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names
-    fn deserialize(repr : &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names
+trait Serializable<'self, T> {
+    //~^ ERROR lifetimes cannot use keyword names
+    fn serialize(val: &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names
+    fn deserialize(repr: &[u8]) -> &'self T; //~ ERROR lifetimes cannot use keyword names
 }
 
-impl<'self> Serializable<str> for &'self str { //~ ERROR lifetimes cannot use keyword names
+impl<'self> Serializable<str> for &'self str {
     //~^ ERROR lifetimes cannot use keyword names
+    //~| ERROR lifetimes cannot use keyword names
     //~| ERROR implicit elided lifetime not allowed here
-    //~| ERROR the size for values of type `str` cannot be known at compilation time
-    fn serialize(val : &'self str) -> Vec<u8> { //~ ERROR lifetimes cannot use keyword names
+    //~| ERROR the size for values of type `str` cannot be known at compilation time [E0277]
+    fn serialize(val: &'self str) -> Vec<u8> {
+        //~^ ERROR lifetimes cannot use keyword names
         vec![1]
     }
-    fn deserialize(repr: &[u8]) -> &'self str { //~ ERROR lifetimes cannot use keyword names
+    fn deserialize(repr: &[u8]) -> &'self str {
+        //~^ ERROR lifetimes cannot use keyword names
         "hi"
     }
 }
index a91b3c90ebb25e3328e26e51faab9e56d3dca5f6..46b9fd541adfa59f07df1d46b90611b4cd2594c1 100644 (file)
@@ -5,51 +5,55 @@ LL | trait Serializable<'self, T> {
    |                    ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:2:25
+  --> $DIR/issue-10412.rs:3:24
    |
-LL |     fn serialize(val : &'self T) -> Vec<u8>;
-   |                         ^^^^^
+LL |     fn serialize(val: &'self T) -> Vec<u8>;
+   |                        ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:3:38
+  --> $DIR/issue-10412.rs:4:37
    |
-LL |     fn deserialize(repr : &[u8]) -> &'self T;
-   |                                      ^^^^^
+LL |     fn deserialize(repr: &[u8]) -> &'self T;
+   |                                     ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:6:6
+  --> $DIR/issue-10412.rs:7:6
    |
 LL | impl<'self> Serializable<str> for &'self str {
    |      ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:6:36
+  --> $DIR/issue-10412.rs:7:36
    |
 LL | impl<'self> Serializable<str> for &'self str {
    |                                    ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:10:25
+  --> $DIR/issue-10412.rs:12:24
    |
-LL |     fn serialize(val : &'self str) -> Vec<u8> {
-   |                         ^^^^^
+LL |     fn serialize(val: &'self str) -> Vec<u8> {
+   |                        ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:13:37
+  --> $DIR/issue-10412.rs:16:37
    |
 LL |     fn deserialize(repr: &[u8]) -> &'self str {
    |                                     ^^^^^
 
 error[E0726]: implicit elided lifetime not allowed here
-  --> $DIR/issue-10412.rs:6:13
+  --> $DIR/issue-10412.rs:7:13
    |
 LL | impl<'self> Serializable<str> for &'self str {
-   |             ^^^^^^^^^^^^^^^^^ help: indicate the anonymous lifetime: `Serializable<'_, str>`
+   |             ^^^^^^^^^^^^^^^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | impl<'self> Serializable<'_, str> for &'self str {
+   |                          +++
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/issue-10412.rs:6:13
+  --> $DIR/issue-10412.rs:7:13
    |
 LL | impl<'self> Serializable<str> for &'self str {
    |             ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
index 1b1912c8e4544d8c03d168914fb4e72cccef0e9b..6ccf008c003e4182b2f0adbd14d5084392e5ce40 100644 (file)
@@ -2,13 +2,17 @@ error: hidden lifetime parameters in types are deprecated
   --> $DIR/issue-91763.rs:8:20
    |
 LL | fn f() -> Ptr<Thing>;
-   |                    ^ expected named lifetime parameter
+   |                    ^ expected lifetime parameter
    |
 note: the lint level is defined here
   --> $DIR/issue-91763.rs:3:9
    |
 LL | #![deny(elided_lifetimes_in_paths)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: indicate the anonymous lifetime
+   |
+LL | fn f() -> Ptr<Thing><'_>;
+   |                     ++++
 
 error: aborting due to previous error
 
index cb459f31cd243fd14eb0683812b1c1b2847ee2b2..0d6ade41511fdcbd8766581e7b922090d1c75079 100644 (file)
@@ -9,6 +9,8 @@ LL |     a: &'b str,
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/undeclared-lifetime-used-in-debug-macro-issue-70152.rs:3:9
    |
+LL | #[derive(Eq, PartialEq)]
+   |          -- lifetime `'b` is missing in item created through this procedural macro
 LL | struct Test {
    |            - help: consider introducing lifetime `'b` here: `<'b>`
 LL |     a: &'b str,
@@ -22,12 +24,12 @@ LL |     fn foo(&'b self) {}
    |
 help: consider introducing lifetime `'b` here
    |
-LL | impl<'b> T for Test {
-   |     ++++
-help: consider introducing lifetime `'b` here
-   |
 LL |     fn foo<'b>(&'b self) {}
    |           ++++
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> T for Test {
+   |     ++++
 
 error: aborting due to 3 previous errors
 
index f5e8b41b1634e5e2b7046af4aab722a0f5c6fefd..ac98b5896ca7bfade498e1ebc03b64a7d1154565 100644 (file)
@@ -2,13 +2,13 @@ warning: hidden lifetime parameters in types are deprecated
   --> $DIR/allowed-by-default-lint.rs:9:12
    |
 LL | fn foo(x: &Foo) {}
-   |            ^^^ expected named lifetime parameter
+   |            ^^^ expected lifetime parameter
    |
    = note: requested on the command line with `--force-warn elided-lifetimes-in-paths`
-help: consider using the `'_` lifetime
+help: indicate the anonymous lifetime
    |
 LL | fn foo(x: &Foo<'_>) {}
-   |            ~~~~~~~
+   |               ++++
 
 warning: 1 warning emitted
 
index b1792e2e9cbf862a1b645cc78d83ebe9d377211a..da1c740c4a3448830b1b634edbb7d61e8537235c 100644 (file)
@@ -19,9 +19,9 @@ pub struct CheaterDetectionMechanism {}
 impl fmt::Debug for CheaterDetectionMechanism {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         //~^ WARN hidden lifetime parameters in types are deprecated
-        //~| NOTE expected named lifetime parameter
+        //~| NOTE expected lifetime parameter
         //~| NOTE explicit anonymous lifetimes aid
-        //~| HELP consider using the `'_` lifetime
+        //~| HELP indicate the anonymous lifetime
         fmt.debug_struct("CheaterDetectionMechanism").finish()
     }
 }
index a692d6af703ea6104c2281f42d68cc5e4928b647..cd8412153f101475ef168d61d5c47a2755249164 100644 (file)
@@ -2,7 +2,9 @@ warning: hidden lifetime parameters in types are deprecated
   --> $DIR/reasons.rs:20:34
    |
 LL |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-   |                                  ^^^^^^^^^ expected named lifetime parameter
+   |                             -----^^^^^^^^^
+   |                             |
+   |                             expected lifetime parameter
    |
    = note: explicit anonymous lifetimes aid reasoning about ownership
 note: the lint level is defined here
@@ -10,10 +12,10 @@ note: the lint level is defined here
    |
 LL | #![warn(elided_lifetimes_in_paths,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-help: consider using the `'_` lifetime
+help: indicate the anonymous lifetime
    |
 LL |     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-   |                                  ~~~~~~~~~~~~~
+   |                                           ++++
 
 warning: variable `Social_exchange_psychology` should have a snake case name
   --> $DIR/reasons.rs:30:9
index d16ba3df47b63de0fa78d120adab7aa840d5b8cd..ba7231070a0f428697d74e17a9b7bf1eda0a0a3e 100644 (file)
@@ -1,3 +1,6 @@
 fn main() {
-    0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a`
+    0.clone::<'a>();
+    //~^ ERROR use of undeclared lifetime name `'a`
+    //~| WARN cannot specify lifetime arguments explicitly if late bound
+    //~| WARN this was previously accepted by the compiler
 }
index c9f235c4f7df7509b14b4aa93e065ec2670e2dc6..78af19586a1b7751168243c4883e2bdf735310a2 100644 (file)
@@ -6,6 +6,21 @@ LL | fn main() {
 LL |     0.clone::<'a>();
    |               ^^ undeclared lifetime
 
-error: aborting due to previous error
+warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/method-call-lifetime-args-unresolved.rs:2:15
+   |
+LL |     0.clone::<'a>();
+   |               ^^
+   |
+  ::: $SRC_DIR/core/src/clone.rs:LL:COL
+   |
+LL |     fn clone(&self) -> Self;
+   |              - the late bound lifetime parameter is introduced here
+   |
+   = note: `#[warn(late_bound_lifetime_arguments)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0261`.
index 730fd99aa68c29c92c2320b3196da7c7a4db019d..da316c6ef5e435c82b61b25b19bfa1ebb9505e08 100644 (file)
@@ -1,5 +1,6 @@
-struct Foo<'static> { //~ ERROR invalid lifetime parameter name: `'static`
-    x: &'static isize
+struct Foo<'static> {
+    //~^ ERROR invalid lifetime parameter name: `'static`
+    x: &'static isize,
 }
 
 fn main() {}
index b8f50a40c45237cdd552f134d68e0b9871e0ad68..7b6ede19341b4953f141faa58f48252bc3f6d3c2 100644 (file)
@@ -23,14 +23,14 @@ fn bar<'a>(x: &'a isize) {
     let y: &'a isize = x;
 
     // &'a is not visible to *items*:
-    type X = Option<&'a isize>; //~ ERROR undeclared lifetime
+    type X = Option<&'a isize>; //~ ERROR can't use generic parameters from outer item
     enum E {
-        E1(&'a isize) //~ ERROR undeclared lifetime
+        E1(&'a isize) //~ ERROR can't use generic parameters from outer item
     }
     struct S {
-        f: &'a isize //~ ERROR undeclared lifetime
+        f: &'a isize //~ ERROR can't use generic parameters from outer item
     }
-    fn f(a: &'a isize) { } //~ ERROR undeclared lifetime
+    fn f(a: &'a isize) { } //~ ERROR can't use generic parameters from outer item
 
     // &'a CAN be declared on functions and used then:
     fn g<'a>(a: &'a isize) { } // OK
index 4399263f716edca6daa667f35237d58778e1af44..532603de5f783f2b8d4939b2977d9f09be01fff7 100644 (file)
@@ -1,19 +1,3 @@
-error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/regions-name-undeclared.rs:28:13
-   |
-LL |     enum E {
-   |           - help: consider introducing lifetime `'a` here: `<'a>`
-LL |         E1(&'a isize)
-   |             ^^ undeclared lifetime
-
-error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/regions-name-undeclared.rs:31:13
-   |
-LL |     struct S {
-   |             - help: consider introducing lifetime `'a` here: `<'a>`
-LL |         f: &'a isize
-   |             ^^ undeclared lifetime
-
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:16:24
    |
@@ -22,12 +6,12 @@ LL |     fn m4(&self, arg: &'b isize) { }
    |
 help: consider introducing lifetime `'b` here
    |
-LL | impl<'b, 'a> Foo<'a> {
-   |      +++
-help: consider introducing lifetime `'b` here
-   |
 LL |     fn m4<'b>(&self, arg: &'b isize) { }
    |          ++++
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      +++
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:17:12
@@ -37,12 +21,12 @@ LL |     fn m5(&'b self) { }
    |
 help: consider introducing lifetime `'b` here
    |
-LL | impl<'b, 'a> Foo<'a> {
-   |      +++
-help: consider introducing lifetime `'b` here
-   |
 LL |     fn m5<'b>(&'b self) { }
    |          ++++
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      +++
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:18:27
@@ -52,26 +36,54 @@ LL |     fn m6(&self, arg: Foo<'b>) { }
    |
 help: consider introducing lifetime `'b` here
    |
-LL | impl<'b, 'a> Foo<'a> {
-   |      +++
-help: consider introducing lifetime `'b` here
-   |
 LL |     fn m6<'b>(&self, arg: Foo<'b>) { }
    |          ++++
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b, 'a> Foo<'a> {
+   |      +++
 
-error[E0261]: use of undeclared lifetime name `'a`
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/regions-name-undeclared.rs:26:22
    |
+LL | fn bar<'a>(x: &'a isize) {
+   |        -- lifetime parameter from outer item
+...
 LL |     type X = Option<&'a isize>;
-   |           -          ^^ undeclared lifetime
+   |           -          ^^ use of generic parameter from outer item
    |           |
    |           help: consider introducing lifetime `'a` here: `<'a>`
 
-error[E0261]: use of undeclared lifetime name `'a`
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/regions-name-undeclared.rs:28:13
+   |
+LL | fn bar<'a>(x: &'a isize) {
+   |        -- lifetime parameter from outer item
+...
+LL |     enum E {
+   |           - help: consider introducing lifetime `'a` here: `<'a>`
+LL |         E1(&'a isize)
+   |             ^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
+  --> $DIR/regions-name-undeclared.rs:31:13
+   |
+LL | fn bar<'a>(x: &'a isize) {
+   |        -- lifetime parameter from outer item
+...
+LL |     struct S {
+   |             - help: consider introducing lifetime `'a` here: `<'a>`
+LL |         f: &'a isize
+   |             ^^ use of generic parameter from outer item
+
+error[E0401]: can't use generic parameters from outer item
   --> $DIR/regions-name-undeclared.rs:33:14
    |
+LL | fn bar<'a>(x: &'a isize) {
+   |        -- lifetime parameter from outer item
+...
 LL |     fn f(a: &'a isize) { }
-   |         -    ^^ undeclared lifetime
+   |         -    ^^ use of generic parameter from outer item
    |         |
    |         help: consider introducing lifetime `'a` here: `<'a>`
 
@@ -90,14 +102,14 @@ LL | ...                   &'b isize,
    |                        ^^ undeclared lifetime
    |
    = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |             b: Box<dyn for<'b, 'a> FnOnce(&'a isize,
+   |                            +++
 help: consider introducing lifetime `'b` here
    |
 LL | fn fn_types<'b>(a: &'a isize,
    |            ++++
-help: consider making the bound lifetime-generic with a new `'b` lifetime
-   |
-LL |             b: Box<dyn for<'a, 'b> FnOnce(&'a isize,
-   |                              ++++
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/regions-name-undeclared.rs:46:36
@@ -105,15 +117,14 @@ error[E0261]: use of undeclared lifetime name `'b`
 LL | ...                   &'b isize)>,
    |                        ^^ undeclared lifetime
    |
-   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |             b: Box<dyn for<'b, 'a> FnOnce(&'a isize,
+   |                            +++
 help: consider introducing lifetime `'b` here
    |
 LL | fn fn_types<'b>(a: &'a isize,
    |            ++++
-help: consider making the bound lifetime-generic with a new `'b` lifetime
-   |
-LL |             b: Box<dyn for<'a, 'b> FnOnce(&'a isize,
-   |                              ++++
 
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/regions-name-undeclared.rs:47:17
@@ -132,13 +143,14 @@ LL |     async fn buggy(&self) -> &'a str {
    |
 help: consider introducing lifetime `'a` here
    |
-LL | impl<'a> Bug {
-   |     ++++
-help: consider introducing lifetime `'a` here
-   |
 LL |     async fn buggy<'a>(&self) -> &'a str {
    |                   ++++
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> Bug {
+   |     ++++
 
 error: aborting due to 12 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0401.
+For more information about an error, try `rustc --explain E0261`.
index 6d389a1317a9fa2f4efa45870520388a9cc4b80d..364c8c8f7069e9e7a98b621ef5719bccde8c45d1 100644 (file)
@@ -1,5 +1,5 @@
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/rfc1623.rs:36:8
+  --> $DIR/rfc1623.rs:32:8
    |
 LL |     f: &id,
    |        ^^^ implementation of `FnOnce` is not general enough
index f85b6ff8ff75b2a0431d8e43e50ce0fe97a4bb55..2eff4708547d80acac58f3492a104d421b1f7818 100644 (file)
@@ -1,63 +1,35 @@
 error[E0308]: mismatched types
-  --> $DIR/rfc1623.rs:29:35
+  --> $DIR/rfc1623.rs:32:8
    |
-LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
-   |  ___________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | };
-   | |_^ one type is more general than the other
+LL |     f: &id,
+   |        ^^^ one type is more general than the other
    |
    = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
               found type `Fn<(&Foo<'_>,)>`
 
 error[E0308]: mismatched types
-  --> $DIR/rfc1623.rs:29:35
+  --> $DIR/rfc1623.rs:32:8
    |
-LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
-   |  ___________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | };
-   | |_^ one type is more general than the other
+LL |     f: &id,
+   |        ^^^ one type is more general than the other
    |
    = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
               found type `Fn<(&Foo<'_>,)>`
 
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/rfc1623.rs:29:35
+  --> $DIR/rfc1623.rs:32:8
    |
-LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
-   |  ___________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | };
-   | |_^ implementation of `FnOnce` is not general enough
+LL |     f: &id,
+   |        ^^^ implementation of `FnOnce` is not general enough
    |
    = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
 
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/rfc1623.rs:29:35
+  --> $DIR/rfc1623.rs:32:8
    |
-LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
-   |  ___________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | };
-   | |_^ implementation of `FnOnce` is not general enough
+LL |     f: &id,
+   |        ^^^ implementation of `FnOnce` is not general enough
    |
    = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
    = note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
index 0e9d2140324256dbdcccab92e0fb3c9837ba5335..443da0aa955f982755b4300fc2732719984713ab 100644 (file)
@@ -27,14 +27,14 @@ fn id<T>(t: T) -> T {
 }
 
 static SOME_STRUCT: &SomeStruct = &SomeStruct {
-    //[nll]~^ ERROR mismatched types
-    //[nll]~| ERROR mismatched types
-    //[nll]~| ERROR implementation of `FnOnce` is not general enough
-    //[nll]~| ERROR implementation of `FnOnce` is not general enough
     foo: &Foo { bools: &[false, true] },
     bar: &Bar { bools: &[true, true] },
     f: &id,
     //[base]~^ ERROR implementation of `FnOnce` is not general enough
+    //[nll]~^^ ERROR mismatched types
+    //[nll]~| ERROR mismatched types
+    //[nll]~| ERROR implementation of `FnOnce` is not general enough
+    //[nll]~| ERROR implementation of `FnOnce` is not general enough
 };
 
 // very simple test for a 'static static with default lifetime
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.base.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.base.stderr
new file mode 100644 (file)
index 0000000..7985bf2
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:52
+   |
+LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+   |                                    ----     ----   ^ ...but data from `f` is returned here
+   |                                    |
+   |                                    this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:82
+   |
+LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |                                     ----              -----------------          ^ ...but data from `f` is returned here
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
+   |
+LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+   |                                               ------     ---   ^^^ ...but data from `arg` is returned here
+   |                                               |
+   |                                               this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index 57374b7e3bb277d9e9c1bfe9010935e8bf57f43a..8a55a7c34d77ba44ef7a4f50b2489cbb14148878 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:52
    |
 LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |                          -         -               ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
@@ -8,7 +8,7 @@ LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |                          let's call the lifetime of this reference `'2`
 
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:75
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:75
    |
 LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
    |                          -          -                                     ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
@@ -17,7 +17,7 @@ LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (
    |                          let's call the lifetime of this reference `'2`
 
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
    |
 LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
    |                  --              -                             ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
index f42337d53406216a492778bf9691a8c4306b8b17..c54f7963c231c8223d09bd65eb096cbee6b55a86 100644 (file)
@@ -1,4 +1,7 @@
 // edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 use std::pin::Pin;
 
@@ -6,15 +9,19 @@
 
 impl Foo {
     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-    //~^ ERROR lifetime mismatch
+    //[base]~^ ERROR lifetime mismatch
+    //[nll]~^^ lifetime may not live long enough
 
     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-    //~^ ERROR lifetime mismatch
+    //[base]~^ ERROR lifetime mismatch
+    //[nll]~^^ lifetime may not live long enough
 }
 
 type Alias<T> = Pin<T>;
 impl Foo {
-    async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
+    async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+    //[base]~^ ERROR E0623
+    //[nll]~^^ lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
deleted file mode 100644 (file)
index 299a2d2..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
-   |
-LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-   |                                    ----     ----   ^ ...but data from `f` is returned here
-   |                                    |
-   |                                    this parameter and the return type are declared with different lifetimes...
-
-error[E0623]: lifetime mismatch
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82
-   |
-LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |                                     ----              -----------------          ^ ...but data from `f` is returned here
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
-
-error[E0623]: lifetime mismatch
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
-   |
-LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-   |                                               ------     ---   ^^^ ...but data from `arg` is returned here
-   |                                               |
-   |                                               this parameter and the return type are declared with different lifetimes...
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.base.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.base.stderr
new file mode 100644 (file)
index 0000000..c0e2f0b
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:46
+   |
+LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+   |                              ----     ----   ^ ...but data from `f` is returned here
+   |                              |
+   |                              this parameter and the return type are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+   |         ++++            ++           ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:76
+   |
+LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |                               ----              -----------------          ^ ...but data from `f` is returned here
+   |                               |
+   |                               this parameter and the return type are declared with different lifetimes...
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |         ++++            ++            ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:58
+   |
+LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+   |                                         ------     ---   ^^^ ...but data from `arg` is returned here
+   |                                         |
+   |                                         this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index 92241b2fb2dc1a0730c99bf5b1ac18af6c00e08b..b06ebf70477378344d4afc6c50ebca9dada1940f 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:46
    |
 LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |                    -         -               ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
@@ -8,7 +8,7 @@ LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
    |                    let's call the lifetime of this reference `'2`
 
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:69
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:69
    |
 LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
    |                    -          -                                     ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
@@ -17,7 +17,7 @@ LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self,
    |                    let's call the lifetime of this reference `'2`
 
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:58
    |
 LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
    |            --  ---- has type `Pin<&'1 Foo>`              ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
index 8291e44080b37dc4993e1971a4ab8f5a38477b92..34b08b364fb5db9d0be509f1a07e9cfb08051d6b 100644 (file)
@@ -1,16 +1,26 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 use std::pin::Pin;
 
 struct Foo;
 
 impl Foo {
-    fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0623
+    fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+    //[base]~^ ERROR E0623
+    //[nll]~^^ lifetime may not live long enough
 
-    fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } //~ ERROR E0623
+    fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+    //[base]~^ ERROR E0623
+    //[nll]~^^ lifetime may not live long enough
 }
 
 type Alias<T> = Pin<T>;
 impl Foo {
-    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
+    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+    //[base]~^ ERROR E0623
+    //[nll]~^^ lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
deleted file mode 100644 (file)
index 64a5746..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46
-   |
-LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-   |                              ----     ----   ^ ...but data from `f` is returned here
-   |                              |
-   |                              this parameter and the return type are declared with different lifetimes...
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
-   |         ++++            ++           ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:76
-   |
-LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |                               ----              -----------------          ^ ...but data from `f` is returned here
-   |                               |
-   |                               this parameter and the return type are declared with different lifetimes...
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |         ++++            ++            ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58
-   |
-LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-   |                                         ------     ---   ^^^ ...but data from `arg` is returned here
-   |                                         |
-   |                                         this parameter and the return type are declared with different lifetimes...
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/lt-ref-self-async.base.stderr b/src/test/ui/self/elision/lt-ref-self-async.base.stderr
new file mode 100644 (file)
index 0000000..b438549
--- /dev/null
@@ -0,0 +1,63 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self-async.rs:16:9
+   |
+LL |     async fn ref_self(&self, f: &u32) -> &u32 {
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self-async.rs:24:9
+   |
+LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
+   |                                       ----     ----
+   |                                       |
+   |                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self-async.rs:30:9
+   |
+LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self-async.rs:36:9
+   |
+LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self-async.rs:42:9
+   |
+LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self-async.rs:48:9
+   |
+LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+   |                                                     ----     ----
+   |                                                     |
+   |                                                     this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index c10b8824e6d63d6d36114d92016d1dab9f5025f2..2ba9a6596f62d8249e5db98c48b7eae77a806d47 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:13:9
+  --> $DIR/lt-ref-self-async.rs:16:9
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:19:9
+  --> $DIR/lt-ref-self-async.rs:24:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             -         - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:23:9
+  --> $DIR/lt-ref-self-async.rs:30:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     -          - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:27:9
+  --> $DIR/lt-ref-self-async.rs:36:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     -          - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:31:9
+  --> $DIR/lt-ref-self-async.rs:42:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             -           - let's call the lifetime of this reference `'1`
@@ -49,7 +49,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:35:9
+  --> $DIR/lt-ref-self-async.rs:48:9
    |
 LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                         -           - let's call the lifetime of this reference `'1`
index ef6cbe7772c276cb7960840beda83782113b09f3..24482b3a2787b19a4b5445a6fe5718037c5305b4 100644 (file)
@@ -1,4 +1,7 @@
 // edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 #![allow(non_snake_case)]
 
@@ -10,29 +13,41 @@ impl<'a> Struct<'a> {
     // Test using `&self` sugar:
 
     async fn ref_self(&self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     // Test using `&Self` explicitly:
 
     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/lt-ref-self-async.stderr b/src/test/ui/self/elision/lt-ref-self-async.stderr
deleted file mode 100644 (file)
index 7448e84..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self-async.rs:13:9
-   |
-LL |     async fn ref_self(&self, f: &u32) -> &u32 {
-   |                                 ----     ----
-   |                                 |
-   |                                 this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self-async.rs:19:9
-   |
-LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
-   |                                       ----     ----
-   |                                       |
-   |                                       this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self-async.rs:23:9
-   |
-LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-   |                                                ----     ----
-   |                                                |
-   |                                                this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self-async.rs:27:9
-   |
-LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-   |                                                ----     ----
-   |                                                |
-   |                                                this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self-async.rs:31:9
-   |
-LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-   |                                                         ----     ----
-   |                                                         |
-   |                                                         this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self-async.rs:35:9
-   |
-LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-   |                                                     ----     ----
-   |                                                     |
-   |                                                     this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/lt-ref-self.base.stderr b/src/test/ui/self/elision/lt-ref-self.base.stderr
new file mode 100644 (file)
index 0000000..0f5cd6f
--- /dev/null
@@ -0,0 +1,99 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:15:9
+   |
+LL |     fn ref_self(&self, f: &u32) -> &u32 {
+   |                           ----     ----
+   |                           |
+   |                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                ++++  ++           ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:23:9
+   |
+LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                ++++        ++           ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:29:9
+   |
+LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+   |                                          ----     ----
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++            ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:35:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                                          ----     ----
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++            ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:41:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+   |                                                   ----     ----
+   |                                                   |
+   |                                                   this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                        ++++                ++             ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/lt-ref-self.rs:47:9
+   |
+LL |     fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+   |                                               ----     ----
+   |                                               |
+   |                                               this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                    ++++                ++             ++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index e2de743b8f63eb1aaf7f08432d56b33e9dd4b9f4..1934207527b9cd9e56c5e066b9b8db08dd6d8d14 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:11:9
+  --> $DIR/lt-ref-self.rs:15:9
    |
 LL |     fn ref_self(&self, f: &u32) -> &u32 {
    |                 -         - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:17:9
+  --> $DIR/lt-ref-self.rs:23:9
    |
 LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:21:9
+  --> $DIR/lt-ref-self.rs:29:9
    |
 LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:25:9
+  --> $DIR/lt-ref-self.rs:35:9
    |
 LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:29:9
+  --> $DIR/lt-ref-self.rs:41:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -49,7 +49,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:33:9
+  --> $DIR/lt-ref-self.rs:47:9
    |
 LL |     fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                   -           - let's call the lifetime of this reference `'1`
index 423c7d5822df7389ba8fbf39210a39672caa30d9..62bdb13dc0f95dd1e5ab2ad7a4f9b326c39a0601 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 #![allow(non_snake_case)]
 
 use std::pin::Pin;
@@ -8,29 +12,41 @@ impl<'a> Struct<'a> {
     // Test using `&self` sugar:
 
     fn ref_self(&self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     // Test using `&Self` explicitly:
 
     fn ref_Self(self: &Self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/lt-ref-self.stderr b/src/test/ui/self/elision/lt-ref-self.stderr
deleted file mode 100644 (file)
index 5764ab0..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self.rs:11:9
-   |
-LL |     fn ref_self(&self, f: &u32) -> &u32 {
-   |                           ----     ----
-   |                           |
-   |                           this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
-   |                ++++  ++           ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self.rs:17:9
-   |
-LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
-   |                                 ----     ----
-   |                                 |
-   |                                 this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
-   |                ++++        ++           ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self.rs:21:9
-   |
-LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-   |                                          ----     ----
-   |                                          |
-   |                                          this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self.rs:25:9
-   |
-LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-   |                                          ----     ----
-   |                                          |
-   |                                          this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self.rs:29:9
-   |
-LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-   |                                                   ----     ----
-   |                                                   |
-   |                                                   this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/lt-ref-self.rs:33:9
-   |
-LL |     fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-   |                                               ----     ----
-   |                                               |
-   |                                               this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
-   |                    ++++                ++             ++
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/ref-mut-self-async.base.stderr b/src/test/ui/self/elision/ref-mut-self-async.base.stderr
new file mode 100644 (file)
index 0000000..8513375
--- /dev/null
@@ -0,0 +1,63 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self-async.rs:16:9
+   |
+LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
+   |                                     ----     ----
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self-async.rs:24:9
+   |
+LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+   |                                           ----     ----
+   |                                           |
+   |                                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self-async.rs:30:9
+   |
+LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self-async.rs:36:9
+   |
+LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self-async.rs:42:9
+   |
+LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self-async.rs:48:9
+   |
+LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index 19496a5ef6d326eaf10b8e28f00e12615cdf88be..cdd464039cda0501162c7a8f20439f4e9bebbbf6 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self-async.rs:13:9
+  --> $DIR/ref-mut-self-async.rs:16:9
    |
 LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
    |                       -             - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self-async.rs:19:9
+  --> $DIR/ref-mut-self-async.rs:24:9
    |
 LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                             -             - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self-async.rs:23:9
+  --> $DIR/ref-mut-self-async.rs:30:9
    |
 LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                                     -              - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self-async.rs:27:9
+  --> $DIR/ref-mut-self-async.rs:36:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                                     -              - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self-async.rs:31:9
+  --> $DIR/ref-mut-self-async.rs:42:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                             -               - let's call the lifetime of this reference `'1`
@@ -49,7 +49,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self-async.rs:35:9
+  --> $DIR/ref-mut-self-async.rs:48:9
    |
 LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                             -               - let's call the lifetime of this reference `'1`
index 1e65605036d6f0b12ed49876184fc1886cbbb510..59b41f364f9a1bf7dd9110d6cbfbda0a1e113f2d 100644 (file)
@@ -1,4 +1,7 @@
 // edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 #![allow(non_snake_case)]
 
@@ -10,29 +13,41 @@ impl Struct {
     // Test using `&mut self` sugar:
 
     async fn ref_self(&mut self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     // Test using `&mut Self` explicitly:
 
     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/ref-mut-self-async.stderr b/src/test/ui/self/elision/ref-mut-self-async.stderr
deleted file mode 100644 (file)
index 6056cc4..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self-async.rs:13:9
-   |
-LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
-   |                                     ----     ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self-async.rs:19:9
-   |
-LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
-   |                                           ----     ----
-   |                                           |
-   |                                           this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self-async.rs:23:9
-   |
-LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
-   |                                                    ----     ----
-   |                                                    |
-   |                                                    this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self-async.rs:27:9
-   |
-LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
-   |                                                    ----     ----
-   |                                                    |
-   |                                                    this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self-async.rs:31:9
-   |
-LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
-   |                                                             ----     ----
-   |                                                             |
-   |                                                             this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self-async.rs:35:9
-   |
-LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
-   |                                                             ----     ----
-   |                                                             |
-   |                                                             this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/ref-mut-self.base.stderr b/src/test/ui/self/elision/ref-mut-self.base.stderr
new file mode 100644 (file)
index 0000000..fcedddd
--- /dev/null
@@ -0,0 +1,99 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:15:9
+   |
+LL |     fn ref_self(&mut self, f: &u32) -> &u32 {
+   |                               ----     ----
+   |                               |
+   |                               this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+   |                ++++  ++               ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:23:9
+   |
+LL |     fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+   |                                     ----     ----
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+   |                ++++        ++               ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:29:9
+   |
+LL |     fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+   |                                              ----     ----
+   |                                              |
+   |                                              this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++                ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:35:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+   |                                              ----     ----
+   |                                              |
+   |                                              this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++                ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:41:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+   |                                                       ----     ----
+   |                                                       |
+   |                                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                        ++++                ++                 ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-self.rs:47:9
+   |
+LL |     fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+   |                                                       ----     ----
+   |                                                       |
+   |                                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+   |                        ++++                ++                 ++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index 94bfc5f4a818693776b35b4fc60e72b399d87f85..f1f4d341b2bd8ac45b464f39bffde6380271ae99 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:11:9
+  --> $DIR/ref-mut-self.rs:15:9
    |
 LL |     fn ref_self(&mut self, f: &u32) -> &u32 {
    |                 -             - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:17:9
+  --> $DIR/ref-mut-self.rs:23:9
    |
 LL |     fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                       -             - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:21:9
+  --> $DIR/ref-mut-self.rs:29:9
    |
 LL |     fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                               -              - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:25:9
+  --> $DIR/ref-mut-self.rs:35:9
    |
 LL |     fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                               -              - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:29:9
+  --> $DIR/ref-mut-self.rs:41:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                       -               - let's call the lifetime of this reference `'1`
@@ -49,7 +49,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:33:9
+  --> $DIR/ref-mut-self.rs:47:9
    |
 LL |     fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                       -               - let's call the lifetime of this reference `'1`
index 8d9359dbd94b571c369a8cc34c20c1df2b514b67..81bd279129d2b0160f934bb672d38a3b2002879a 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 #![allow(non_snake_case)]
 
 use std::pin::Pin;
@@ -8,29 +12,41 @@ impl Struct {
     // Test using `&mut self` sugar:
 
     fn ref_self(&mut self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     // Test using `&mut Self` explicitly:
 
     fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/ref-mut-self.stderr b/src/test/ui/self/elision/ref-mut-self.stderr
deleted file mode 100644 (file)
index 416719a..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self.rs:11:9
-   |
-LL |     fn ref_self(&mut self, f: &u32) -> &u32 {
-   |                               ----     ----
-   |                               |
-   |                               this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
-   |                ++++  ++               ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self.rs:17:9
-   |
-LL |     fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
-   |                                     ----     ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
-   |                ++++        ++               ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self.rs:21:9
-   |
-LL |     fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
-   |                                              ----     ----
-   |                                              |
-   |                                              this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++                ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self.rs:25:9
-   |
-LL |     fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
-   |                                              ----     ----
-   |                                              |
-   |                                              this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++                ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self.rs:29:9
-   |
-LL |     fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
-   |                                                       ----     ----
-   |                                                       |
-   |                                                       this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++                 ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-self.rs:33:9
-   |
-LL |     fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
-   |                                                       ----     ----
-   |                                                       |
-   |                                                       this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++                 ++
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/ref-mut-struct-async.base.stderr b/src/test/ui/self/elision/ref-mut-struct-async.base.stderr
new file mode 100644 (file)
index 0000000..0de11c2
--- /dev/null
@@ -0,0 +1,53 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct-async.rs:16:9
+   |
+LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+   |                                               ----     ----
+   |                                               |
+   |                                               this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct-async.rs:22:9
+   |
+LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+   |                                                        ----     ----
+   |                                                        |
+   |                                                        this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct-async.rs:28:9
+   |
+LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+   |                                                        ----     ----
+   |                                                        |
+   |                                                        this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct-async.rs:34:9
+   |
+LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+   |                                                                 ----     ----
+   |                                                                 |
+   |                                                                 this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct-async.rs:40:9
+   |
+LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+   |                                                                 ----     ----
+   |                                                                 |
+   |                                                                 this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index 94671c7c87a5e516113ea7a986bf366ba70f3130..0ef410c8df1eb1c0479b10f3bd543026310e25bf 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct-async.rs:13:9
+  --> $DIR/ref-mut-struct-async.rs:16:9
    |
 LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                               -               - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct-async.rs:17:9
+  --> $DIR/ref-mut-struct-async.rs:22:9
    |
 LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                       -                - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct-async.rs:21:9
+  --> $DIR/ref-mut-struct-async.rs:28:9
    |
 LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                       -                - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct-async.rs:25:9
+  --> $DIR/ref-mut-struct-async.rs:34:9
    |
 LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
    |                                               -                 - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct-async.rs:29:9
+  --> $DIR/ref-mut-struct-async.rs:40:9
    |
 LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
    |                                               -                 - let's call the lifetime of this reference `'1`
index 990f485907f8ec70cc9b534e13463af17c7b810b..7448988355c9ef6bb1d63614e7da9c01d66a5c0a 100644 (file)
@@ -1,4 +1,7 @@
 // edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 #![allow(non_snake_case)]
 
@@ -10,23 +13,33 @@ impl Struct {
     // Test using `&mut Struct` explicitly:
 
     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/ref-mut-struct-async.stderr b/src/test/ui/self/elision/ref-mut-struct-async.stderr
deleted file mode 100644 (file)
index 61034ae..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct-async.rs:13:9
-   |
-LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
-   |                                               ----     ----
-   |                                               |
-   |                                               this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct-async.rs:17:9
-   |
-LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
-   |                                                        ----     ----
-   |                                                        |
-   |                                                        this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct-async.rs:21:9
-   |
-LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
-   |                                                        ----     ----
-   |                                                        |
-   |                                                        this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct-async.rs:25:9
-   |
-LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
-   |                                                                 ----     ----
-   |                                                                 |
-   |                                                                 this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct-async.rs:29:9
-   |
-LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
-   |                                                                 ----     ----
-   |                                                                 |
-   |                                                                 this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/ref-mut-struct.base.stderr b/src/test/ui/self/elision/ref-mut-struct.base.stderr
new file mode 100644 (file)
index 0000000..a01492f
--- /dev/null
@@ -0,0 +1,83 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:15:9
+   |
+LL |     fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+   |                                         ----     ----
+   |                                         |
+   |                                         this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+   |                  ++++        ++                 ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:21:9
+   |
+LL |     fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+   |                                                  ----     ----
+   |                                                  |
+   |                                                  this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                      ++++            ++                  ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:27:9
+   |
+LL |     fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+   |                                                  ----     ----
+   |                                                  |
+   |                                                  this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+   |                      ++++            ++                  ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:33:9
+   |
+LL |     fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+   |                                                           ----     ----
+   |                                                           |
+   |                                                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                          ++++                ++                   ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-mut-struct.rs:39:9
+   |
+LL |     fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+   |                                                           ----     ----
+   |                                                           |
+   |                                                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+   |                          ++++                ++                   ++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index c9e7479ea5dff46a2154088e44e1c877a74837c5..de7eb02d7a7fe38e82f341d056cf512d08ffa806 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:11:9
+  --> $DIR/ref-mut-struct.rs:15:9
    |
 LL |     fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                         -               - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:15:9
+  --> $DIR/ref-mut-struct.rs:21:9
    |
 LL |     fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                 -                - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:19:9
+  --> $DIR/ref-mut-struct.rs:27:9
    |
 LL |     fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                 -                - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:23:9
+  --> $DIR/ref-mut-struct.rs:33:9
    |
 LL |     fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
    |                                         -                 - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:27:9
+  --> $DIR/ref-mut-struct.rs:39:9
    |
 LL |     fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
    |                                         -                 - let's call the lifetime of this reference `'1`
index 05e275b19e4c414d6cb422eed2a4db9ff9c769b6..72674bd65b66a8fd53ce042f7debb3a8f9a06280 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 #![allow(non_snake_case)]
 
 use std::pin::Pin;
@@ -8,23 +12,33 @@ impl Struct {
     // Test using `&mut Struct` explicitly:
 
     fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/ref-mut-struct.stderr b/src/test/ui/self/elision/ref-mut-struct.stderr
deleted file mode 100644 (file)
index 6ca9ab1..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct.rs:11:9
-   |
-LL |     fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
-   |                                         ----     ----
-   |                                         |
-   |                                         this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
-   |                  ++++        ++                 ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct.rs:15:9
-   |
-LL |     fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
-   |                                                  ----     ----
-   |                                                  |
-   |                                                  this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++                  ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct.rs:19:9
-   |
-LL |     fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
-   |                                                  ----     ----
-   |                                                  |
-   |                                                  this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++                  ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct.rs:23:9
-   |
-LL |     fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
-   |                                                           ----     ----
-   |                                                           |
-   |                                                           this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++                   ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-mut-struct.rs:27:9
-   |
-LL |     fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
-   |                                                           ----     ----
-   |                                                           |
-   |                                                           this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++                   ++
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/ref-self-async.base.stderr b/src/test/ui/self/elision/ref-self-async.base.stderr
new file mode 100644 (file)
index 0000000..fa13b69
--- /dev/null
@@ -0,0 +1,73 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self-async.rs:26:9
+   |
+LL |     async fn ref_self(&self, f: &u32) -> &u32 {
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self-async.rs:34:9
+   |
+LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
+   |                                       ----     ----
+   |                                       |
+   |                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self-async.rs:40:9
+   |
+LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self-async.rs:46:9
+   |
+LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self-async.rs:52:9
+   |
+LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self-async.rs:58:9
+   |
+LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self-async.rs:64:9
+   |
+LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+   |                                                             ---     ---
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index bd1f80811b5425748ffe18cf90ff1e3c70f5136a..77faaa866505fb1ae5d8e74ab9a88faa6390b901 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-self-async.rs:23:9
+  --> $DIR/ref-self-async.rs:26:9
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self-async.rs:29:9
+  --> $DIR/ref-self-async.rs:34:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             -         - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self-async.rs:33:9
+  --> $DIR/ref-self-async.rs:40:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     -          - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self-async.rs:37:9
+  --> $DIR/ref-self-async.rs:46:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     -          - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self-async.rs:41:9
+  --> $DIR/ref-self-async.rs:52:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             -           - let's call the lifetime of this reference `'1`
@@ -49,7 +49,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self-async.rs:45:9
+  --> $DIR/ref-self-async.rs:58:9
    |
 LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                             -           - let's call the lifetime of this reference `'1`
@@ -59,7 +59,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self-async.rs:49:9
+  --> $DIR/ref-self-async.rs:64:9
    |
 LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                            -                - let's call the lifetime of this reference `'1`
index 0fbbd95c975d6afb2ea35b35033a5480eabeba99..afe5fe100e36ca10c92c0e75bc320c9ea219dc75 100644 (file)
@@ -1,4 +1,7 @@
 // edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 #![allow(non_snake_case)]
 #![feature(arbitrary_self_types)]
@@ -20,33 +23,47 @@ impl Struct {
     // Test using `&self` sugar:
 
     async fn ref_self(&self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     // Test using `&Self` explicitly:
 
     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/ref-self-async.stderr b/src/test/ui/self/elision/ref-self-async.stderr
deleted file mode 100644 (file)
index 0eab16e..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self-async.rs:23:9
-   |
-LL |     async fn ref_self(&self, f: &u32) -> &u32 {
-   |                                 ----     ----
-   |                                 |
-   |                                 this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self-async.rs:29:9
-   |
-LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
-   |                                       ----     ----
-   |                                       |
-   |                                       this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self-async.rs:33:9
-   |
-LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-   |                                                ----     ----
-   |                                                |
-   |                                                this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self-async.rs:37:9
-   |
-LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-   |                                                ----     ----
-   |                                                |
-   |                                                this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self-async.rs:41:9
-   |
-LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-   |                                                         ----     ----
-   |                                                         |
-   |                                                         this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self-async.rs:45:9
-   |
-LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-   |                                                         ----     ----
-   |                                                         |
-   |                                                         this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self-async.rs:49:9
-   |
-LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
-   |                                                             ---     ---
-   |                                                             |
-   |                                                             this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/ref-self.base.stderr b/src/test/ui/self/elision/ref-self.base.stderr
new file mode 100644 (file)
index 0000000..8bd194d
--- /dev/null
@@ -0,0 +1,115 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:25:9
+   |
+LL |     fn ref_self(&self, f: &u32) -> &u32 {
+   |                           ----     ----
+   |                           |
+   |                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+   |                ++++  ++           ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:33:9
+   |
+LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+   |                ++++        ++           ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:39:9
+   |
+LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+   |                                          ----     ----
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++            ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:45:9
+   |
+LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+   |                                          ----     ----
+   |                                          |
+   |                                          this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+   |                    ++++            ++            ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:51:9
+   |
+LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+   |                                                   ----     ----
+   |                                                   |
+   |                                                   this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+   |                        ++++                ++             ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:57:9
+   |
+LL |     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+   |                                                   ----     ----
+   |                                                   |
+   |                                                   this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+   |                        ++++                ++             ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-self.rs:63:9
+   |
+LL |     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+   |                                                       ---     ---
+   |                                                       |
+   |                                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+   |                          ++++             ++                  ++
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index d1fd209102e6952454549b03a34501e1b54ca321..f2b7b0ad019570965bfae7026292e79d121ac51c 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:21:9
+  --> $DIR/ref-self.rs:25:9
    |
 LL |     fn ref_self(&self, f: &u32) -> &u32 {
    |                 -         - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:27:9
+  --> $DIR/ref-self.rs:33:9
    |
 LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:31:9
+  --> $DIR/ref-self.rs:39:9
    |
 LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:35:9
+  --> $DIR/ref-self.rs:45:9
    |
 LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:39:9
+  --> $DIR/ref-self.rs:51:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -49,7 +49,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:43:9
+  --> $DIR/ref-self.rs:57:9
    |
 LL |     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -59,7 +59,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:47:9
+  --> $DIR/ref-self.rs:63:9
    |
 LL |     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                      -                - let's call the lifetime of this reference `'1`
index e389d8518ada4f6a375e4d48c8cba91324aed168..34df3da4505e81cefb725f7aa91c86bb280025a9 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 #![feature(arbitrary_self_types)]
 #![allow(non_snake_case)]
 
@@ -18,33 +22,47 @@ impl Struct {
     // Test using `&self` sugar:
 
     fn ref_self(&self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     // Test using `&Self` explicitly:
 
     fn ref_Self(self: &Self, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/ref-self.stderr b/src/test/ui/self/elision/ref-self.stderr
deleted file mode 100644 (file)
index 955222f..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self.rs:21:9
-   |
-LL |     fn ref_self(&self, f: &u32) -> &u32 {
-   |                           ----     ----
-   |                           |
-   |                           this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
-   |                ++++  ++           ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self.rs:27:9
-   |
-LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
-   |                                 ----     ----
-   |                                 |
-   |                                 this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
-   |                ++++        ++           ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self.rs:31:9
-   |
-LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-   |                                          ----     ----
-   |                                          |
-   |                                          this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self.rs:35:9
-   |
-LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-   |                                          ----     ----
-   |                                          |
-   |                                          this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self.rs:39:9
-   |
-LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-   |                                                   ----     ----
-   |                                                   |
-   |                                                   this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self.rs:43:9
-   |
-LL |     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-   |                                                   ----     ----
-   |                                                   |
-   |                                                   this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-self.rs:47:9
-   |
-LL |     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
-   |                                                       ---     ---
-   |                                                       |
-   |                                                       this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
-   |                          ++++             ++                  ++
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/ref-struct-async.base.stderr b/src/test/ui/self/elision/ref-struct-async.base.stderr
new file mode 100644 (file)
index 0000000..8da673d
--- /dev/null
@@ -0,0 +1,53 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct-async.rs:16:9
+   |
+LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+   |                                           ----     ----
+   |                                           |
+   |                                           this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct-async.rs:22:9
+   |
+LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct-async.rs:28:9
+   |
+LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct-async.rs:34:9
+   |
+LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct-async.rs:40:9
+   |
+LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index 9361b6f3f81f429eb20393248016a3fcee3e6c9b..ad07c70df87783e1808328de3eb89e9d4ab6f2ff 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-struct-async.rs:13:9
+  --> $DIR/ref-struct-async.rs:16:9
    |
 LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                               -           - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct-async.rs:17:9
+  --> $DIR/ref-struct-async.rs:22:9
    |
 LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                       -            - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct-async.rs:21:9
+  --> $DIR/ref-struct-async.rs:28:9
    |
 LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                       -            - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct-async.rs:25:9
+  --> $DIR/ref-struct-async.rs:34:9
    |
 LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                               -             - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct-async.rs:29:9
+  --> $DIR/ref-struct-async.rs:40:9
    |
 LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                           -             - let's call the lifetime of this reference `'1`
index e6bd5418c8d92b8b6986e41aecd277c12159ef22..12f8f6faf1b9c361750ea4d6ccd7497a52714129 100644 (file)
@@ -1,4 +1,7 @@
 // edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
 
 #![allow(non_snake_case)]
 
@@ -10,23 +13,33 @@ impl Struct {
     // Test using `&Struct` explicitly:
 
     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/ref-struct-async.stderr b/src/test/ui/self/elision/ref-struct-async.stderr
deleted file mode 100644 (file)
index aa1d745..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct-async.rs:13:9
-   |
-LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
-   |                                           ----     ----
-   |                                           |
-   |                                           this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct-async.rs:17:9
-   |
-LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
-   |                                                    ----     ----
-   |                                                    |
-   |                                                    this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct-async.rs:21:9
-   |
-LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
-   |                                                    ----     ----
-   |                                                    |
-   |                                                    this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct-async.rs:25:9
-   |
-LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
-   |                                                             ----     ----
-   |                                                             |
-   |                                                             this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct-async.rs:29:9
-   |
-LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
-   |                                                         ----     ----
-   |                                                         |
-   |                                                         this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/self/elision/ref-struct.base.stderr b/src/test/ui/self/elision/ref-struct.base.stderr
new file mode 100644 (file)
index 0000000..5650b37
--- /dev/null
@@ -0,0 +1,83 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:15:9
+   |
+LL |     fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+   |                                     ----     ----
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+   |                  ++++        ++             ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:21:9
+   |
+LL |     fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+   |                                              ----     ----
+   |                                              |
+   |                                              this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+   |                      ++++            ++              ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:27:9
+   |
+LL |     fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+   |                                              ----     ----
+   |                                              |
+   |                                              this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+   |                      ++++            ++              ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:33:9
+   |
+LL |     fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+   |                                                       ----     ----
+   |                                                       |
+   |                                                       this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                          ++++                ++               ++
+
+error[E0623]: lifetime mismatch
+  --> $DIR/ref-struct.rs:39:9
+   |
+LL |     fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+   |                                                   ----     ----
+   |                                                   |
+   |                                                   this parameter and the return type are declared with different lifetimes...
+LL |         f
+   |         ^ ...but data from `f` is returned here
+   |
+   = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+   |
+LL |     fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+   |                      ++++                ++               ++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
index e1cc38b7c952f949b95ed227592ac40214e43e0d..70453b0ddfc71ab2b8b951ee5420a5711680e387 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:11:9
+  --> $DIR/ref-struct.rs:15:9
    |
 LL |     fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                         -           - let's call the lifetime of this reference `'1`
@@ -9,7 +9,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:15:9
+  --> $DIR/ref-struct.rs:21:9
    |
 LL |     fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                 -            - let's call the lifetime of this reference `'1`
@@ -19,7 +19,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:19:9
+  --> $DIR/ref-struct.rs:27:9
    |
 LL |     fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                 -            - let's call the lifetime of this reference `'1`
@@ -29,7 +29,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:23:9
+  --> $DIR/ref-struct.rs:33:9
    |
 LL |     fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                         -             - let's call the lifetime of this reference `'1`
@@ -39,7 +39,7 @@ LL |         f
    |         ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:27:9
+  --> $DIR/ref-struct.rs:39:9
    |
 LL |     fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                     -             - let's call the lifetime of this reference `'1`
index 73711a7feead3a8dfab0e6c3968c0647063b94b4..0ffe72793d731c4d29d1283fb812faefe4876b98 100644 (file)
@@ -1,3 +1,7 @@
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
 #![allow(non_snake_case)]
 
 use std::pin::Pin;
@@ -8,23 +12,33 @@ impl Struct {
     // Test using `&Struct` explicitly:
 
     fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 
     fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
-        f //~ ERROR lifetime mismatch
+        f
+        //[base]~^ ERROR lifetime mismatch
+        //[nll]~^^ ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/self/elision/ref-struct.stderr b/src/test/ui/self/elision/ref-struct.stderr
deleted file mode 100644 (file)
index c80993f..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct.rs:11:9
-   |
-LL |     fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
-   |                                     ----     ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
-   |                  ++++        ++             ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct.rs:15:9
-   |
-LL |     fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
-   |                                              ----     ----
-   |                                              |
-   |                                              this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++              ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct.rs:19:9
-   |
-LL |     fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
-   |                                              ----     ----
-   |                                              |
-   |                                              this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++              ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct.rs:23:9
-   |
-LL |     fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
-   |                                                       ----     ----
-   |                                                       |
-   |                                                       this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++               ++
-
-error[E0623]: lifetime mismatch
-  --> $DIR/ref-struct.rs:27:9
-   |
-LL |     fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
-   |                                                   ----     ----
-   |                                                   |
-   |                                                   this parameter and the return type are declared with different lifetimes...
-LL |         f
-   |         ^ ...but data from `f` is returned here
-   |
-   = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
-   |
-LL |     fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
-   |                      ++++                ++               ++
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
index d5645474891062e2a43bddacdcf8fbe0ab450e7f..f5c6f444317feb7cbc643dbb43b15e1647ec6f8b 100644 (file)
@@ -11,11 +11,11 @@ enum Void {}
 
 static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
 //~| WARN: previously accepted
-//~| ERROR undefined behavior to use this value
+//~| ERROR could not evaluate static initializer
 //~| WARN: type `Void` does not permit zero-initialization
 static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
 //~| WARN: previously accepted
-//~| ERROR undefined behavior to use this value
+//~| ERROR could not evaluate static initializer
 //~| WARN: type `Void` does not permit zero-initialization
 
 fn main() {}
index c38cf10d6e648bfad53cb16009a3d2c4c5759329..1e0becb7d5aa87662c33250585821911f2962a78 100644 (file)
@@ -43,23 +43,17 @@ LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
    = note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
    = note: uninhabited statics cannot be initialized, and any access would be an immediate error
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/uninhabited-static.rs:12:1
+error[E0080]: could not evaluate static initializer
+  --> $DIR/uninhabited-static.rs:12:31
    |
 LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 0, align: 1) {}
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/uninhabited-static.rs:16:1
+error[E0080]: could not evaluate static initializer
+  --> $DIR/uninhabited-static.rs:16:32
    |
 LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: 0, align: 1) {}
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
 
 warning: the type `Void` does not permit zero-initialization
   --> $DIR/uninhabited-static.rs:12:31
index 7c0f8d199a965b111a9c9be6479f379988499391..a761ec5916745d5a5df8bcdd450159165eed0abb 100644 (file)
@@ -5,14 +5,14 @@ LL | struct S1<F: Fn(&i32, &i32) -> &'a i32>(F);
    |                                 ^^ undeclared lifetime
    |
    = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider introducing lifetime `'a` here
-   |
-LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F);
-   |           +++
 help: consider making the bound lifetime-generic with a new `'a` lifetime
    |
 LL | struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
    |              +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | struct S1<'a, F: Fn(&i32, &i32) -> &'a i32>(F);
+   |           +++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/fn-missing-lifetime-in-item.rs:2:32
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr
new file mode 100644 (file)
index 0000000..0ae6296
--- /dev/null
@@ -0,0 +1,106 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/missing-lifetimes-in-signature.rs:38:11
+   |
+LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |        -  ^^ undeclared lifetime
+   |        |
+   |        help: consider introducing lifetime `'a` here: `'a,`
+
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:19:5
+   |
+LL |   fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
+   |                            ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here
+...
+LL | /     move || {
+LL | |
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                                   ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:32:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:26:26
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                          ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:55:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:49:34
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                  ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:65:9
+   |
+LL | /         move || {
+LL | |             *dest = g.get();
+LL | |         }
+   | |_________^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:62:47
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                               ^^^^^^
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:77:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:72:34
+   |
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                                  ^^^^^^
+
+error[E0621]: explicit lifetime required in the type of `dest`
+  --> $DIR/missing-lifetimes-in-signature.rs:77:5
+   |
+LL |   fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                                    ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
+...
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^ lifetime `'a` required
+
+error[E0309]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:89:5
+   |
+LL | /     move || {
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+   = help: consider adding an explicit lifetime bound `G: 'a`...
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0261, E0309, E0621, E0700.
+For more information about an error, try `rustc --explain E0261`.
index dd434ea5318781753c9ec94bbf55a6ada781a323..647b343fe06947c43727e39ec7b84c87a1ad5e73 100644 (file)
@@ -14,28 +14,31 @@ fn get(self) -> usize {
 
 fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
+        //~^ ERROR hidden type for `impl Trait` captures lifetime
         *dest = g.get();
     }
 }
 
 // After applying suggestion for `foo`:
 fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR the parameter type `G` may not live long enough
 where
-    G: Get<T>
+    G: Get<T>,
 {
+    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
 }
 
-
 // After applying suggestion for `bar`:
-fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ //~ ERROR undeclared lifetime
+fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR undeclared lifetime name `'a`
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
         *dest = g.get();
@@ -44,9 +47,11 @@ fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ //~ ERROR undeclared
 
 // After applying suggestion for `baz`:
 fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+//~^ ERROR the parameter type `G` may not live long enough
 where
-    G: Get<T>
+    G: Get<T>,
 {
+    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
@@ -55,6 +60,8 @@ fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
 // Same as above, but show that we pay attention to lifetime names from parent item
 impl<'a> Foo {
     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+        //~^ ERROR the parameter type `G` may not live long enough
+        //~| ERROR the parameter type `G` may not live long enough
         move || {
             *dest = g.get();
         }
@@ -63,8 +70,9 @@ fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
 
 // After applying suggestion for `qux`:
 fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+//~^ ERROR explicit lifetime required in the type of `dest`
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
         *dest = g.get();
@@ -73,19 +81,20 @@ fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
 
 // Potential incorrect attempt:
 fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+//~^ ERROR the parameter type `G` may not live long enough
 where
-    G: Get<T>
+    G: Get<T>,
 {
+    //~^ ERROR the parameter type `G` may not live long enough
     move || {
         *dest = g.get();
     }
 }
 
-
 // We need to tie the lifetime of `G` with the lifetime of `&mut T` and the returned closure:
 fn ok<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
         *dest = g.get();
@@ -95,7 +104,7 @@ fn ok<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
 // This also works. The `'_` isn't necessary but it's where we arrive to following the suggestions:
 fn ok2<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
 where
-    G: Get<T>
+    G: Get<T>,
 {
     move || {
         *dest = g.get();
index 916a6c2bf12af6277f3affdfbb205a216295f3dc..6d538dfd609a80b47df0c180df5646e31308b387 100644 (file)
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/missing-lifetimes-in-signature.rs:36:11
+  --> $DIR/missing-lifetimes-in-signature.rs:38:11
    |
 LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |        -  ^^ undeclared lifetime
    |        |
    |        help: consider introducing lifetime `'a` here: `'a,`
 
-error: aborting due to previous error
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:19:5
+   |
+LL |   fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
+   |                            ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here
+...
+LL | /     move || {
+LL | |
+LL | |         *dest = g.get();
+LL | |     }
+   | |_____^
+   |
+help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'_` lifetime bound
+   |
+LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                                   ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:26:37
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                     ^^^^^^^^^^^^^^^^^^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:26:26
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                          ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:26:37
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                     ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+   |
+LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |        ~~~~~                                                   ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:30:1
+   |
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:26:26
+   |
+LL | fn bar<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                          ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:32:5: 34:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:30:1
+   |
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^
+help: consider introducing an explicit lifetime bound
+   |
+LL ~ fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+LL |
+LL | where
+LL |     G: Get<T>,
+LL | {
+LL |
+ ...
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:49:45
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                             ^^^^^^^^^^^^^^^^^^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:49:34
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                  ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:49:45
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                             ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+   |
+LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b
+   |        +++     ~~~~~~~                                                  ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:53:1
+   |
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:49:34
+   |
+LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |                                  ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:55:5: 57:6]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:53:1
+   |
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^
+help: consider introducing an explicit lifetime bound
+   |
+LL ~ fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+LL |
+LL | where
+LL |     G: Get<T>,
+LL | {
+LL |
+ ...
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:62:58
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                                          ^^^^^^^^^^^^^^^^^^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:62:47
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                               ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:62:58
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                                          ^^^^^^^^^^^^^^^^^^
+help: consider introducing an explicit lifetime bound
+   |
+LL |     fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c {
+   |            +++     ~~~~~~~                                                           ++++
+
+error[E0311]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:62:77
+   |
+LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |  _____________________________________________________________________________^
+LL | |
+LL | |
+LL | |         move || {
+LL | |             *dest = g.get();
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+note: the parameter type `G` must be valid for the anonymous lifetime defined here...
+  --> $DIR/missing-lifetimes-in-signature.rs:62:47
+   |
+LL |     fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |                                               ^^^^^^
+note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:65:9: 67:10]` will meet its required lifetime bounds
+  --> $DIR/missing-lifetimes-in-signature.rs:62:77
+   |
+LL |       fn qux<'b, G: Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |  _____________________________________________________________________________^
+LL | |
+LL | |
+LL | |         move || {
+LL | |             *dest = g.get();
+LL | |         }
+LL | |     }
+   | |_____^
+help: consider introducing an explicit lifetime bound
+   |
+LL ~     fn qux<'c, 'b, G: 'c + Get<T> + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+LL |
+LL |
+LL |         move || {
+LL |             *dest = g.get();
+LL |         }
+ ...
+
+error[E0621]: explicit lifetime required in the type of `dest`
+  --> $DIR/missing-lifetimes-in-signature.rs:72:45
+   |
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |                                  ------     ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
+   |                                  |
+   |                                  help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
+
+error[E0309]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:83:44
+   |
+LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+   |            -                               ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds
+   |            |
+   |            help: consider adding an explicit lifetime bound...: `G: 'a`
+
+error[E0309]: the parameter type `G` may not live long enough
+  --> $DIR/missing-lifetimes-in-signature.rs:87:1
+   |
+LL |   fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a
+   |              - help: consider adding an explicit lifetime bound...: `G: 'a`
+...
+LL | / {
+LL | |
+LL | |     move || {
+LL | |         *dest = g.get();
+LL | |     }
+LL | | }
+   | |_^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:89:5: 91:6]` will meet its required lifetime bounds
+
+error: aborting due to 11 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0309, E0621, E0700.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.rs
new file mode 100644 (file)
index 0000000..5b223a9
--- /dev/null
@@ -0,0 +1,35 @@
+use std::ops::Deref;
+
+struct Foo {
+    v: Vec<u32>,
+}
+
+struct Bar {
+    v: Vec<u32>,
+}
+
+impl Deref for Bar {
+    type Target = Vec<u32>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.v
+    }
+}
+
+fn f(foo: &Foo) {
+    match foo {
+        Foo { v: [1, 2] } => {}
+        //~^ ERROR expected an array or slice, found `Vec<u32>
+        _ => {}
+    }
+}
+
+fn bar(bar: &Bar) {
+    match bar {
+        Bar { v: [1, 2] } => {}
+        //~^ ERROR expected an array or slice, found `Vec<u32>
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr b/src/test/ui/suggestions/pattern-struct-with-slice-vec-field.stderr
new file mode 100644 (file)
index 0000000..5b48a8b
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0529]: expected an array or slice, found `Vec<u32>`
+  --> $DIR/pattern-struct-with-slice-vec-field.rs:21:18
+   |
+LL |         Foo { v: [1, 2] } => {}
+   |                  ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error[E0529]: expected an array or slice, found `Vec<u32>`
+  --> $DIR/pattern-struct-with-slice-vec-field.rs:29:18
+   |
+LL |         Bar { v: [1, 2] } => {}
+   |                  ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0529`.
index 5a158e5876a069a23049d6872a15ee22ca3a47ba..5409e32c436fbd9ff1e26dc88901e133362c55f3 100644 (file)
@@ -2,15 +2,17 @@ error[E0107]: this trait takes 2 generic arguments but 4 generic arguments were
   --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
    |
 LL |     i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
-   |                ^               ------------ help: remove these generic arguments
-   |                |
-   |                expected 2 generic arguments
+   |                ^ expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `X`, `Y`
   --> $DIR/use-type-argument-instead-of-assoc-type.rs:1:11
    |
 LL | pub trait T<X, Y> {
    |           ^ -  -
+help: replace the generic bounds with the associated types
+   |
+LL |     i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
+   |                                ~~~~~~~~~  ~~~~~~~~~
 
 error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified
   --> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
@@ -23,11 +25,6 @@ LL |     type C;
 ...
 LL |     i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified
-   |
-help: specify the associated types
-   |
-LL |     i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
-   |                                ~~~~~~~~~  ~~~~~~~~~
 
 error: aborting due to 2 previous errors
 
index 6732902c09a504d7aef29f1291d36a998cfe3a8e..b0de8bf6aa4f267d578e319fff1bf448dac14d9d 100644 (file)
@@ -18,5 +18,7 @@ impl<T> WithAssoc<T> for () {
 //~^ ERROR use of undeclared lifetime name `'a`
 
 fn my_fun() -> Return<()> {}
+//~^ ERROR non-defining opaque type use in defining scope
+//~| ERROR non-defining opaque type use in defining scope
 
 fn main() {}
index fe45e39d938f009e1b340cd155fbc6fb322cbe0b..d038fbbe1b40a191fc35a9da4cccccc9f95293f7 100644 (file)
@@ -2,10 +2,42 @@ error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:65
    |
 LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
-   |             -                                                   ^^ undeclared lifetime
-   |             |
-   |             help: consider introducing lifetime `'a` here: `'a,`
+   |                                                                 ^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL | type Return<A> = impl for<'a> WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |                       +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | type Return<'a, A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |             +++
+
+error: non-defining opaque type use in defining scope
+  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
+   |
+LL | fn my_fun() -> Return<()> {}
+   |                           ^^
+   |
+note: used non-generic type `()` for generic parameter
+  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
+   |
+LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |             ^
+
+error: non-defining opaque type use in defining scope
+  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
+   |
+LL | fn my_fun() -> Return<()> {}
+   |                           ^^
+   |
+note: used non-generic type `()` for generic parameter
+  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
+   |
+LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
+   |             ^
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0261`.
index e4ee5e8cb2741e8b5cf49a0cc4e32c17d3c43763..74dc331b00a5ce797c70091012def3c127f39ea9 100644 (file)
@@ -10,22 +10,22 @@ impl<'_> IceCube<'_> {}
 //~^ ERROR `'_` cannot be used here
 
 struct Struct<'_> {
-//~^ ERROR `'_` cannot be used here
+    //~^ ERROR `'_` cannot be used here
     v: Vec<&'static char>
 }
 
 enum Enum<'_> {
-//~^ ERROR `'_` cannot be used here
+    //~^ ERROR `'_` cannot be used here
     Variant
 }
 
 union Union<'_> {
-//~^ ERROR `'_` cannot be used here
+    //~^ ERROR `'_` cannot be used here
     a: u32
 }
 
 trait Trait<'_> {
-//~^ ERROR `'_` cannot be used here
+    //~^ ERROR `'_` cannot be used here
 }
 
 fn foo<'_>() {
diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs b/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs
new file mode 100644 (file)
index 0000000..b37ec26
--- /dev/null
@@ -0,0 +1,29 @@
+// Verifies that MIR building for a call expression respects
+// privacy when checking if a call return type is uninhabited.
+
+pub mod widget {
+    enum Unimplemented {}
+    pub struct Widget(Unimplemented);
+
+    impl Widget {
+        pub fn new() -> Widget {
+            todo!();
+        }
+    }
+
+    pub fn f() {
+        let x: &mut u32;
+        Widget::new();
+        // Ok. Widget type returned from new is known to be uninhabited
+        // and the following code is considered unreachable.
+        *x = 1;
+    }
+}
+
+fn main() {
+    let y: &mut u32;
+    widget::Widget::new();
+    // Error. Widget type is not known to be uninhabited here,
+    // so the following code is considered reachable.
+    *y = 2; //~ ERROR use of possibly-uninitialized variable
+}
diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
new file mode 100644 (file)
index 0000000..fb19534
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0381]: use of possibly-uninitialized variable: `y`
+  --> $DIR/privately-uninhabited-mir-call.rs:28:5
+   |
+LL |     *y = 2;
+   |     ^^^^^^ use of possibly-uninitialized `y`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
index 33f762ccf63016a0f1f9a94c5bd3ec1614b18e7a..e7960960774fcdf54641b50b5c913cc4482f57bc 100644 (file)
@@ -1,11 +1,27 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+  --> $DIR/issue-45087-unreachable-unsafe.rs:7:5
    |
 LL |     *(1 as *mut u32) = 42;
    |     ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
    |
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
-error: aborting due to previous error
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:17:5
+   |
+LL |     *a = 1;
+   |     ^^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:29:5
+   |
+LL |     *b = 1;
+   |     ^^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
index 071cea8fbd78bd905a4f9cfea5951de842ad05a7..3e3da667c0b0883bb0636cc460c6e4dd0e8c4acc 100644 (file)
@@ -1,3 +1,4 @@
+// Verify that unreachable code undergoes unsafety checks.
 // revisions: mir thir
 // [thir]compile-flags: -Z thir-unsafeck
 
@@ -6,3 +7,25 @@ fn main() {
     *(1 as *mut u32) = 42;
     //~^ ERROR dereference of raw pointer is unsafe
 }
+
+fn panic() -> ! {
+    panic!();
+}
+
+fn f(a: *mut u32) {
+    panic();
+    *a = 1;
+    //~^ ERROR dereference of raw pointer is unsafe
+}
+
+enum Void {}
+
+fn uninhabited() -> Void {
+    panic!();
+}
+
+fn g(b: *mut u32) {
+    uninhabited();
+    *b = 1;
+    //~^ ERROR dereference of raw pointer is unsafe
+}
index 73a113652b8338b02f0388078f46b82beba22fca..e81adad45075054682737061ac3c3d64999b478a 100644 (file)
@@ -1,11 +1,27 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+  --> $DIR/issue-45087-unreachable-unsafe.rs:7:5
    |
 LL |     *(1 as *mut u32) = 42;
    |     ^^^^^^^^^^^^^^^^ dereference of raw pointer
    |
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
-error: aborting due to previous error
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:17:5
+   |
+LL |     *a = 1;
+   |     ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:29:5
+   |
+LL |     *b = 1;
+   |     ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.rs
deleted file mode 100644 (file)
index e69df03..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with bad location type
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=badloc:in-the-test-file -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr b/src/test/ui/unused-crate-deps/extern-loc-bad-loctype.stderr
deleted file mode 100644 (file)
index 12378f1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: unknown location type `badloc`: use `raw` or `json`
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-defl-json.rs b/src/test/ui/unused-crate-deps/extern-loc-defl-json.rs
deleted file mode 100644 (file)
index a023f53..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// Default extern location from name and path if one isn't specified
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--error-format json
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-defl-json.stderr
deleted file mode 100644 (file)
index cee3f6c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{"message":"external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":146,"byte_end":146,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":154,"byte_end":179,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"name":"bar"}}],"rendered":"warning: external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-defl-json.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-defl-json.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.rs
deleted file mode 100644 (file)
index aee6233..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:[{"malformed -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json-bad-json.stderr
deleted file mode 100644 (file)
index 20d6063..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: `--extern-location`: malformed json location `[{"malformed`
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json-json.rs
deleted file mode 100644 (file)
index c7988cd..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json-json.stderr
deleted file mode 100644 (file)
index 001ec6a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":189,"byte_end":189,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":197,"byte_end":222,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-json-json.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-json-json.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json.rs b/src/test/ui/unused-crate-deps/extern-loc-json.rs
deleted file mode 100644 (file)
index c0d76c8..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-json.stderr
deleted file mode 100644 (file)
index a6bbc0d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: external crate `bar` unused in `extern_loc_json`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-json.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-json.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar`
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.rs
deleted file mode 100644 (file)
index 6ac5589..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar -Zunstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr b/src/test/ui/unused-crate-deps/extern-loc-missing-loc.stderr
deleted file mode 100644 (file)
index 4584fbf..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: `--extern-location`: specify location for extern crate `bar`
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.rs
deleted file mode 100644 (file)
index 3590b9c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with no type
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=missing-loc-type -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr b/src/test/ui/unused-crate-deps/extern-loc-missing-loctype.stderr
deleted file mode 100644 (file)
index d0c36eb..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: unknown location type `missing-loc-type`: use `raw` or `json`
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs b/src/test/ui/unused-crate-deps/extern-loc-raw-json.rs
deleted file mode 100644 (file)
index 64c3d77..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw-json.stderr
deleted file mode 100644 (file)
index 4083bd5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":182,"byte_end":182,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":190,"byte_end":215,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-raw-json.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-raw-json.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar` at `in-the-test-file`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.rs
deleted file mode 100644 (file)
index a9e7afb..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw-missing-loc.stderr
deleted file mode 100644 (file)
index 4b51266..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-error: `--extern-location`: missing `raw` location
-
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw.rs b/src/test/ui/unused-crate-deps/extern-loc-raw.rs
deleted file mode 100644 (file)
index 27d0975..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
diff --git a/src/test/ui/unused-crate-deps/extern-loc-raw.stderr b/src/test/ui/unused-crate-deps/extern-loc-raw.stderr
deleted file mode 100644 (file)
index 2cdd005..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: external crate `bar` unused in `extern_loc_raw`: remove the dependency or add `use bar as _;`
-  --> $DIR/extern-loc-raw.rs:7:1
-   |
-LL | #![warn(unused_crate_dependencies)]
-   | ^
-   |
-note: the lint level is defined here
-  --> $DIR/extern-loc-raw.rs:7:9
-   |
-LL | #![warn(unused_crate_dependencies)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar` at `in-the-test-file`
-
-warning: 1 warning emitted
-
index 479f51bff464d61f1ee8aa324d4426d520e3d699..15833126bd6201ddda75e3b529eb26f8dc08473c 100644 (file)
@@ -5,7 +5,6 @@ LL | pub fn fib(n: u32) -> Vec<u32> {
    | ^
    |
    = note: requested on the command line with `-W unused-crate-dependencies`
-   = help: remove unnecessary dependency `bar`
 
 warning: 1 warning emitted
 
index 1142d156d0e96e507d863f77532d7f710075309c..c8c6c4507b0c51427136d656ba9de8cdbdcd3a43 100644 (file)
@@ -9,7 +9,6 @@ note: the lint level is defined here
    |
 LL | #![warn(unused_crate_dependencies)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `barbar`
 
 warning: 1 warning emitted
 
index 29667d9525cb4b266fc00b7783416079b9fd91cd..0d38315704b11fb25e6bc7be22774c0714d4f4d4 100644 (file)
@@ -9,7 +9,6 @@ note: the lint level is defined here
    |
 LL | #![warn(unused_crate_dependencies)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: remove unnecessary dependency `bar`
 
 warning: 1 warning emitted
 
index 2c0c9215129866c593193ebfce314d02946ecea1..65956461d643928fa5a319c7ae533f3dc7e15ded 100644 (file)
@@ -5,7 +5,6 @@ LL | fn main() {}
    | ^
    |
    = note: requested on the command line with `-W unused-crate-dependencies`
-   = help: remove unnecessary dependency `bar`
 
 warning: 1 warning emitted
 
index 2cd49218f5ad85728a314ac64aebf715c5a1f4bd..ea675ba9a1eb184560f8379ea4571e2d2b1e9ec4 100644 (file)
@@ -5,7 +5,6 @@ LL | fn main() {}
    | ^
    |
    = note: requested on the command line with `-W unused-crate-dependencies`
-   = help: remove unnecessary dependency `bar`
 
 warning: 1 warning emitted
 
index ba624507c21f0d332f13adb8259c7d786fedf2ab..16d198725523e0436817ef0c5144e3a3a3fa1311 100644 (file)
@@ -2,9 +2,13 @@ error[E0726]: implicit elided lifetime not allowed here
   --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:16
    |
 LL | impl Trait for Ref {}
-   |                ^^^- help: indicate the anonymous lifetime: `<'_>`
+   |                ^^^ expected lifetime parameter
    |
    = note: assuming a `'static` lifetime...
+help: indicate the anonymous lifetime
+   |
+LL | impl Trait for Ref<'_> {}
+   |                   ++++
 
 error: incompatible lifetime on type
   --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21
index 6c52664154bbf333667287e087c21af0396527b6..e8df02fbad62f3590c792544a85d29c697414904 100644 (file)
@@ -1,20 +1,41 @@
 error[E0261]: use of undeclared lifetime name `'a`
   --> $DIR/where-lifetime-resolution.rs:6:38
    |
-LL | fn f() where
-   |     - help: consider introducing lifetime `'a` here: `<'a>`
-LL |     for<'a> dyn Trait1<'a>: Trait1<'a>, // OK
 LL |     (dyn for<'a> Trait1<'a>): Trait1<'a>,
    |                                      ^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |     (dyn for<'a> Trait1<'a>): for<'a> Trait1<'a>,
+   |                               +++++++
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |     for<'a> (dyn for<'a> Trait1<'a>): Trait1<'a>,
+   |     +++++++
+help: consider introducing lifetime `'a` here
+   |
+LL | fn f<'a>() where
+   |     ++++
 
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/where-lifetime-resolution.rs:8:52
    |
-LL | fn f() where
-   |     - help: consider introducing lifetime `'b` here: `<'b>`
-...
 LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
    |                                                    ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |     for<'a> dyn for<'b> Trait2<'a, 'b>: for<'b> Trait2<'a, 'b>,
+   |                                         +++++++
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |     for<'b, 'a> dyn for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>,
+   |         +++
+help: consider introducing lifetime `'b` here
+   |
+LL | fn f<'b>() where
+   |     ++++
 
 error: aborting due to 2 previous errors
 
index dba5baf4345858c591517b24801902a062c399f8..edffc4ada3d77799e5a04eeafd9b2f843d29fc23 160000 (submodule)
@@ -1 +1 @@
-Subproject commit dba5baf4345858c591517b24801902a062c399f8
+Subproject commit edffc4ada3d77799e5a04eeafd9b2f843d29fc23
index fc0483a929a7a1e93c3cded4003f6b2835ec2985..5816a95dcebffe63aa2a9410940e4c372a83260d 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, DefIdTree};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Span;
@@ -114,8 +114,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
             hir::ItemKind::Fn(..) => {
                 // ignore main()
                 if it.ident.name == sym::main {
-                    let def_key = cx.tcx.hir().def_key(it.def_id);
-                    if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
+                    let at_root = cx.tcx.local_parent(it.def_id) == Some(CRATE_DEF_ID);
+                    if at_root {
                         return;
                     }
                 }
index 02038b5fb6b5a7ed56ce688bdf1e01834d0a68c6..0d2cb77855be1198a45f9ee31bb930a56312e151 100644 (file)
@@ -1,8 +1,8 @@
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:19:28
+  --> $DIR/unused_unit.rs:19:58
    |
 LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
-   |                            ^^^^^^ help: remove the `-> ()`
+   |                                                          ^^^^^^ help: remove the `-> ()`
    |
 note: the lint level is defined here
   --> $DIR/unused_unit.rs:12:9
@@ -11,16 +11,16 @@ LL | #![deny(clippy::unused_unit)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:20:18
+  --> $DIR/unused_unit.rs:19:28
    |
-LL |     where G: Fn() -> () {
-   |                  ^^^^^^ help: remove the `-> ()`
+LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
+   |                            ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
-  --> $DIR/unused_unit.rs:19:58
+  --> $DIR/unused_unit.rs:20:18
    |
-LL |     pub fn get_unit<F: Fn() -> (), G>(&self, f: F, _g: G) -> ()
-   |                                                          ^^^^^^ help: remove the `-> ()`
+LL |     where G: Fn() -> () {
+   |                  ^^^^^^ help: remove the `-> ()`
 
 error: unneeded unit return type
   --> $DIR/unused_unit.rs:21:26
index 1ef91e122775060acb1fbda2c9a366891af3ea89..edd4858846003dc96020a0de07a1499e3224e633 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 1ef91e122775060acb1fbda2c9a366891af3ea89
+Subproject commit edd4858846003dc96020a0de07a1499e3224e633
index dbf5cf9650c5f4f16098a2d11979b1bf423531c3..1736233835529a260525228f3dab6411be275fc5 100644 (file)
@@ -58,7 +58,8 @@ function extractFunction(content, functionName) {
                 } while (pos < content.length && content[pos] !== '/' && content[pos - 1] !== '*');
 
             // Eat quoted strings
-            } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
+            } else if ((content[pos] === '"' || content[pos] === "'" || content[pos] === "`") &&
+                       (pos === 0 || content[pos - 1] !== '/')) {
                 stop = content[pos];
                 do {
                     if (content[pos] === '\\') {
@@ -269,8 +270,13 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
     // execQuery last parameter is built in buildIndex.
     // buildIndex requires the hashmap from search-index.
     var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
-                           "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch",
-                           "removeEmptyStringsFromArray"];
+                           "buildIndex", "execQuery", "parseQuery", "createQueryResults",
+                           "isWhitespace", "isSpecialStartCharacter", "isStopCharacter",
+                           "parseInput", "getItemsBefore", "getNextElem", "createQueryElement",
+                           "isReturnArrow", "isPathStart", "getStringElem", "newParsedQuery",
+                           "itemTypeFromName", "isEndCharacter", "isErrorCharacter",
+                           "isIdentCharacter", "isSeparatorCharacter", "getIdentEndPosition",
+                           "checkExtraTypeFilterCharacters", "isWhitespaceCharacter"];
 
     const functions = ["hasOwnPropertyRustdoc", "onEach"];
     ALIASES = {};
@@ -286,12 +292,99 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
     return [loaded, index];
 }
 
+// This function checks if `expected` has all the required fields needed for the checks.
+function checkNeededFields(fullPath, expected, error_text, queryName, position) {
+    let fieldsToCheck;
+    if (fullPath.length === 0) {
+        fieldsToCheck = [
+            "foundElems",
+            "original",
+            "returned",
+            "typeFilter",
+            "userQuery",
+            "error",
+        ];
+    } else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) {
+        fieldsToCheck = [
+            "name",
+            "fullPath",
+            "pathWithoutLast",
+            "pathLast",
+            "generics",
+        ];
+    } else {
+        fieldsToCheck = [];
+    }
+    for (var i = 0; i < fieldsToCheck.length; ++i) {
+        const field = fieldsToCheck[i];
+        if (!expected.hasOwnProperty(field)) {
+            let text = `${queryName}==> Mandatory key \`${field}\` is not present`;
+            if (fullPath.length > 0) {
+                text += ` in field \`${fullPath}\``;
+                if (position != null) {
+                    text += ` (position ${position})`;
+                }
+            }
+            error_text.push(text);
+        }
+    }
+}
+
+function valueCheck(fullPath, expected, result, error_text, queryName) {
+    if (Array.isArray(expected)) {
+        for (var i = 0; i < expected.length; ++i) {
+            checkNeededFields(fullPath, expected[i], error_text, queryName, i);
+            if (i >= result.length) {
+                error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +
+                    `\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``);
+            } else {
+                valueCheck(fullPath + '[' + i + ']', expected[i], result[i], error_text, queryName);
+            }
+        }
+        for (; i < result.length; ++i) {
+            error_text.push(`${queryName}==> RESULT has extra value in array from field ` +
+                `\`${fullPath}\` (position ${i}): \`${JSON.stringify(result[i])}\` ` +
+                'compared to EXPECTED');
+        }
+    } else if (expected !== null && typeof expected !== "undefined" &&
+               expected.constructor == Object)
+    {
+        for (const key in expected) {
+            if (!expected.hasOwnProperty(key)) {
+                continue;
+            }
+            if (!result.hasOwnProperty(key)) {
+                error_text.push('==> Unknown key "' + key + '"');
+                break;
+            }
+            const obj_path = fullPath + (fullPath.length > 0 ? '.' : '') + key;
+            valueCheck(obj_path, expected[key], result[key], error_text, queryName);
+        }
+    } else {
+        expectedValue = JSON.stringify(expected);
+        resultValue = JSON.stringify(result);
+        if (expectedValue != resultValue) {
+            error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` +
+                `EXPECTED: \`${expectedValue}\`\nRESULT:   \`${resultValue}\``);
+        }
+    }
+}
+
+function runParser(query, expected, loaded, loadedFile, queryName) {
+    var error_text = [];
+    checkNeededFields("", expected, error_text, queryName, null);
+    if (error_text.length === 0) {
+        valueCheck('', expected, loaded.parseQuery(query), error_text, queryName);
+    }
+    return error_text;
+}
+
 function runSearch(query, expected, index, loaded, loadedFile, queryName) {
     const filter_crate = loadedFile.FILTER_CRATE;
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
 
-    var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate);
+    var results = loaded.execQuery(loaded.parseQuery(query), index, filter_crate);
     var error_text = [];
 
     for (var key in expected) {
@@ -353,40 +446,75 @@ function checkResult(error_text, loadedFile, displaySuccess) {
     return 1;
 }
 
-function runChecks(testFile, loaded, index) {
-    var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
-    if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
-        testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
-    } else {
-        testFileContent += "exports.FILTER_CRATE = null;";
-    }
-    var loadedFile = loadContent(testFileContent);
-
-    const expected = loadedFile.EXPECTED;
+function runCheck(loadedFile, key, callback) {
+    const expected = loadedFile[key];
     const query = loadedFile.QUERY;
 
     if (Array.isArray(query)) {
         if (!Array.isArray(expected)) {
             console.log("FAILED");
-            console.log("==> If QUERY variable is an array, EXPECTED should be an array too");
+            console.log(`==> If QUERY variable is an array, ${key} should be an array too`);
             return 1;
         } else if (query.length !== expected.length) {
             console.log("FAILED");
-            console.log("==> QUERY variable should have the same length as EXPECTED");
+            console.log(`==> QUERY variable should have the same length as ${key}`);
             return 1;
         }
         for (var i = 0; i < query.length; ++i) {
-            var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile,
-                "[ query `" + query[i] + "`]");
+            var error_text = callback(query[i], expected[i], "[ query `" + query[i] + "`]");
             if (checkResult(error_text, loadedFile, false) !== 0) {
                 return 1;
             }
         }
         console.log("OK");
-        return 0;
+    } else {
+        var error_text = callback(query, expected, "");
+        if (checkResult(error_text, loadedFile, true) !== 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+function runChecks(testFile, loaded, index) {
+    var checkExpected = false;
+    var checkParsed = false;
+    var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
+
+    if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
+        testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
+    } else {
+        testFileContent += "exports.FILTER_CRATE = null;";
+    }
+
+    if (testFileContent.indexOf("\nconst EXPECTED") !== -1) {
+        testFileContent += 'exports.EXPECTED = EXPECTED;';
+        checkExpected = true;
+    }
+    if (testFileContent.indexOf("\nconst PARSED") !== -1) {
+        testFileContent += 'exports.PARSED = PARSED;';
+        checkParsed = true;
+    }
+    if (!checkParsed && !checkExpected) {
+        console.log("FAILED");
+        console.log("==> At least `PARSED` or `EXPECTED` is needed!");
+        return 1;
+    }
+
+    const loadedFile = loadContent(testFileContent);
+    var res = 0;
+
+    if (checkExpected) {
+        res += runCheck(loadedFile, "EXPECTED", (query, expected, text) => {
+            return runSearch(query, expected, index, loaded, loadedFile, text);
+        });
+    }
+    if (checkParsed) {
+        res += runCheck(loadedFile, "PARSED", (query, expected, text) => {
+            return runParser(query, expected, loaded, loadedFile, text);
+        });
     }
-    var error_text = runSearch(query, expected, index, loaded, loadedFile, "");
-    return checkResult(error_text, loadedFile, true);
+    return res;
 }
 
 function load_files(doc_folder, resource_suffix, crate) {
index 92f423bbb6275d647e6116a5ca6f6d1c48e8693d..ad2502b041840ca04036fe025f2b299532f6292c 100644 (file)
@@ -204,12 +204,11 @@ pub(crate) fn from_method_sig(
 
     pub(crate) fn from_fn_kind(
         fn_kind: &'a visit::FnKind<'_>,
-        generics: &'a ast::Generics,
         decl: &'a ast::FnDecl,
         defaultness: ast::Defaultness,
     ) -> FnSig<'a> {
         match *fn_kind {
-            visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
+            visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, generics, _) => match fn_ctxt {
                 visit::FnCtxt::Assoc(..) => {
                     let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
                     fn_sig.defaultness = defaultness;
@@ -3180,8 +3179,14 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
                     let inner_attrs = inner_attributes(&self.attrs);
                     let fn_ctxt = visit::FnCtxt::Foreign;
                     visitor.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, self.ident, sig, &self.vis, Some(body)),
-                        generics,
+                        visit::FnKind::Fn(
+                            fn_ctxt,
+                            self.ident,
+                            sig,
+                            &self.vis,
+                            generics,
+                            Some(body),
+                        ),
                         &sig.decl,
                         self.span,
                         defaultness,
index 3ebfa551d1cbc2e17ca5eac859328fdddb8e3421..1621eb406b10f35514e24ae78cdc466fbd92d662 100644 (file)
@@ -382,7 +382,6 @@ fn unindent_comment_on_closing_brace(&self, b: &ast::Block) -> bool {
     pub(crate) fn visit_fn(
         &mut self,
         fk: visit::FnKind<'_>,
-        generics: &ast::Generics,
         fd: &ast::FnDecl,
         s: Span,
         defaultness: ast::Defaultness,
@@ -391,12 +390,12 @@ pub(crate) fn visit_fn(
         let indent = self.block_indent;
         let block;
         let rewrite = match fk {
-            visit::FnKind::Fn(_, ident, _, _, Some(ref b)) => {
+            visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => {
                 block = b;
                 self.rewrite_fn_before_block(
                     indent,
                     ident,
-                    &FnSig::from_fn_kind(&fk, generics, fd, defaultness),
+                    &FnSig::from_fn_kind(&fk, fd, defaultness),
                     mk_sp(s.lo(), b.span.lo()),
                 )
             }
@@ -552,8 +551,14 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) {
                             _ => visit::FnCtxt::Foreign,
                         };
                         self.visit_fn(
-                            visit::FnKind::Fn(fn_ctxt, item.ident, sig, &item.vis, Some(body)),
-                            generics,
+                            visit::FnKind::Fn(
+                                fn_ctxt,
+                                item.ident,
+                                sig,
+                                &item.vis,
+                                generics,
+                                Some(body),
+                            ),
                             &sig.decl,
                             item.span,
                             defaultness,
@@ -642,8 +647,7 @@ fn visit_assoc_item(&mut self, visitor_kind: &ItemVisitorKind<'_>) {
                     let inner_attrs = inner_attributes(&ai.attrs);
                     let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
                     self.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, Some(body)),
-                        generics,
+                        visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)),
                         &sig.decl,
                         ai.span,
                         defaultness,
index ea6e01e577c6bfd3fa56740ce8d72c1a9a1a42ef..3f776b70b14c771fdb1b36008b3850d50d478769 100644 (file)
@@ -42,6 +42,9 @@
     ("self_cell", "Apache-2.0"),      // rustc (fluent translations)
     // FIXME: this dependency violates the documentation comment above:
     ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
+    ("dunce", "CC0-1.0"),            // cargo (dev dependency)
+    ("similar", "Apache-2.0"),       // cargo (dev dependency)
+    ("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency)
 ];
 
 const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[