]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #99651 - compiler-errors:fn-and-raw-ptr-in-const-generics, r=oli-obk
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Wed, 27 Jul 2022 15:55:04 +0000 (17:55 +0200)
committerGitHub <noreply@github.com>
Wed, 27 Jul 2022 15:55:04 +0000 (17:55 +0200)
Deeply deny fn and raw ptrs in const generics

I think this is right -- just because we wrap a fn ptr in a wrapper type does not mean we should allow it in a const parameter.

We now reject both of these in the same way:

```
#![feature(adt_const_params)]

#[derive(Eq, PartialEq)]
struct Wrapper();

fn foo<const W: Wrapper>() {}

fn foo2<const F: fn()>() {}
```

This does regress one test (`src/test/ui/consts/refs_check_const_eq-issue-88384.stderr`), but I'm not sure it should've passed in the first place.

cc: ``@b-naber`` who introduced that test^
fixes #99641

327 files changed:
Cargo.lock
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/member_constraints.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_codegen_cranelift/.vscode/settings.json
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/Cargo.toml
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
compiler/rustc_codegen_cranelift/example/mini_core.rs
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
compiler/rustc_codegen_cranelift/example/std_example.rs
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/src/abi/mod.rs
compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
compiler/rustc_codegen_cranelift/src/archive.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/cast.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/inline_asm.rs
compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/main_shim.rs
compiler/rustc_codegen_cranelift/src/pretty_clif.rs
compiler/rustc_codegen_cranelift/src/unsize.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_gcc/src/archive.rs
compiler/rustc_codegen_llvm/src/attributes.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_llvm/src/llvm/mod.rs
compiler/rustc_codegen_ssa/src/back/archive.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/linker.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_codegen_ssa/src/target_features.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/terminator.rs
compiler/rustc_const_eval/src/transform/check_consts/ops.rs
compiler/rustc_error_messages/locales/en-US/passes.ftl
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/infer/region_constraints/mod.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_middle/src/infer/mod.rs
compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/assoc.rs
compiler/rustc_middle/src/ty/consts/valtree.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_transform/src/add_retag.rs
compiler/rustc_mir_transform/src/check_packed_ref.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/const_prop_lint.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/errors.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_resolve/src/build_reduced_graph.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_resolve/src/macros.rs
compiler/rustc_session/src/options.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_typeck/src/astconv/errors.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/closure.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fallback.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/inherited.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/check/writeback.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/errors.rs
compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
library/alloc/benches/lib.rs
library/alloc/benches/vec.rs
library/alloc/src/alloc.rs
library/alloc/src/lib.rs
library/alloc/src/string.rs
library/alloc/src/vec/into_iter.rs
library/alloc/tests/lib.rs
library/alloc/tests/vec.rs
library/core/src/cmp.rs
library/core/src/hint.rs
library/core/src/intrinsics.rs
library/core/src/lib.rs
library/core/src/mem/mod.rs
library/core/src/num/int_macros.rs
library/core/src/num/uint_macros.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/slice/iter.rs
library/core/tests/slice.rs
library/panic_abort/src/lib.rs
library/proc_macro/src/lib.rs
library/std/src/io/buffered/bufreader.rs
library/std/src/io/buffered/bufreader/buffer.rs [new file with mode: 0644]
library/std/src/io/buffered/tests.rs
library/std/src/io/mod.rs
library/std/src/io/tests.rs
library/std/src/os/windows/fs.rs
library/std/src/sys/solid/abi/mod.rs
library/std/src/sys/solid/mod.rs
library/std/src/sys/solid/os.rs
library/std/src/sys/unix/fs.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
src/ci/pgo.sh
src/doc/rustdoc/src/deprecated-features.md
src/doc/rustdoc/src/unstable-features.md
src/librustdoc/Cargo.toml
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/test/codegen/box-maybe-uninit-llvm14.rs [new file with mode: 0644]
src/test/codegen/box-maybe-uninit.rs
src/test/codegen/vec-calloc-llvm14.rs [new file with mode: 0644]
src/test/codegen/vec-calloc.rs
src/test/mir-opt/issue-99325.rs [new file with mode: 0644]
src/test/mir-opt/issue_99325.main.mir_map.0.mir [new file with mode: 0644]
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline-dead.txt
src/test/run-make-fulldeps/coverage/inline-dead.rs
src/test/run-make-fulldeps/tools.mk
src/test/run-make/export-executable-symbols/Makefile [new file with mode: 0644]
src/test/run-make/export-executable-symbols/main.rs [new file with mode: 0644]
src/test/run-make/raw-dylib-alt-calling-convention/Makefile
src/test/run-make/raw-dylib-c/Makefile
src/test/run-make/raw-dylib-c/lib.rs
src/test/run-make/raw-dylib-link-ordinal/Makefile
src/test/run-make/raw-dylib-stdcall-ordinal/Makefile
src/test/rustdoc-gui/sidebar-mobile.goml
src/test/rustdoc-ui/z-help.stdout
src/test/rustdoc/must_implement_one_of.rs [new file with mode: 0644]
src/test/rustdoc/type-layout.rs
src/test/ui-fulldeps/internal-lints/diagnostics_incorrect.stderr
src/test/ui-fulldeps/internal-lints/query_stability_incorrect.stderr
src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.rs
src/test/ui/associated-consts/associated-const-impl-wrong-lifetime.stderr
src/test/ui/associated-type-bounds/elision.rs [new file with mode: 0644]
src/test/ui/associated-type-bounds/elision.stderr [new file with mode: 0644]
src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr
src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr
src/test/ui/async-await/issues/issue-63388-2.rs
src/test/ui/async-await/issues/issue-63388-2.stderr
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
src/test/ui/c-variadic/variadic-ffi-6.stderr
src/test/ui/coherence/issue-99663-2.rs [new file with mode: 0644]
src/test/ui/coherence/issue-99663.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr [deleted file]
src/test/ui/const-generics/issues/issue-90318.rs
src/test/ui/const-generics/issues/issue-90318.stderr
src/test/ui/const-ptr/forbidden_slices.32bit.stderr
src/test/ui/const-ptr/forbidden_slices.64bit.stderr
src/test/ui/consts/const-eval/const_raw_ptr_ops.rs
src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr
src/test/ui/consts/issue-25826.rs
src/test/ui/consts/issue-25826.stderr
src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs
src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr
src/test/ui/consts/miri_unleashed/ptr_arith.rs
src/test/ui/consts/miri_unleashed/ptr_arith.stderr
src/test/ui/consts/offset_from_ub.rs
src/test/ui/consts/offset_from_ub.stderr
src/test/ui/derives/deriving-with-repr-packed.rs
src/test/ui/derives/deriving-with-repr-packed.stderr
src/test/ui/error-codes/E0106.stderr
src/test/ui/error-codes/E0395.rs [deleted file]
src/test/ui/error-codes/E0395.stderr [deleted file]
src/test/ui/error-codes/E0637.stderr
src/test/ui/foreign-fn-return-lifetime.stderr
src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs
src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr
src/test/ui/generic-associated-types/generic-associated-types-where.stderr
src/test/ui/generic-associated-types/impl_bounds.rs
src/test/ui/generic-associated-types/impl_bounds.stderr
src/test/ui/generic-associated-types/issue-47206-where-clause.stderr
src/test/ui/generic-associated-types/issue-70304.rs
src/test/ui/generic-associated-types/issue-70304.stderr
src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs
src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr
src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
src/test/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
src/test/ui/generics/wrong-number-of-args.rs
src/test/ui/generics/wrong-number-of-args.stderr
src/test/ui/impl-header-lifetime-elision/assoc-type.rs
src/test/ui/impl-header-lifetime-elision/assoc-type.stderr
src/test/ui/impl-trait/hidden-lifetimes.stderr
src/test/ui/impl-trait/issue-99073-2.rs
src/test/ui/impl-trait/issue-99073-2.stderr
src/test/ui/impl-trait/issue-99073.rs
src/test/ui/impl-trait/issue-99073.stderr
src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs
src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
src/test/ui/impl-trait/negative-reasoning.stderr
src/test/ui/impl-trait/region-escape-via-bound.rs
src/test/ui/impl-trait/region-escape-via-bound.stderr
src/test/ui/impl-trait/static-return-lifetime-infered.stderr
src/test/ui/intrinsics/const-eval-select-bad.stderr
src/test/ui/invalid/invalid-rustc_legacy_const_generics-arguments.stderr
src/test/ui/issues/issue-13497.stderr
src/test/ui/issues/issue-19707.stderr
src/test/ui/issues/issue-30255.stderr
src/test/ui/issues/issue-30371.rs
src/test/ui/lifetimes/issue-26638.rs
src/test/ui/lifetimes/issue-26638.stderr
src/test/ui/lifetimes/lifetime-elision-return-type-requires-explicit-lifetime.stderr
src/test/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs
src/test/ui/lifetimes/missing-lifetime-in-alias.stderr
src/test/ui/mismatched_types/issue-74918-missing-lifetime.rs
src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr
src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.fixed [new file with mode: 0644]
src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.rs [new file with mode: 0644]
src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.stderr [new file with mode: 0644]
src/test/ui/nll/issue-73159-rpit-static.stderr
src/test/ui/nll/trait-associated-constant.rs
src/test/ui/nll/trait-associated-constant.stderr
src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
src/test/ui/process/nofile-limit.rs
src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs
src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr
src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
src/test/ui/rfc1623-2.rs
src/test/ui/rfc1623-2.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr
src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-child.rs [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-parent.rs [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.rs [new file with mode: 0644]
src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.stderr [new file with mode: 0644]
src/test/ui/suggestions/fn-missing-lifetime-in-item.stderr
src/test/ui/suggestions/impl-trait-missing-lifetime-gated.stderr
src/test/ui/suggestions/impl-trait-missing-lifetime.rs
src/test/ui/suggestions/impl-trait-missing-lifetime.stderr
src/test/ui/suggestions/issue-86667.rs
src/test/ui/suggestions/issue-86667.stderr
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.rs
src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr
src/test/ui/suggestions/missing-lifetime-specifier.rs
src/test/ui/suggestions/missing-lifetime-specifier.stderr
src/test/ui/suggestions/missing-lt-for-hrtb.rs
src/test/ui/suggestions/missing-lt-for-hrtb.stderr
src/test/ui/suggestions/return-elided-lifetime.rs
src/test/ui/suggestions/return-elided-lifetime.stderr
src/test/ui/suggestions/return-without-lifetime.stderr
src/test/ui/unboxed-closures/unboxed-closure-sugar-lifetime-elision.stderr
src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs
src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr
src/test/ui/underscore-lifetime/underscore-lifetime-binders.stderr
src/tools/cargo
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/linkchecker/main.rs
src/tools/miri
src/tools/tidy/src/deps.rs

index ed3e30342f2f61f475891338e7564cd2cb8ecb48..2325d0f3bf263a8e8f43b2f2d5570767fc023021 100644 (file)
@@ -202,9 +202,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitmaps"
@@ -2394,9 +2394,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -3044,9 +3044,9 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.9.1"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
+checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
 dependencies = [
  "bitflags",
  "memchr",
index 7cd360623ec424f6e6995dbd632f3ced0221efa5..d4b41aad08ca4ba6e839168eb05e7bd15d2f6062 100644 (file)
@@ -1835,7 +1835,6 @@ fn new_named_lifetime_with_res(
         debug!(?self.captured_lifetimes);
         let name = match res {
             LifetimeRes::Param { mut param, binder } => {
-                debug_assert_ne!(ident.name, kw::UnderscoreLifetime);
                 let p_name = ParamName::Plain(ident);
                 if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
                     if !captured_lifetimes.binders_to_ignore.contains(&binder) {
index 64a6f91f02206f6472f00a6ada3ef730d94c5045..10a9cfb626e63391ae7ae22a439f1d13d9f2a907 100644 (file)
@@ -138,7 +138,7 @@ pub enum StabilityLevel {
     /// `#[unstable]`
     Unstable {
         /// Reason for the current stability level.
-        reason: Option<Symbol>,
+        reason: UnstableReason,
         /// Relevant `rust-lang/rust` issue.
         issue: Option<NonZeroU32>,
         is_soft: bool,
@@ -182,6 +182,32 @@ pub fn is_stable(&self) -> bool {
     }
 }
 
+#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
+#[derive(HashStable_Generic)]
+pub enum UnstableReason {
+    None,
+    Default,
+    Some(Symbol),
+}
+
+impl UnstableReason {
+    fn from_opt_reason(reason: Option<Symbol>) -> Self {
+        // UnstableReason::Default constructed manually
+        match reason {
+            Some(r) => Self::Some(r),
+            None => Self::None,
+        }
+    }
+
+    pub fn to_opt_reason(&self) -> Option<Symbol> {
+        match self {
+            Self::None => None,
+            Self::Default => Some(sym::unstable_location_reason_default),
+            Self::Some(r) => Some(*r),
+        }
+    }
+}
+
 /// Collects stability info from all stability attributes in `attrs`.
 /// Returns `None` if no stability attributes are found.
 pub fn find_stability(
@@ -371,7 +397,12 @@ fn find_stability_generic<'a, I>(
                                 );
                                 continue;
                             }
-                            let level = Unstable { reason, issue: issue_num, is_soft, implied_by };
+                            let level = Unstable {
+                                reason: UnstableReason::from_opt_reason(reason),
+                                issue: issue_num,
+                                is_soft,
+                                implied_by,
+                            };
                             if sym::unstable == meta_name {
                                 stab = Some((Stability { level, feature }, attr.span));
                             } else {
index 07aba50f03b996c40680ca6c9d3f7cc4751dd43b..176090c3b7a14e9dd78caccfad7a10bca07c4d66 100644 (file)
@@ -78,6 +78,8 @@ pub(crate) enum RegionErrorKind<'tcx> {
         span: Span,
         /// The hidden type.
         hidden_ty: Ty<'tcx>,
+        /// The opaque type.
+        key: ty::OpaqueTypeKey<'tcx>,
         /// The unexpected region.
         member_region: ty::Region<'tcx>,
     },
@@ -205,14 +207,16 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
                     }
                 }
 
-                RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => {
+                RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, key, member_region } => {
                     let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
+                    let named_key = self.regioncx.name_regions(self.infcx.tcx, key);
                     let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
                     self.buffer_error(unexpected_hidden_region_diagnostic(
                         self.infcx.tcx,
                         span,
                         named_ty,
                         named_region,
+                        named_key,
                     ));
                 }
 
@@ -850,13 +854,11 @@ fn suggest_constrain_dyn_trait_in_impl(
             debug!("trait spans found: {:?}", traits);
             for span in &traits {
                 let mut multi_span: MultiSpan = vec![*span].into();
-                multi_span.push_span_label(
-                    *span,
-                    "this has an implicit `'static` lifetime requirement".to_string(),
-                );
+                multi_span
+                    .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
                 multi_span.push_span_label(
                     ident.span,
-                    "calling this method introduces the `impl`'s 'static` requirement".to_string(),
+                    "calling this method introduces the `impl`'s 'static` requirement",
                 );
                 err.span_note(multi_span, "the used `impl` has a `'static` requirement");
                 err.span_suggestion_verbose(
index e91fcf1472df14c67c22b8be88858162a4d06819..43253a2aab00cfdd52515ff260643c096acda344 100644 (file)
@@ -38,6 +38,8 @@ pub(crate) struct NllMemberConstraint<'tcx> {
     /// The hidden type in which `R0` appears. (Used in error reporting.)
     pub(crate) hidden_ty: Ty<'tcx>,
 
+    pub(crate) key: ty::OpaqueTypeKey<'tcx>,
+
     /// The region `R0`.
     pub(crate) member_region_vid: ty::RegionVid,
 
@@ -90,6 +92,7 @@ pub(crate) fn push_constraint(
             member_region_vid,
             definition_span: m_c.definition_span,
             hidden_ty: m_c.hidden_ty,
+            key: m_c.key,
             start_index,
             end_index,
         });
index 9040cfcf54f41e977bb8bbe4940989e481f83e9d..2894c6d29ec43978ec1e5fac7ee3de67e8e1cb56 100644 (file)
@@ -1763,6 +1763,7 @@ fn check_member_constraints(
             errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion {
                 span: m_c.definition_span,
                 hidden_ty: m_c.hidden_ty,
+                key: m_c.key,
                 member_region,
             });
         }
index 407bbf48813c35fb0e3d55d13a901174be38cea4..d6712b6a4799c9cc1fbe6e885b7e86461f89c3b8 100644 (file)
@@ -246,7 +246,7 @@ fn infer_opaque_definition_from_instantiation(
         // after producing an error for each of them.
         let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
             self.tcx,
-            def_id,
+            opaque_type_key,
             map,
             instantiated_ty.ty,
             instantiated_ty.span,
@@ -429,7 +429,7 @@ fn check_opaque_type_parameter_valid(
 struct ReverseMapper<'tcx> {
     tcx: TyCtxt<'tcx>,
 
-    opaque_type_def_id: LocalDefId,
+    key: ty::OpaqueTypeKey<'tcx>,
     map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
     map_missing_regions_to_empty: bool,
 
@@ -443,14 +443,14 @@ struct ReverseMapper<'tcx> {
 impl<'tcx> ReverseMapper<'tcx> {
     fn new(
         tcx: TyCtxt<'tcx>,
-        opaque_type_def_id: LocalDefId,
+        key: ty::OpaqueTypeKey<'tcx>,
         map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
         hidden_ty: Ty<'tcx>,
         span: Span,
     ) -> Self {
         Self {
             tcx,
-            opaque_type_def_id,
+            key,
             map,
             map_missing_regions_to_empty: false,
             hidden_ty: Some(hidden_ty),
@@ -504,7 +504,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
             }
         }
 
-        let generics = self.tcx().generics_of(self.opaque_type_def_id);
+        let generics = self.tcx().generics_of(self.key.def_id);
         match self.map.get(&r.into()).map(|k| k.unpack()) {
             Some(GenericArgKind::Lifetime(r1)) => r1,
             Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
@@ -513,9 +513,10 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                 if let Some(hidden_ty) = self.hidden_ty.take() {
                     unexpected_hidden_region_diagnostic(
                         self.tcx,
-                        self.tcx.def_span(self.opaque_type_def_id),
+                        self.tcx.def_span(self.key.def_id),
                         hidden_ty,
                         r,
+                        self.key,
                     )
                     .emit();
                 }
index eb9df281e7d24ab26a755ed2e6b28f199c6b916d..cf2140097e6da02b45253fef2e86ec5777de83d4 100644 (file)
@@ -21,7 +21,6 @@
 use rustc_infer::infer::{
     InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
 };
-use rustc_infer::traits::ObligationCause;
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::AssertKind;
@@ -225,26 +224,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
                     )
                     .unwrap();
                     let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
-                    // Check that RPITs are only constrained in their outermost
-                    // function, otherwise report a mismatched types error.
-                    if let OpaqueTyOrigin::FnReturn(parent) | OpaqueTyOrigin::AsyncFn(parent)
-                            = infcx.opaque_ty_origin_unchecked(opaque_type_key.def_id, hidden_type.span)
-                        && parent.to_def_id() != body.source.def_id()
-                    {
-                        infcx
-                            .report_mismatched_types(
-                                &ObligationCause::misc(
-                                    hidden_type.span,
-                                    infcx.tcx.hir().local_def_id_to_hir_id(
-                                        body.source.def_id().expect_local(),
-                                    ),
-                                ),
-                                infcx.tcx.mk_opaque(opaque_type_key.def_id.to_def_id(), opaque_type_key.substs),
-                                hidden_type.ty,
-                                ty::error::TypeError::Mismatch,
-                            )
-                            .emit();
-                    }
                     trace!(
                         "finalized opaque type {:?} to {:#?}",
                         opaque_type_key,
index ecb20f22d8c92005c4b488785c4cc428ccc8289e..d88309e412ed0e596f1f4091dd500a96b65b2338 100644 (file)
@@ -1,10 +1,9 @@
 {
     // source for rustc_* is not included in the rust-src component; disable the errors about this
     "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
-    "rust-analyzer.assist.importGranularity": "module",
-    "rust-analyzer.assist.importEnforceGranularity": true,
-    "rust-analyzer.assist.importPrefix": "crate",
-    "rust-analyzer.cargo.runBuildScripts": true,
+    "rust-analyzer.imports.granularity.enforce": true,
+    "rust-analyzer.imports.granularity.group": "module",
+    "rust-analyzer.imports.prefix": "crate",
     "rust-analyzer.cargo.features": ["unstable-features"],
     "rust-analyzer.linkedProjects": [
         "./Cargo.toml",
index 2f5d1c0432f55d595d326a3ad6137d952ea402ec..532049c858d4f4ce78218a816512d2a9c7acd9cb 100644 (file)
@@ -2,6 +2,17 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "ahash"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
+
 [[package]]
 name = "anyhow"
 version = "1.0.56"
@@ -25,6 +36,12 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -33,56 +50,57 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed44413e7e2fe3260d0ed73e6956ab188b69c10ee92b892e401e0f4f6808c68b"
+checksum = "749d0d6022c9038dccf480bdde2a38d435937335bf2bb0f14e815d94517cdce8"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b5d83f0f26bf213f971f45589d17e5b65e4861f9ed22392b0cbb6eaa5bd329c"
+checksum = "e94370cc7b37bf652ccd8bb8f09bd900997f7ccf97520edfc75554bb5c4abbea"
 dependencies = [
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
  "cranelift-entity",
+ "cranelift-isle",
  "gimli",
  "log",
- "regalloc",
+ "regalloc2",
  "smallvec",
  "target-lexicon",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6800dc386177df6ecc5a32680607ed8ba1fa0d31a2a59c8c61fbf44826b8191d"
+checksum = "e0a3cea8fdab90e44018c5b9a1dfd460d8ee265ac354337150222a354628bdb6"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c961f85070985ebc8fcdb81b838a5cf842294d1e6ed4852446161c7e246fd455"
+checksum = "5ac72f76f2698598951ab26d8c96eaa854810e693e7dd52523958b5909fde6b2"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2347b2b8d1d5429213668f2a8e36c85ee3c73984a2f6a79007e365d3e575e7ed"
+checksum = "09eaeacfcd2356fe0e66b295e8f9d59fdd1ac3ace53ba50de14d628ec902f72d"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cbcdbf7bed29e363568b778649b69dabc3d727256d5d25236096ef693757654"
+checksum = "dba69c9980d5ffd62c18a2bde927855fcd7c8dc92f29feaf8636052662cbd99c"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -90,11 +108,17 @@ dependencies = [
  "target-lexicon",
 ]
 
+[[package]]
+name = "cranelift-isle"
+version = "0.85.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2920dc1e05cac40304456ed3301fde2c09bd6a9b0210bcfa2f101398d628d5b"
+
 [[package]]
 name = "cranelift-jit"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c769d4e0d76f59c8b2a3bf0477d89ee149bb0731b53fbb245ee081d49063095"
+checksum = "1c3c5ed067f2c81577e431f3039148a9c187b33cc79e0d1731fede27d801ec56"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -110,9 +134,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ab57d399a2401074bb0cc40b3031e420f3d66d46ec0cf21eeae53ac04bd73e2"
+checksum = "eee6784303bf9af235237a4885f7417e09a35df896d38ea969a0081064b3ede4"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -120,9 +144,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f4cdf93552e5ceb2e3c042829ebb4de4378492705f769eadc6a7c6c5251624c"
+checksum = "f04dfa45f9b2a6f587c564d6b63388e00cd6589d2df6ea2758cf79e1a13285e6"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -131,9 +155,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.83.0"
+version = "0.85.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf8e65f4839c26e6237fc0744911d79b0a2ac5e76b4e4eebd14db2b8d849fd31"
+checksum = "0bf38b2c505db749276793116c0cb30bd096206c7810e471677a453134881881"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -152,6 +176,26 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
 [[package]]
 name = "gimli"
 version = "0.26.1"
@@ -161,6 +205,15 @@ dependencies = [
  "indexmap",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+dependencies = [
+ "ahash",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.12.3"
@@ -174,14 +227,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
 dependencies = [
  "autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.119"
+version = "0.2.126"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
 
 [[package]]
 name = "libloading"
@@ -219,11 +272,12 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 
 [[package]]
 name = "object"
-version = "0.27.1"
+version = "0.28.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
 dependencies = [
  "crc32fast",
+ "hashbrown 0.11.2",
  "indexmap",
  "memchr",
 ]
@@ -235,13 +289,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
 
 [[package]]
-name = "regalloc"
-version = "0.0.34"
+name = "regalloc2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02"
+checksum = "4a8d23b35d7177df3b9d31ed8a9ab4bf625c668be77a319d4f5efd4a5257701c"
 dependencies = [
+ "fxhash",
  "log",
- "rustc-hash",
+ "slice-group-by",
  "smallvec",
 ]
 
@@ -257,12 +312,6 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
 [[package]]
 name = "rustc_codegen_cranelift"
 version = "0.1.0"
@@ -283,6 +332,12 @@ dependencies = [
  "target-lexicon",
 ]
 
+[[package]]
+name = "slice-group-by"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec"
+
 [[package]]
 name = "smallvec"
 version = "1.8.1"
@@ -295,6 +350,18 @@ version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
 
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
 [[package]]
 name = "winapi"
 version = "0.3.9"
index ff71d7a209e4deb1cc3e75b72ce081d5ce575d17..61e977e3e69bfbd0ae0e23a4d82693a509e25d3e 100644 (file)
@@ -8,15 +8,15 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.83.0", features = ["unwind", "all-arch"] }
-cranelift-frontend = "0.83.0"
-cranelift-module = "0.83.0"
-cranelift-native = "0.83.0"
-cranelift-jit = { version = "0.83.0", optional = true }
-cranelift-object = "0.83.0"
+cranelift-codegen = { version = "0.85.3", features = ["unwind", "all-arch"] }
+cranelift-frontend = "0.85.3"
+cranelift-module = "0.85.3"
+cranelift-native = "0.85.3"
+cranelift-jit = { version = "0.85.3", optional = true }
+cranelift-object = "0.85.3"
 target-lexicon = "0.12.0"
 gimli = { version = "0.26.0", default-features = false, features = ["write"]}
-object = { version = "0.27.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+object = { version = "0.28.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
 ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
 indexmap = "1.9.1"
index efee6ef3f3780192943ec1b2dd34332d8692b57a..7b2cdd273366f41ea8b21939395ba82e124b07ae 100644 (file)
@@ -56,9 +56,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.72"
+version = "0.1.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afdbb35d279238cf77f0c9e8d90ad50d6c7bff476ab342baafa29440f0f10bff"
+checksum = "c6e3183e88f659a862835db8f4b67dbeed3d93e44dd4927eef78edb1c149d784"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -112,9 +112,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.12.1"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -123,20 +123,21 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.2.0"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f"
+checksum = "7668753748e445859e4e373c3d41117235d9feed578392f5a3a73efdc751ca4a"
 dependencies = [
  "compiler_builtins",
  "libc",
+ "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.125"
+version = "0.2.126"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
+checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
 dependencies = [
  "rustc-std-workspace-core",
 ]
index 8682204f4fd30b355fa0d11f83adbb1705af8eae..16cce83dd9c850f06222f5e0549fc30b538bb31f 100644 (file)
@@ -205,7 +205,7 @@ fn build_clif_sysroot_for_triple(
     {
         let entry = entry.unwrap();
         if let Some(ext) = entry.path().extension() {
-            if ext == "rmeta" || ext == "d" || ext == "dSYM" {
+            if ext == "rmeta" || ext == "d" || ext == "dSYM" || ext == "clif" {
                 continue;
             }
         } else {
index 489259d1a6bc6564e03002712ed5c6e53f0272f0..8b6042a3d66380909f63bb727a4fcb08cce5fc5e 100644 (file)
@@ -458,7 +458,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
 
 #[lang = "panic"]
 #[track_caller]
-pub fn panic(_msg: &str) -> ! {
+pub fn panic(_msg: &'static str) -> ! {
     unsafe {
         libc::puts("Panicking\n\0" as *const str as *const i8);
         intrinsics::abort();
@@ -497,7 +497,7 @@ pub trait Deref {
 #[repr(transparent)]
 #[rustc_layout_scalar_valid_range_start(1)]
 #[rustc_nonnull_optimization_guaranteed]
-pub struct NonNull<T: ?Sized>(pub *mut T);
+pub struct NonNull<T: ?Sized>(pub *const T);
 
 impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
@@ -521,7 +521,7 @@ fn drop(&mut self) {
     }
 }
 
-impl<T> Deref for Box<T> {
+impl<T: ?Sized> Deref for Box<T> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
index 0f1245c2758edabc691d4932a3fae3c66d7492cd..aa1f239bae23ec55bce6c5872f7eac3d37ae8355 100644 (file)
@@ -124,6 +124,23 @@ fn call_return_u128_pair() {
     return_u128_pair();
 }
 
+#[repr(C)]
+pub struct bool_11 {
+    field0: bool,
+    field1: bool,
+    field2: bool,
+    field3: bool,
+    field4: bool,
+    field5: bool,
+    field6: bool,
+    field7: bool,
+    field8: bool,
+    field9: bool,
+    field10: bool,
+}
+
+extern "C" fn bool_struct_in_11(arg0: bool_11) {}
+
 #[allow(unreachable_code)] // FIXME false positive
 fn main() {
     take_unique(Unique {
@@ -134,6 +151,20 @@ fn main() {
 
     call_return_u128_pair();
 
+    bool_struct_in_11(bool_11 {
+        field0: true,
+        field1: true,
+        field2: true,
+        field3: true,
+        field4: true,
+        field5: true,
+        field6: true,
+        field7: true,
+        field8: true,
+        field9: true,
+        field10: true,
+    });
+
     let slice = &[0, 1] as &[i32];
     let slice_ptr = slice as *const [i32] as *const i32;
 
@@ -299,6 +330,17 @@ struct ExternTypeWrapper {
     static REF1: &u8 = &42;
     static REF2: &u8 = REF1;
     assert_eq!(*REF1, *REF2);
+
+    extern "C" {
+        type A;
+    }
+
+    fn main() {
+        let x: &A = unsafe { &*(1usize as *const A) };
+
+        assert_eq!(unsafe { intrinsics::size_of_val(x) }, 0);
+        assert_eq!(unsafe { intrinsics::min_align_of_val(x) }, 1);
+}
 }
 
 #[cfg(all(not(jit), target_arch = "x86_64", target_os = "linux"))]
index 0a2bce2621d963f1e6d68e173c5f65522c108a89..0b5b6cd55d720d4750060ecb81f75b83f76f4cf6 100644 (file)
@@ -128,6 +128,25 @@ enum Nums {
         0 => loop {},
         v => panic(v),
     };
+
+    if black_box(false) {
+        // Based on https://github.com/rust-lang/rust/blob/2f320a224e827b400be25966755a621779f797cc/src/test/ui/debuginfo/debuginfo_with_uninhabitable_field_and_unsized.rs
+        let _ = Foo::<dyn Send>::new();
+
+        #[allow(dead_code)]
+        struct Foo<T: ?Sized> {
+            base: Never,
+            value: T,
+        }
+
+        impl<T: ?Sized> Foo<T> {
+            pub fn new() -> Box<Foo<T>> {
+                todo!()
+            }
+        }
+
+        enum Never {}
+    }
 }
 
 fn panic(_: u128) {
index e98e92e468e93dacc140a5c23b22a147710917e3..3ab395d89d50e884945dd045e080c922039c73aa 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-05-15"
+channel = "nightly-2022-07-25"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 4d0dfa16c5ecf88488e6a360b752e65fbb200012..091bfa1e9926fac647315298b8c35c386f46b3d3 100644 (file)
@@ -29,14 +29,15 @@ diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/ru
 index 8431aa7b818..a3ff7e68ce5 100644
 --- a/src/tools/compiletest/src/runtest.rs
 +++ b/src/tools/compiletest/src/runtest.rs
-@@ -3489,11 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
-             .join("library");
-         normalize_path(&src_dir, "$(echo '$SRC_DIR')");
+@@ -3489,12 +3489,7 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
+         let compiler_src_dir = base_dir.join("compiler");
+         normalize_path(&compiler_src_dir, "$(echo '$COMPILER_DIR')");
 
 -        if let Some(virtual_rust_source_base_dir) =
 -            option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from)
 -        {
 -            normalize_path(&virtual_rust_source_base_dir.join("library"), "$(echo '$SRC_DIR')");
+-            normalize_path(&virtual_rust_source_base_dir.join("compiler"), "$(echo '$COMPILER_DIR')");
 -        }
 +        normalize_path(&Path::new("$(cd ../build_sysroot/sysroot_src/library; pwd)"), "$(echo '$SRC_DIR')");
 
@@ -62,3 +63,6 @@ deny-warnings = false
 verbose-tests = false
 EOF
 popd
+
+# FIXME remove once inline asm is fully supported
+export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
index 9bdb9f22c549a56d34850f97cbf2461a0d83585d..944787612d8bc206e1a29a7ab130518696ecc410 100755 (executable)
@@ -33,6 +33,7 @@ rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-typ
 rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte
 rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same
 rm src/test/ui/generator/size-moved-locals.rs # same
+rm -r src/test/ui/macros/rfc-2011-nicer-assert-messages/
 
 # vendor intrinsics
 rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected
@@ -65,11 +66,13 @@ rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and n
 rm src/test/ui/target-feature/missing-plusminus.rs # error not implemented
 rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
 rm -r src/test/run-make/emit-named-files # requires full --emit support
+rm src/test/ui/abi/stack-probes.rs # stack probes not yet implemented
 
 # optimization tests
 # ==================
-rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations
+rm src/test/ui/codegen/issue-28950.rs # depends on stack size optimizations
 rm src/test/ui/codegen/init-large-type.rs # same
+rm src/test/ui/issues/issue-40883.rs # same
 rm -r src/test/run-make/fmt-write-bloat/ # tests an optimization
 
 # backend specific tests
@@ -89,14 +92,13 @@ rm src/test/ui/consts/issue-33537.rs # same
 rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/
 rm -r src/test/run-make/unstable-flag-required # same
 rm -r src/test/run-make/rustdoc-* # same
+rm -r src/test/run-make/issue-88756-default-output # same
+rm -r src/test/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
 
 # genuine bugs
 # ============
 rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
 
-rm -r src/test/ui/polymorphization/ # polymorphization not yet supported
-rm src/test/codegen-units/polymorphization/unused_type_parameters.rs # same
-
 rm src/test/incremental/spike-neg1.rs # errors out for some reason
 rm src/test/incremental/spike-neg2.rs # same
 rm src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
@@ -111,6 +113,8 @@ rm src/test/ui/backtrace.rs # TODO warning
 rm src/test/ui/empty_global_asm.rs # TODO add needs-asm-support
 rm src/test/ui/simple_global_asm.rs # TODO add needs-asm-support
 rm src/test/ui/test-attrs/test-type.rs # TODO panic message on stderr. correct stdout
+# not sure if this is actually a bug in the test suite, but the symbol list shows the function without leading _ for some reason
+rm -r src/test/run-make/native-link-modifier-bundle
 
 echo "[TEST] rustc test suite"
 RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
index ffa5d747b1160c01bdfbf6f0b73f002dacacd12a..815450f689e4ab50c4957a35d5ee90faf22ca7e9 100644 (file)
@@ -4,6 +4,7 @@
 mod pass_mode;
 mod returning;
 
+use cranelift_module::ModuleError;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_target::abi::call::{Conv, FnAbi};
@@ -69,7 +70,17 @@ pub(crate) fn import_function<'tcx>(
 ) -> FuncId {
     let name = tcx.symbol_name(inst).name;
     let sig = get_function_sig(tcx, module.isa().triple(), inst);
-    module.declare_function(name, Linkage::Import, &sig).unwrap()
+    match module.declare_function(name, Linkage::Import, &sig) {
+        Ok(func_id) => func_id,
+        Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+            "attempt to declare `{name}` as function, but it was already declared as static"
+        )),
+        Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.sess.fatal(&format!(
+            "attempt to declare `{name}` with signature {new_sig:?}, \
+             but it was already declared with signature {prev_sig:?}"
+        )),
+        Err(err) => Err::<_, _>(err).unwrap(),
+    }
 }
 
 impl<'tcx> FunctionCx<'_, '_, 'tcx> {
@@ -182,6 +193,15 @@ enum ArgKind<'tcx> {
     }
 
     let fn_abi = fx.fn_abi.take().unwrap();
+
+    // FIXME implement variadics in cranelift
+    if fn_abi.c_variadic {
+        fx.tcx.sess.span_fatal(
+            fx.mir.span,
+            "Defining variadic functions is not yet supported by Cranelift",
+        );
+    }
+
     let mut arg_abis_iter = fn_abi.args.iter();
 
     let func_params = fx
@@ -376,9 +396,15 @@ pub(crate) fn codegen_terminator_call<'tcx>(
         RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
     };
 
-    let is_cold = instance
-        .map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD))
-        .unwrap_or(false);
+    let is_cold = if fn_sig.abi == Abi::RustCold {
+        true
+    } else {
+        instance
+            .map(|inst| {
+                fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)
+            })
+            .unwrap_or(false)
+    };
     if is_cold {
         fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
         if let Some(destination_block) = target {
index 9f0bd31e95fcc47a162066fd13c4127f61137305..6c10baa53d415da6e32e64adebecab4d57a059d4 100644 (file)
@@ -18,9 +18,9 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam {
     let clif_ty = match (reg.kind, reg.size.bytes()) {
         (RegKind::Integer, 1) => types::I8,
         (RegKind::Integer, 2) => types::I16,
-        (RegKind::Integer, 4) => types::I32,
-        (RegKind::Integer, 8) => types::I64,
-        (RegKind::Integer, 16) => types::I128,
+        (RegKind::Integer, 3..=4) => types::I32,
+        (RegKind::Integer, 5..=8) => types::I64,
+        (RegKind::Integer, 9..=16) => types::I128,
         (RegKind::Float, 4) => types::F32,
         (RegKind::Float, 8) => types::F64,
         (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
@@ -48,23 +48,9 @@ fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -
         )
     };
 
-    if cast.prefix.iter().all(|x| x.is_none()) {
-        // Simplify to a single unit when there is no prefix and size <= unit size
-        if cast.rest.total <= cast.rest.unit.size {
-            let clif_ty = match (cast.rest.unit.kind, cast.rest.unit.size.bytes()) {
-                (RegKind::Integer, 1) => types::I8,
-                (RegKind::Integer, 2) => types::I16,
-                (RegKind::Integer, 3..=4) => types::I32,
-                (RegKind::Integer, 5..=8) => types::I64,
-                (RegKind::Integer, 9..=16) => types::I128,
-                (RegKind::Float, 4) => types::F32,
-                (RegKind::Float, 8) => types::F64,
-                (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
-                _ => unreachable!("{:?}", cast.rest.unit),
-            };
-            return smallvec![AbiParam::new(clif_ty)];
-        }
-    }
+    // Note: Unlike the LLVM equivalent of this code we don't have separate branches for when there
+    // is no prefix as a single unit, an array and a heterogeneous struct are not represented using
+    // different types in Cranelift IR. Instead a single array of primitive types is used.
 
     // Create list of fields in the main structure
     let mut args = cast
@@ -230,7 +216,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
     arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
     is_owned: bool,
 ) -> SmallVec<[Value; 2]> {
-    assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty);
+    assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty, 16);
     match arg_abi.mode {
         PassMode::Ignore => smallvec![],
         PassMode::Direct(_) => smallvec![arg.load_scalar(fx)],
index 0812f930b5dea20c06b97e93127c9105174c5dd5..c92c1051139542299ae933bbd904035e319a6307 100644 (file)
@@ -86,7 +86,7 @@ enum BuilderKind {
 
         let mut entries = Vec::new();
 
-        for (entry_name, entry) in self.entries {
+        for (mut entry_name, entry) in self.entries {
             // FIXME only read the symbol table of the object files to avoid having to keep all
             // object files in memory at once, or read them twice.
             let data = match entry {
@@ -109,6 +109,23 @@ enum BuilderKind {
             };
 
             if !self.no_builtin_ranlib {
+                if symbol_table.contains_key(&entry_name) {
+                    // The ar crate can't handle creating a symbol table in case of multiple archive
+                    // members with the same name. Work around this by prepending a number until we
+                    // get a unique name.
+                    for i in 1.. {
+                        let new_name = format!("{}_", i)
+                            .into_bytes()
+                            .into_iter()
+                            .chain(entry_name.iter().copied())
+                            .collect::<Vec<_>>();
+                        if !symbol_table.contains_key(&new_name) {
+                            entry_name = new_name;
+                            break;
+                        }
+                    }
+                }
+
                 match object::File::parse(&*data) {
                     Ok(object) => {
                         symbol_table.insert(
@@ -204,12 +221,16 @@ enum BuilderKind {
         any_members
     }
 
-    fn inject_dll_import_lib(
-        &mut self,
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn create_dll_import_lib(
+        _sess: &Session,
         _lib_name: &str,
         _dll_imports: &[rustc_session::cstore::DllImport],
-        _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir,
-    ) {
-        bug!("injecting dll imports is not supported");
+        _tmpdir: &Path,
+    ) -> PathBuf {
+        bug!("creating dll imports is not supported");
     }
 }
index 63cd4d6de4c3e12fab188e78f1c323e019e8915e..122e103ff62bc14262a1b91a7e38d4e293bba6e4 100644 (file)
@@ -175,10 +175,37 @@ fn compile_fn<'tcx>(
         );
     });
 
+    #[cfg(any())] // This is never true
+    let _clif_guard = {
+        use std::fmt::Write;
+
+        let func_clone = context.func.clone();
+        let clif_comments_clone = clif_comments.clone();
+        let mut clif = String::new();
+        for flag in module.isa().flags().iter() {
+            writeln!(clif, "set {}", flag).unwrap();
+        }
+        write!(clif, "target {}", module.isa().triple().architecture.to_string()).unwrap();
+        for isa_flag in module.isa().isa_flags().iter() {
+            write!(clif, " {}", isa_flag).unwrap();
+        }
+        writeln!(clif, "\n").unwrap();
+        crate::PrintOnPanic(move || {
+            let mut clif = clif.clone();
+            ::cranelift_codegen::write::decorate_function(
+                &mut &clif_comments_clone,
+                &mut clif,
+                &func_clone,
+            )
+            .unwrap();
+            clif
+        })
+    };
+
     // Define function
     tcx.sess.time("define function", || {
         context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
-        module.define_function(func_id, context).unwrap()
+        module.define_function(func_id, context).unwrap();
     });
 
     // Write optimized function to file for debugging
@@ -815,15 +842,7 @@ pub(crate) fn codegen_place<'tcx>(
     for elem in place.projection {
         match elem {
             PlaceElem::Deref => {
-                if cplace.layout().ty.is_box() {
-                    cplace = cplace
-                        .place_field(fx, Field::new(0)) // Box<T> -> Unique<T>
-                        .place_field(fx, Field::new(0)) // Unique<T> -> NonNull<T>
-                        .place_field(fx, Field::new(0)) // NonNull<T> -> *mut T
-                        .place_deref(fx);
-                } else {
-                    cplace = cplace.place_deref(fx);
-                }
+                cplace = cplace.place_deref(fx);
             }
             PlaceElem::Field(field, _ty) => {
                 cplace = cplace.place_field(fx, field);
index b24e49e94c91ecfa850ec44c48dc5f1b368b7114..bad5d1f08a9cf5454766b36de3f2614e5a6020a4 100644 (file)
@@ -149,17 +149,8 @@ pub(crate) fn clif_int_or_float_cast(
         }
 
         let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from);
-        if to_ty == types::I128 {
-            // FIXME(bytecodealliance/wasmtime#3963): select.i128 on fcmp eq miscompiles
-            let (lsb, msb) = fx.bcx.ins().isplit(val);
-            let zero = fx.bcx.ins().iconst(types::I64, 0);
-            let lsb = fx.bcx.ins().select(is_not_nan, lsb, zero);
-            let msb = fx.bcx.ins().select(is_not_nan, msb, zero);
-            fx.bcx.ins().iconcat(lsb, msb)
-        } else {
-            let zero = fx.bcx.ins().iconst(to_ty, 0);
-            fx.bcx.ins().select(is_not_nan, val, zero)
-        }
+        let zero = fx.bcx.ins().iconst(to_ty, 0);
+        fx.bcx.ins().select(is_not_nan, val, zero)
     } else if from_ty.is_float() && to_ty.is_float() {
         // float -> float
         match (from_ty, to_ty) {
index 94a2fb2fbddc298da7efde1311b555785bcda11a..7f7fd0e9c579d17fb2d8a6fc7803c439bd7fc020 100644 (file)
@@ -328,14 +328,18 @@ fn data_id_for_static(
 
     let attrs = tcx.codegen_fn_attrs(def_id);
 
-    let data_id = module
-        .declare_data(
-            &*symbol_name,
-            linkage,
-            is_mutable,
-            attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
-        )
-        .unwrap();
+    let data_id = match module.declare_data(
+        &*symbol_name,
+        linkage,
+        is_mutable,
+        attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
+    ) {
+        Ok(data_id) => data_id,
+        Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+            "attempt to declare `{symbol_name}` as static, but it was already declared as function"
+        )),
+        Err(err) => Err::<_, _>(err).unwrap(),
+    };
 
     if rlinkage.is_some() {
         // Comment copied from https://github.com/rust-lang/rust/blob/45060c2a66dfd667f88bd8b94261b28a58d85bd5/src/librustc_codegen_llvm/consts.rs#L141
@@ -441,7 +445,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
             let data_id = match reloc_target_alloc {
                 GlobalAlloc::Function(instance) => {
                     assert_eq!(addend, 0);
-                    let func_id = crate::abi::import_function(tcx, module, instance);
+                    let func_id =
+                        crate::abi::import_function(tcx, module, instance.polymorphize(tcx));
                     let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                     data_ctx.write_function_addr(offset.bytes() as u32, local_func_id);
                     continue;
index deac5dfd3ec1adc43b8e2380446dba99a493eb6e..241de5e36530c8bbddb1bce99b2f4f2fe39fa23b 100644 (file)
@@ -18,86 +18,96 @@ pub(crate) fn codegen_inline_asm<'tcx>(
 ) {
     // FIXME add .eh_frame unwind info directives
 
-    if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
-        let true_ = fx.bcx.ins().iconst(types::I32, 1);
-        fx.bcx.ins().trapnz(true_, TrapCode::User(1));
-        return;
-    } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
-        && matches!(
-            template[1],
-            InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
-        )
-        && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
-        && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
-        && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
-        && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
-        && matches!(
-            template[6],
-            InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
-        )
-    {
-        assert_eq!(operands.len(), 4);
-        let (leaf, eax_place) = match operands[1] {
-            InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
-                assert_eq!(
-                    reg,
-                    InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax))
-                );
-                (
-                    crate::base::codegen_operand(fx, in_value).load_scalar(fx),
-                    crate::base::codegen_place(fx, out_place.unwrap()),
-                )
-            }
-            _ => unreachable!(),
-        };
-        let ebx_place = match operands[0] {
-            InlineAsmOperand::Out { reg, late: true, place } => {
-                assert_eq!(
-                    reg,
-                    InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
-                        X86InlineAsmRegClass::reg
-                    ))
-                );
-                crate::base::codegen_place(fx, place.unwrap())
-            }
-            _ => unreachable!(),
-        };
-        let (sub_leaf, ecx_place) = match operands[2] {
-            InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
-                assert_eq!(
-                    reg,
-                    InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx))
-                );
-                (
-                    crate::base::codegen_operand(fx, in_value).load_scalar(fx),
-                    crate::base::codegen_place(fx, out_place.unwrap()),
-                )
-            }
-            _ => unreachable!(),
-        };
-        let edx_place = match operands[3] {
-            InlineAsmOperand::Out { reg, late: true, place } => {
-                assert_eq!(
-                    reg,
-                    InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx))
-                );
-                crate::base::codegen_place(fx, place.unwrap())
-            }
-            _ => unreachable!(),
-        };
-
-        let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
-
-        eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
-        ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
-        ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
-        edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
-        return;
-    } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
-        // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
-        crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
-    } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
-        crate::trap::trap_unimplemented(fx, "Alloca is not supported");
+    if !template.is_empty() {
+        if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
+            let true_ = fx.bcx.ins().iconst(types::I32, 1);
+            fx.bcx.ins().trapnz(true_, TrapCode::User(1));
+            return;
+        } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+            && matches!(
+                template[1],
+                InlineAsmTemplatePiece::Placeholder {
+                    operand_idx: 0,
+                    modifier: Some('r'),
+                    span: _
+                }
+            )
+            && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
+            && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
+            && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
+            && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+            && matches!(
+                template[6],
+                InlineAsmTemplatePiece::Placeholder {
+                    operand_idx: 0,
+                    modifier: Some('r'),
+                    span: _
+                }
+            )
+        {
+            assert_eq!(operands.len(), 4);
+            let (leaf, eax_place) = match operands[1] {
+                InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+                    assert_eq!(
+                        reg,
+                        InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax))
+                    );
+                    (
+                        crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+                        crate::base::codegen_place(fx, out_place.unwrap()),
+                    )
+                }
+                _ => unreachable!(),
+            };
+            let ebx_place = match operands[0] {
+                InlineAsmOperand::Out { reg, late: true, place } => {
+                    assert_eq!(
+                        reg,
+                        InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
+                            X86InlineAsmRegClass::reg
+                        ))
+                    );
+                    crate::base::codegen_place(fx, place.unwrap())
+                }
+                _ => unreachable!(),
+            };
+            let (sub_leaf, ecx_place) = match operands[2] {
+                InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+                    assert_eq!(
+                        reg,
+                        InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx))
+                    );
+                    (
+                        crate::base::codegen_operand(fx, in_value).load_scalar(fx),
+                        crate::base::codegen_place(fx, out_place.unwrap()),
+                    )
+                }
+                _ => unreachable!(),
+            };
+            let edx_place = match operands[3] {
+                InlineAsmOperand::Out { reg, late: true, place } => {
+                    assert_eq!(
+                        reg,
+                        InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx))
+                    );
+                    crate::base::codegen_place(fx, place.unwrap())
+                }
+                _ => unreachable!(),
+            };
+
+            let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
+
+            eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
+            ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
+            ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
+            edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
+            return;
+        } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
+            // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
+            crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
+        } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
+            crate::trap::trap_unimplemented(fx, "Alloca is not supported");
+        }
     }
 
     let mut inputs = Vec::new();
index 77ac46540a9ba88f8c65b47eb18d8e225f1b2555..869670c8cfac7ec41e50df30dce1954f49ce915f 100644 (file)
@@ -13,15 +13,11 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
     ret: CPlace<'tcx>,
     target: Option<BasicBlock>,
 ) {
-    intrinsic_match! {
-        fx, intrinsic, args,
-        _ => {
-            fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
-            crate::trap::trap_unimplemented(fx, intrinsic);
-        };
-
+    match intrinsic {
         // Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
-        "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd", (c a) {
+        "llvm.x86.sse2.pmovmskb.128" | "llvm.x86.avx2.pmovmskb" | "llvm.x86.sse2.movmsk.pd" => {
+            intrinsic_args!(fx, args => (a); intrinsic);
+
             let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
             let lane_ty = fx.clif_type(lane_ty).unwrap();
             assert!(lane_count <= 32);
@@ -29,7 +25,8 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
             let mut res = fx.bcx.ins().iconst(types::I32, 0);
 
             for lane in (0..lane_count).rev() {
-                let a_lane = a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx);
+                let a_lane =
+                    a.value_field(fx, mir::Field::new(lane.try_into().unwrap())).load_scalar(fx);
 
                 // cast float to int
                 let a_lane = match lane_ty {
@@ -49,26 +46,29 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
 
             let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.i32));
             ret.write_cvalue(fx, res);
-        };
-        "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd", (c x, c y, o kind) {
-            let kind = crate::constant::mir_operand_get_const_val(fx, kind).expect("llvm.x86.sse2.cmp.* kind not const");
-            let flt_cc = match kind.try_to_bits(Size::from_bytes(1)).unwrap_or_else(|| panic!("kind not scalar: {:?}", kind)) {
+        }
+        "llvm.x86.sse2.cmp.ps" | "llvm.x86.sse2.cmp.pd" => {
+            let (x, y, kind) = match args {
+                [x, y, kind] => (x, y, kind),
+                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+            };
+            let x = codegen_operand(fx, x);
+            let y = codegen_operand(fx, y);
+            let kind = crate::constant::mir_operand_get_const_val(fx, kind)
+                .expect("llvm.x86.sse2.cmp.* kind not const");
+
+            let flt_cc = match kind
+                .try_to_bits(Size::from_bytes(1))
+                .unwrap_or_else(|| panic!("kind not scalar: {:?}", kind))
+            {
                 0 => FloatCC::Equal,
                 1 => FloatCC::LessThan,
                 2 => FloatCC::LessThanOrEqual,
-                7 => {
-                    unimplemented!("Compares corresponding elements in `a` and `b` to see if neither is `NaN`.");
-                }
-                3 => {
-                    unimplemented!("Compares corresponding elements in `a` and `b` to see if either is `NaN`.");
-                }
+                7 => FloatCC::Ordered,
+                3 => FloatCC::Unordered,
                 4 => FloatCC::NotEqual,
-                5 => {
-                    unimplemented!("not less than");
-                }
-                6 => {
-                    unimplemented!("not less than or equal");
-                }
+                5 => FloatCC::UnorderedOrGreaterThanOrEqual,
+                6 => FloatCC::UnorderedOrGreaterThan,
                 kind => unreachable!("kind {:?}", kind),
             };
 
@@ -79,50 +79,67 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
                 };
                 bool_to_zero_or_max_uint(fx, res_lane_ty, res_lane)
             });
-        };
-        "llvm.x86.sse2.psrli.d", (c a, o imm8) {
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
-                match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
-                    imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
-                    _ => fx.bcx.ins().iconst(types::I32, 0),
-                }
+        }
+        "llvm.x86.sse2.psrli.d" => {
+            let (a, imm8) = match args {
+                [a, imm8] => (a, imm8),
+                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+            };
+            let a = codegen_operand(fx, a);
+            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+                .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+                .try_to_bits(Size::from_bytes(4))
+                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+            {
+                imm8 if imm8 < 32 => fx.bcx.ins().ushr_imm(lane, i64::from(imm8 as u8)),
+                _ => fx.bcx.ins().iconst(types::I32, 0),
             });
-        };
-        "llvm.x86.sse2.pslli.d", (c a, o imm8) {
-            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8).expect("llvm.x86.sse2.psrli.d imm8 not const");
-            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| {
-                match imm8.try_to_bits(Size::from_bytes(4)).unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8)) {
-                    imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
-                    _ => fx.bcx.ins().iconst(types::I32, 0),
-                }
+        }
+        "llvm.x86.sse2.pslli.d" => {
+            let (a, imm8) = match args {
+                [a, imm8] => (a, imm8),
+                _ => bug!("wrong number of args for intrinsic {intrinsic}"),
+            };
+            let a = codegen_operand(fx, a);
+            let imm8 = crate::constant::mir_operand_get_const_val(fx, imm8)
+                .expect("llvm.x86.sse2.psrli.d imm8 not const");
+
+            simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| match imm8
+                .try_to_bits(Size::from_bytes(4))
+                .unwrap_or_else(|| panic!("imm8 not scalar: {:?}", imm8))
+            {
+                imm8 if imm8 < 32 => fx.bcx.ins().ishl_imm(lane, i64::from(imm8 as u8)),
+                _ => fx.bcx.ins().iconst(types::I32, 0),
             });
-        };
-        "llvm.x86.sse2.storeu.dq", (v mem_addr, c a) {
+        }
+        "llvm.x86.sse2.storeu.dq" => {
+            intrinsic_args!(fx, args => (mem_addr, a); intrinsic);
+            let mem_addr = mem_addr.load_scalar(fx);
+
             // FIXME correctly handle the unalignment
             let dest = CPlace::for_ptr(Pointer::new(mem_addr), a.layout());
             dest.write_cvalue(fx, a);
-        };
-        "llvm.x86.addcarry.64", (v c_in, c a, c b) {
-            llvm_add_sub(
-                fx,
-                BinOp::Add,
-                ret,
-                c_in,
-                a,
-                b
-            );
-        };
-        "llvm.x86.subborrow.64", (v b_in, c a, c b) {
-            llvm_add_sub(
-                fx,
-                BinOp::Sub,
-                ret,
-                b_in,
-                a,
-                b
-            );
-        };
+        }
+        "llvm.x86.addcarry.64" => {
+            intrinsic_args!(fx, args => (c_in, a, b); intrinsic);
+            let c_in = c_in.load_scalar(fx);
+
+            llvm_add_sub(fx, BinOp::Add, ret, c_in, a, b);
+        }
+        "llvm.x86.subborrow.64" => {
+            intrinsic_args!(fx, args => (b_in, a, b); intrinsic);
+            let b_in = b_in.load_scalar(fx);
+
+            llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
+        }
+        _ => {
+            fx.tcx
+                .sess
+                .warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
+            crate::trap::trap_unimplemented(fx, intrinsic);
+        }
     }
 
     let dest = target.expect("all llvm intrinsics used by stdlib should return");
index d5a79e254a891eb90d141d5635ee4281678ca3ba..b2a83e1d4ebc96c57da441aff4e044123a5faeed 100644 (file)
@@ -1,50 +1,14 @@
 //! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, `extern "platform-intrinsic"`
 //! and LLVM intrinsics that have symbol names starting with `llvm.`.
 
-macro_rules! intrinsic_pat {
-    (_) => {
-        _
-    };
-    ($name:ident) => {
-        sym::$name
-    };
-    (kw.$name:ident) => {
-        kw::$name
-    };
-    ($name:literal) => {
-        $name
-    };
-}
-
-macro_rules! intrinsic_arg {
-    (o $fx:expr, $arg:ident) => {};
-    (c $fx:expr, $arg:ident) => {
-        let $arg = codegen_operand($fx, $arg);
-    };
-    (v $fx:expr, $arg:ident) => {
-        let $arg = codegen_operand($fx, $arg).load_scalar($fx);
-    };
-}
-
-macro_rules! intrinsic_match {
-    ($fx:expr, $intrinsic:expr, $args:expr,
-    _ => $unknown:block;
-    $(
-        $($($name:tt).*)|+ $(if $cond:expr)?, ($($a:ident $arg:ident),*) $content:block;
-    )*) => {
-        match $intrinsic {
-            $(
-                $(intrinsic_pat!($($name).*))|* $(if $cond)? => {
-                    if let [$($arg),*] = $args {
-                        $(intrinsic_arg!($a $fx, $arg);)*
-                        $content
-                    } else {
-                        bug!("wrong number of args for intrinsic {:?}", $intrinsic);
-                    }
-                }
-            )*
-            _ => $unknown,
-        }
+macro_rules! intrinsic_args {
+    ($fx:expr, $args:expr => ($($arg:tt),*); $intrinsic:expr) => {
+        #[allow(unused_parens)]
+        let ($($arg),*) = if let [$($arg),*] = $args {
+            ($(codegen_operand($fx, $arg)),*)
+        } else {
+            $crate::intrinsics::bug_on_incorrect_arg_count($intrinsic);
+        };
     }
 }
 
@@ -62,6 +26,10 @@ macro_rules! intrinsic_match {
 use crate::prelude::*;
 use cranelift_codegen::ir::AtomicRmwOp;
 
+fn bug_on_incorrect_arg_count(intrinsic: impl std::fmt::Display) -> ! {
+    bug!("wrong number of args for intrinsic {}", intrinsic);
+}
+
 fn report_atomic_type_validation_error<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     intrinsic: Symbol,
@@ -351,28 +319,31 @@ fn codegen_regular_intrinsic_call<'tcx>(
 ) {
     let usize_layout = fx.layout_of(fx.tcx.types.usize);
 
-    intrinsic_match! {
-        fx, intrinsic, args,
-        _ => {
-            fx.tcx.sess.span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic));
-        };
+    match intrinsic {
+        sym::assume => {
+            intrinsic_args!(fx, args => (_a); intrinsic);
+        }
+        sym::likely | sym::unlikely => {
+            intrinsic_args!(fx, args => (a); intrinsic);
 
-        assume, (c _a) {};
-        likely | unlikely, (c a) {
             ret.write_cvalue(fx, a);
-        };
-        breakpoint, () {
+        }
+        sym::breakpoint => {
+            intrinsic_args!(fx, args => (); intrinsic);
+
             fx.bcx.ins().debugtrap();
-        };
-        copy | copy_nonoverlapping, (v src, v dst, v count) {
+        }
+        sym::copy | sym::copy_nonoverlapping => {
+            intrinsic_args!(fx, args => (src, dst, count); intrinsic);
+            let src = src.load_scalar(fx);
+            let dst = dst.load_scalar(fx);
+            let count = count.load_scalar(fx);
+
             let elem_ty = substs.type_at(0);
             let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
             assert_eq!(args.len(), 3);
-            let byte_amount = if elem_size != 1 {
-                fx.bcx.ins().imul_imm(count, elem_size as i64)
-            } else {
-                count
-            };
+            let byte_amount =
+                if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
 
             if intrinsic == sym::copy_nonoverlapping {
                 // FIXME emit_small_memcpy
@@ -381,17 +352,19 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 // FIXME emit_small_memmove
                 fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
             }
-        };
-        // NOTE: the volatile variants have src and dst swapped
-        volatile_copy_memory | volatile_copy_nonoverlapping_memory, (v dst, v src, v count) {
+        }
+        sym::volatile_copy_memory | sym::volatile_copy_nonoverlapping_memory => {
+            // NOTE: the volatile variants have src and dst swapped
+            intrinsic_args!(fx, args => (dst, src, count); intrinsic);
+            let dst = dst.load_scalar(fx);
+            let src = src.load_scalar(fx);
+            let count = count.load_scalar(fx);
+
             let elem_ty = substs.type_at(0);
             let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
             assert_eq!(args.len(), 3);
-            let byte_amount = if elem_size != 1 {
-                fx.bcx.ins().imul_imm(count, elem_size as i64)
-            } else {
-                count
-            };
+            let byte_amount =
+                if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
 
             // FIXME make the copy actually volatile when using emit_small_mem{cpy,move}
             if intrinsic == sym::volatile_copy_nonoverlapping_memory {
@@ -401,48 +374,64 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 // FIXME emit_small_memmove
                 fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
             }
-        };
-        size_of_val, (c ptr) {
+        }
+        sym::size_of_val => {
+            intrinsic_args!(fx, args => (ptr); intrinsic);
+
             let layout = fx.layout_of(substs.type_at(0));
-            let size = if layout.is_unsized() {
+            // Note: Can't use is_unsized here as truly unsized types need to take the fixed size
+            // branch
+            let size = if let Abi::ScalarPair(_, _) = ptr.layout().abi {
                 let (_ptr, info) = ptr.load_scalar_pair(fx);
                 let (size, _align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
                 size
             } else {
-                fx
-                    .bcx
-                    .ins()
-                    .iconst(fx.pointer_type, layout.size.bytes() as i64)
+                fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64)
             };
             ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
-        };
-        min_align_of_val, (c ptr) {
+        }
+        sym::min_align_of_val => {
+            intrinsic_args!(fx, args => (ptr); intrinsic);
+
             let layout = fx.layout_of(substs.type_at(0));
-            let align = if layout.is_unsized() {
+            // Note: Can't use is_unsized here as truly unsized types need to take the fixed size
+            // branch
+            let align = if let Abi::ScalarPair(_, _) = ptr.layout().abi {
                 let (_ptr, info) = ptr.load_scalar_pair(fx);
                 let (_size, align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
                 align
             } else {
-                fx
-                    .bcx
-                    .ins()
-                    .iconst(fx.pointer_type, layout.align.abi.bytes() as i64)
+                fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64)
             };
             ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
-        };
+        }
+
+        sym::vtable_size => {
+            intrinsic_args!(fx, args => (vtable); intrinsic);
+            let vtable = vtable.load_scalar(fx);
 
-        vtable_size, (v vtable) {
             let size = crate::vtable::size_of_obj(fx, vtable);
             ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
-        };
+        }
+
+        sym::vtable_align => {
+            intrinsic_args!(fx, args => (vtable); intrinsic);
+            let vtable = vtable.load_scalar(fx);
 
-        vtable_align, (v vtable) {
             let align = crate::vtable::min_align_of_obj(fx, vtable);
             ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
-        };
+        }
+
+        sym::unchecked_add
+        | sym::unchecked_sub
+        | sym::unchecked_mul
+        | sym::unchecked_div
+        | sym::exact_div
+        | sym::unchecked_rem
+        | sym::unchecked_shl
+        | sym::unchecked_shr => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
 
-        unchecked_add | unchecked_sub | unchecked_mul | unchecked_div | exact_div | unchecked_rem
-        | unchecked_shl | unchecked_shr, (c x, c y) {
             // FIXME trap on overflow
             let bin_op = match intrinsic {
                 sym::unchecked_add => BinOp::Add,
@@ -456,8 +445,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
             };
             let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
             ret.write_cvalue(fx, res);
-        };
-        add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) {
+        }
+        sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
             assert_eq!(x.layout().ty, y.layout().ty);
             let bin_op = match intrinsic {
                 sym::add_with_overflow => BinOp::Add,
@@ -466,15 +457,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 _ => unreachable!(),
             };
 
-            let res = crate::num::codegen_checked_int_binop(
-                fx,
-                bin_op,
-                x,
-                y,
-            );
+            let res = crate::num::codegen_checked_int_binop(fx, bin_op, x, y);
             ret.write_cvalue(fx, res);
-        };
-        saturating_add | saturating_sub, (c lhs, c rhs) {
+        }
+        sym::saturating_add | sym::saturating_sub => {
+            intrinsic_args!(fx, args => (lhs, rhs); intrinsic);
+
             assert_eq!(lhs.layout().ty, rhs.layout().ty);
             let bin_op = match intrinsic {
                 sym::saturating_add => BinOp::Add,
@@ -484,12 +472,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
             let signed = type_sign(lhs.layout().ty);
 
-            let checked_res = crate::num::codegen_checked_int_binop(
-                fx,
-                bin_op,
-                lhs,
-                rhs,
-            );
+            let checked_res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
 
             let (val, has_overflow) = checked_res.load_scalar_pair(fx);
             let clif_ty = fx.clif_type(lhs.layout().ty).unwrap();
@@ -501,13 +484,15 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
                 (sym::saturating_add, true) => {
                     let rhs = rhs.load_scalar(fx);
-                    let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
+                    let rhs_ge_zero =
+                        fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
                     let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
                     fx.bcx.ins().select(has_overflow, sat_val, val)
                 }
                 (sym::saturating_sub, true) => {
                     let rhs = rhs.load_scalar(fx);
-                    let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
+                    let rhs_ge_zero =
+                        fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
                     let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
                     fx.bcx.ins().select(has_overflow, sat_val, val)
                 }
@@ -517,23 +502,32 @@ fn codegen_regular_intrinsic_call<'tcx>(
             let res = CValue::by_val(val, lhs.layout());
 
             ret.write_cvalue(fx, res);
-        };
-        rotate_left, (c x, v y) {
+        }
+        sym::rotate_left => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+            let y = y.load_scalar(fx);
+
             let layout = x.layout();
             let x = x.load_scalar(fx);
             let res = fx.bcx.ins().rotl(x, y);
             ret.write_cvalue(fx, CValue::by_val(res, layout));
-        };
-        rotate_right, (c x, v y) {
+        }
+        sym::rotate_right => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+            let y = y.load_scalar(fx);
+
             let layout = x.layout();
             let x = x.load_scalar(fx);
             let res = fx.bcx.ins().rotr(x, y);
             ret.write_cvalue(fx, CValue::by_val(res, layout));
-        };
+        }
 
         // The only difference between offset and arith_offset is regarding UB. Because Cranelift
         // doesn't have UB both are codegen'ed the same way
-        offset | arith_offset, (c base, v offset) {
+        sym::offset | sym::arith_offset => {
+            intrinsic_args!(fx, args => (base, offset); intrinsic);
+            let offset = offset.load_scalar(fx);
+
             let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
             let pointee_size = fx.layout_of(pointee_ty).size.bytes();
             let ptr_diff = if pointee_size != 1 {
@@ -544,12 +538,18 @@ fn codegen_regular_intrinsic_call<'tcx>(
             let base_val = base.load_scalar(fx);
             let res = fx.bcx.ins().iadd(base_val, ptr_diff);
             ret.write_cvalue(fx, CValue::by_val(res, base.layout()));
-        };
+        }
+
+        sym::transmute => {
+            intrinsic_args!(fx, args => (from); intrinsic);
 
-        transmute, (c from) {
             ret.write_cvalue_transmute(fx, from);
-        };
-        write_bytes | volatile_set_memory, (c dst, v val, v count) {
+        }
+        sym::write_bytes | sym::volatile_set_memory => {
+            intrinsic_args!(fx, args => (dst, val, count); intrinsic);
+            let val = val.load_scalar(fx);
+            let count = count.load_scalar(fx);
+
             let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty;
             let pointee_size = fx.layout_of(pointee_ty).size.bytes();
             let count = if pointee_size != 1 {
@@ -561,34 +561,42 @@ fn codegen_regular_intrinsic_call<'tcx>(
             // FIXME make the memset actually volatile when switching to emit_small_memset
             // FIXME use emit_small_memset
             fx.bcx.call_memset(fx.target_config, dst_ptr, val, count);
-        };
-        ctlz | ctlz_nonzero, (c arg) {
+        }
+        sym::ctlz | sym::ctlz_nonzero => {
+            intrinsic_args!(fx, args => (arg); intrinsic);
             let val = arg.load_scalar(fx);
+
             // FIXME trap on `ctlz_nonzero` with zero arg.
             let res = fx.bcx.ins().clz(val);
             let res = CValue::by_val(res, arg.layout());
             ret.write_cvalue(fx, res);
-        };
-        cttz | cttz_nonzero, (c arg) {
+        }
+        sym::cttz | sym::cttz_nonzero => {
+            intrinsic_args!(fx, args => (arg); intrinsic);
             let val = arg.load_scalar(fx);
+
             // FIXME trap on `cttz_nonzero` with zero arg.
             let res = fx.bcx.ins().ctz(val);
             let res = CValue::by_val(res, arg.layout());
             ret.write_cvalue(fx, res);
-        };
-        ctpop, (c arg) {
+        }
+        sym::ctpop => {
+            intrinsic_args!(fx, args => (arg); intrinsic);
             let val = arg.load_scalar(fx);
+
             let res = fx.bcx.ins().popcnt(val);
             let res = CValue::by_val(res, arg.layout());
             ret.write_cvalue(fx, res);
-        };
-        bitreverse, (c arg) {
+        }
+        sym::bitreverse => {
+            intrinsic_args!(fx, args => (arg); intrinsic);
             let val = arg.load_scalar(fx);
+
             let res = fx.bcx.ins().bitrev(val);
             let res = CValue::by_val(res, arg.layout());
             ret.write_cvalue(fx, res);
-        };
-        bswap, (c arg) {
+        }
+        sym::bswap => {
             // FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift
             fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 match bcx.func.dfg.value_type(v) {
@@ -664,11 +672,15 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                     ty => unreachable!("bswap {}", ty),
                 }
             }
+            intrinsic_args!(fx, args => (arg); intrinsic);
             let val = arg.load_scalar(fx);
+
             let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout());
             ret.write_cvalue(fx, res);
-        };
-        assert_inhabited | assert_zero_valid | assert_uninit_valid, () {
+        }
+        sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
+            intrinsic_args!(fx, args => (); intrinsic);
+
             let layout = fx.layout_of(substs.type_at(0));
             if layout.abi.is_uninhabited() {
                 with_no_trimmed_paths!({
@@ -685,7 +697,10 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 with_no_trimmed_paths!({
                     crate::base::codegen_panic(
                         fx,
-                        &format!("attempted to zero-initialize type `{}`, which is invalid", layout.ty),
+                        &format!(
+                            "attempted to zero-initialize type `{}`, which is invalid",
+                            layout.ty
+                        ),
                         source_info,
                     );
                 });
@@ -696,41 +711,53 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 with_no_trimmed_paths!({
                     crate::base::codegen_panic(
                         fx,
-                        &format!("attempted to leave type `{}` uninitialized, which is invalid", layout.ty),
+                        &format!(
+                            "attempted to leave type `{}` uninitialized, which is invalid",
+                            layout.ty
+                        ),
                         source_info,
                     )
                 });
                 return;
             }
-        };
+        }
+
+        sym::volatile_load | sym::unaligned_volatile_load => {
+            intrinsic_args!(fx, args => (ptr); intrinsic);
 
-        volatile_load | unaligned_volatile_load, (c ptr) {
             // Cranelift treats loads as volatile by default
             // FIXME correctly handle unaligned_volatile_load
-            let inner_layout =
-                fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
+            let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
             let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout);
             ret.write_cvalue(fx, val);
-        };
-        volatile_store | unaligned_volatile_store, (v ptr, c val) {
+        }
+        sym::volatile_store | sym::unaligned_volatile_store => {
+            intrinsic_args!(fx, args => (ptr, val); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             // Cranelift treats stores as volatile by default
             // FIXME correctly handle unaligned_volatile_store
             let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
             dest.write_cvalue(fx, val);
-        };
+        }
+
+        sym::pref_align_of
+        | sym::needs_drop
+        | sym::type_id
+        | sym::type_name
+        | sym::variant_count => {
+            intrinsic_args!(fx, args => (); intrinsic);
 
-        pref_align_of | needs_drop | type_id | type_name | variant_count, () {
             let const_val =
                 fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
-            let val = crate::constant::codegen_const_value(
-                fx,
-                const_val,
-                ret.layout().ty,
-            );
+            let val = crate::constant::codegen_const_value(fx, const_val, ret.layout().ty);
             ret.write_cvalue(fx, val);
-        };
+        }
 
-        ptr_offset_from | ptr_offset_from_unsigned, (v ptr, v base) {
+        sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
+            intrinsic_args!(fx, args => (ptr, base); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+            let base = base.load_scalar(fx);
             let ty = substs.type_at(0);
 
             let pointee_size: u64 = fx.layout_of(ty).size.bytes();
@@ -746,31 +773,44 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 CValue::by_val(fx.bcx.ins().sdiv_imm(diff_bytes, pointee_size as i64), isize_layout)
             };
             ret.write_cvalue(fx, val);
-        };
+        }
+
+        sym::ptr_guaranteed_eq => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
 
-        ptr_guaranteed_eq, (c a, c b) {
             let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
             ret.write_cvalue(fx, val);
-        };
+        }
+
+        sym::ptr_guaranteed_ne => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
 
-        ptr_guaranteed_ne, (c a, c b) {
             let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b);
             ret.write_cvalue(fx, val);
-        };
+        }
+
+        sym::caller_location => {
+            intrinsic_args!(fx, args => (); intrinsic);
 
-        caller_location, () {
             let caller_location = fx.get_caller_location(source_info);
             ret.write_cvalue(fx, caller_location);
-        };
+        }
+
+        _ if intrinsic.as_str().starts_with("atomic_fence") => {
+            intrinsic_args!(fx, args => (); intrinsic);
 
-        _ if intrinsic.as_str().starts_with("atomic_fence"), () {
             fx.bcx.ins().fence();
-        };
-        _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_singlethreadfence") => {
+            intrinsic_args!(fx, args => (); intrinsic);
+
             // FIXME use a compiler fence once Cranelift supports it
             fx.bcx.ins().fence();
-        };
-        _ if intrinsic.as_str().starts_with("atomic_load"), (v ptr) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_load") => {
+            intrinsic_args!(fx, args => (ptr); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let ty = substs.type_at(0);
             match ty.kind() {
                 ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
@@ -782,7 +822,9 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                         fx.bcx.ins().jump(ret_block, &[]);
                         return;
                     } else {
-                        fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
+                        fx.tcx
+                            .sess
+                            .span_fatal(source_info.span, "128bit atomics not yet supported");
                     }
                 }
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -797,8 +839,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let val = CValue::by_val(val, fx.layout_of(ty));
             ret.write_cvalue(fx, val);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_store") => {
+            intrinsic_args!(fx, args => (ptr, val); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let ty = substs.type_at(0);
             match ty.kind() {
                 ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
@@ -810,7 +855,9 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                         fx.bcx.ins().jump(ret_block, &[]);
                         return;
                     } else {
-                        fx.tcx.sess.span_fatal(source_info.span, "128bit atomics not yet supported");
+                        fx.tcx
+                            .sess
+                            .span_fatal(source_info.span, "128bit atomics not yet supported");
                     }
                 }
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -823,8 +870,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let val = val.load_scalar(fx);
 
             fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_xchg") => {
+            intrinsic_args!(fx, args => (ptr, new); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = new.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -841,8 +891,12 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
+        }
+        _ if intrinsic.as_str().starts_with("atomic_cxchg") => {
+            // both atomic_cxchg_* and atomic_cxchgweak_*
+            intrinsic_args!(fx, args => (ptr, test_old, new); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = new.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -858,11 +912,15 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new);
             let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old);
 
-            let ret_val = CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
+            let ret_val =
+                CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
             ret.write_cvalue(fx, ret_val)
-        };
+        }
+
+        _ if intrinsic.as_str().starts_with("atomic_xadd") => {
+            intrinsic_args!(fx, args => (ptr, amount); intrinsic);
+            let ptr = ptr.load_scalar(fx);
 
-        _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) {
             let layout = amount.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -875,12 +933,16 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let amount = amount.load_scalar(fx);
 
-            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount);
+            let old =
+                fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount);
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_xsub") => {
+            intrinsic_args!(fx, args => (ptr, amount); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = amount.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -893,12 +955,16 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let amount = amount.load_scalar(fx);
 
-            let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount);
+            let old =
+                fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount);
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_and") => {
+            intrinsic_args!(fx, args => (ptr, src); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = src.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -915,8 +981,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_or") => {
+            intrinsic_args!(fx, args => (ptr, src); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = src.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -933,8 +1002,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_xor") => {
+            intrinsic_args!(fx, args => (ptr, src); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = src.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -951,8 +1023,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_nand") => {
+            intrinsic_args!(fx, args => (ptr, src); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = src.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -969,8 +1044,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_max") => {
+            intrinsic_args!(fx, args => (ptr, src); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = src.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -987,8 +1065,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_umax") => {
+            intrinsic_args!(fx, args => (ptr, src); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = src.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -1005,8 +1086,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_min") => {
+            intrinsic_args!(fx, args => (ptr, src); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = src.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -1023,8 +1107,11 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
-        _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) {
+        }
+        _ if intrinsic.as_str().starts_with("atomic_umin") => {
+            intrinsic_args!(fx, args => (ptr, src); intrinsic);
+            let ptr = ptr.load_scalar(fx);
+
             let layout = src.layout();
             match layout.ty.kind() {
                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
@@ -1041,30 +1128,51 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
 
             let old = CValue::by_val(old, layout);
             ret.write_cvalue(fx, old);
-        };
+        }
+
+        sym::minnumf32 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
 
-        minnumf32, (v a, v b) {
             let val = crate::num::codegen_float_min(fx, a, b);
             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
             ret.write_cvalue(fx, val);
-        };
-        minnumf64, (v a, v b) {
+        }
+        sym::minnumf64 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
             let val = crate::num::codegen_float_min(fx, a, b);
             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
             ret.write_cvalue(fx, val);
-        };
-        maxnumf32, (v a, v b) {
+        }
+        sym::maxnumf32 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
             let val = crate::num::codegen_float_max(fx, a, b);
             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
             ret.write_cvalue(fx, val);
-        };
-        maxnumf64, (v a, v b) {
+        }
+        sym::maxnumf64 => {
+            intrinsic_args!(fx, args => (a, b); intrinsic);
+            let a = a.load_scalar(fx);
+            let b = b.load_scalar(fx);
+
             let val = crate::num::codegen_float_max(fx, a, b);
             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
             ret.write_cvalue(fx, val);
-        };
+        }
+
+        kw::Try => {
+            intrinsic_args!(fx, args => (f, data, catch_fn); intrinsic);
+            let f = f.load_scalar(fx);
+            let data = data.load_scalar(fx);
+            let _catch_fn = catch_fn.load_scalar(fx);
 
-        kw.Try, (v f, v data, v _catch_fn) {
             // FIXME once unwinding is supported, change this to actually catch panics
             let f_sig = fx.bcx.func.import_signature(Signature {
                 call_conv: fx.target_config.default_call_conv,
@@ -1077,20 +1185,30 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
             let layout = ret.layout();
             let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
             ret.write_cvalue(fx, ret_val);
-        };
+        }
 
-        fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) {
-            let res = crate::num::codegen_float_binop(fx, match intrinsic {
-                sym::fadd_fast => BinOp::Add,
-                sym::fsub_fast => BinOp::Sub,
-                sym::fmul_fast => BinOp::Mul,
-                sym::fdiv_fast => BinOp::Div,
-                sym::frem_fast => BinOp::Rem,
-                _ => unreachable!(),
-            }, x, y);
+        sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
+
+            let res = crate::num::codegen_float_binop(
+                fx,
+                match intrinsic {
+                    sym::fadd_fast => BinOp::Add,
+                    sym::fsub_fast => BinOp::Sub,
+                    sym::fmul_fast => BinOp::Mul,
+                    sym::fdiv_fast => BinOp::Div,
+                    sym::frem_fast => BinOp::Rem,
+                    _ => unreachable!(),
+                },
+                x,
+                y,
+            );
             ret.write_cvalue(fx, res);
-        };
-        float_to_int_unchecked, (v f) {
+        }
+        sym::float_to_int_unchecked => {
+            intrinsic_args!(fx, args => (f); intrinsic);
+            let f = f.load_scalar(fx);
+
             let res = crate::cast::clif_int_or_float_cast(
                 fx,
                 f,
@@ -1099,52 +1217,74 @@ fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
                 type_sign(ret.layout().ty),
             );
             ret.write_cvalue(fx, CValue::by_val(res, ret.layout()));
-        };
+        }
+
+        sym::raw_eq => {
+            intrinsic_args!(fx, args => (lhs_ref, rhs_ref); intrinsic);
+            let lhs_ref = lhs_ref.load_scalar(fx);
+            let rhs_ref = rhs_ref.load_scalar(fx);
 
-        raw_eq, (v lhs_ref, v rhs_ref) {
             let size = fx.layout_of(substs.type_at(0)).layout.size();
             // FIXME add and use emit_small_memcmp
-            let is_eq_value =
-                if size == Size::ZERO {
-                    // No bytes means they're trivially equal
-                    fx.bcx.ins().iconst(types::I8, 1)
-                } else if let Some(clty) = size.bits().try_into().ok().and_then(Type::int) {
-                    // Can't use `trusted` for these loads; they could be unaligned.
-                    let mut flags = MemFlags::new();
-                    flags.set_notrap();
-                    let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
-                    let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
-                    let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
-                    fx.bcx.ins().bint(types::I8, eq)
-                } else {
-                    // Just call `memcmp` (like slices do in core) when the
-                    // size is too large or it's not a power-of-two.
-                    let signed_bytes = i64::try_from(size.bytes()).unwrap();
-                    let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes);
-                    let params = vec![AbiParam::new(fx.pointer_type); 3];
-                    let returns = vec![AbiParam::new(types::I32)];
-                    let args = &[lhs_ref, rhs_ref, bytes_val];
-                    let cmp = fx.lib_call("memcmp", params, returns, args)[0];
-                    let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
-                    fx.bcx.ins().bint(types::I8, eq)
-                };
+            let is_eq_value = if size == Size::ZERO {
+                // No bytes means they're trivially equal
+                fx.bcx.ins().iconst(types::I8, 1)
+            } else if let Some(clty) = size.bits().try_into().ok().and_then(Type::int) {
+                // Can't use `trusted` for these loads; they could be unaligned.
+                let mut flags = MemFlags::new();
+                flags.set_notrap();
+                let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
+                let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
+                let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
+                fx.bcx.ins().bint(types::I8, eq)
+            } else {
+                // Just call `memcmp` (like slices do in core) when the
+                // size is too large or it's not a power-of-two.
+                let signed_bytes = i64::try_from(size.bytes()).unwrap();
+                let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes);
+                let params = vec![AbiParam::new(fx.pointer_type); 3];
+                let returns = vec![AbiParam::new(types::I32)];
+                let args = &[lhs_ref, rhs_ref, bytes_val];
+                let cmp = fx.lib_call("memcmp", params, returns, args)[0];
+                let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
+                fx.bcx.ins().bint(types::I8, eq)
+            };
             ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
-        };
+        }
+
+        sym::const_allocate => {
+            intrinsic_args!(fx, args => (_size, _align); intrinsic);
 
-        const_allocate, (c _size, c _align) {
             // returns a null pointer at runtime.
             let null = fx.bcx.ins().iconst(fx.pointer_type, 0);
             ret.write_cvalue(fx, CValue::by_val(null, ret.layout()));
-        };
+        }
 
-        const_deallocate, (c _ptr, c _size, c _align) {
+        sym::const_deallocate => {
+            intrinsic_args!(fx, args => (_ptr, _size, _align); intrinsic);
             // nop at runtime.
-        };
+        }
+
+        sym::black_box => {
+            intrinsic_args!(fx, args => (a); intrinsic);
 
-        black_box, (c a) {
             // FIXME implement black_box semantics
             ret.write_cvalue(fx, a);
-        };
+        }
+
+        // FIXME implement variadics in cranelift
+        sym::va_copy | sym::va_arg | sym::va_end => {
+            fx.tcx.sess.span_fatal(
+                source_info.span,
+                "Defining variadic functions is not yet supported by Cranelift",
+            );
+        }
+
+        _ => {
+            fx.tcx
+                .sess
+                .span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic));
+        }
     }
 
     let ret_block = fx.get_block(destination.unwrap());
index d1ca9edf2e0f1bb578889566bc8384c5bf5bfc1c..30e3d112594a6d60beb75bb8459ffeb485d1ec6d 100644 (file)
@@ -25,13 +25,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
     ret: CPlace<'tcx>,
     span: Span,
 ) {
-    intrinsic_match! {
-        fx, intrinsic, args,
-        _ => {
-            fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
-        };
+    match intrinsic {
+        sym::simd_cast => {
+            intrinsic_args!(fx, args => (a); intrinsic);
 
-        simd_cast, (c a) {
             if !a.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
                 return;
@@ -45,9 +42,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
 
                 clif_int_or_float_cast(fx, lane, from_signed, ret_lane_clif_ty, to_signed)
             });
-        };
+        }
+
+        sym::simd_eq | sym::simd_ne | sym::simd_lt | sym::simd_le | sym::simd_gt | sym::simd_ge => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
 
-        simd_eq | simd_ne | simd_lt | simd_le | simd_gt | simd_ge, (c x, c y) {
             if !x.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
                 return;
@@ -57,7 +56,9 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| {
                 let res_lane = match (lane_ty.kind(), intrinsic) {
                     (ty::Uint(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane),
-                    (ty::Uint(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_ne) => {
+                        fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane)
+                    }
                     (ty::Uint(_), sym::simd_lt) => {
                         fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane)
                     }
@@ -72,8 +73,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     }
 
                     (ty::Int(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane),
-                    (ty::Int(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane),
-                    (ty::Int(_), sym::simd_lt) => fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane),
+                    (ty::Int(_), sym::simd_ne) => {
+                        fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane)
+                    }
+                    (ty::Int(_), sym::simd_lt) => {
+                        fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane)
+                    }
                     (ty::Int(_), sym::simd_le) => {
                         fx.bcx.ins().icmp(IntCC::SignedLessThanOrEqual, x_lane, y_lane)
                     }
@@ -84,13 +89,21 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                         fx.bcx.ins().icmp(IntCC::SignedGreaterThanOrEqual, x_lane, y_lane)
                     }
 
-                    (ty::Float(_), sym::simd_eq) => fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane),
-                    (ty::Float(_), sym::simd_ne) => fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane),
-                    (ty::Float(_), sym::simd_lt) => fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane),
+                    (ty::Float(_), sym::simd_eq) => {
+                        fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane)
+                    }
+                    (ty::Float(_), sym::simd_ne) => {
+                        fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane)
+                    }
+                    (ty::Float(_), sym::simd_lt) => {
+                        fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane)
+                    }
                     (ty::Float(_), sym::simd_le) => {
                         fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, x_lane, y_lane)
                     }
-                    (ty::Float(_), sym::simd_gt) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane),
+                    (ty::Float(_), sym::simd_gt) => {
+                        fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane)
+                    }
                     (ty::Float(_), sym::simd_ge) => {
                         fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, x_lane, y_lane)
                     }
@@ -103,10 +116,19 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let res_lane = fx.bcx.ins().bint(ty, res_lane);
                 fx.bcx.ins().ineg(res_lane)
             });
-        };
+        }
 
         // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
-        _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) {
+        _ if intrinsic.as_str().starts_with("simd_shuffle") => {
+            let (x, y, idx) = match args {
+                [x, y, idx] => (x, y, idx),
+                _ => {
+                    bug!("wrong number of args for intrinsic {intrinsic}");
+                }
+            };
+            let x = codegen_operand(fx, x);
+            let y = codegen_operand(fx, y);
+
             if !x.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
                 return;
@@ -119,11 +141,13 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 // version of this intrinsic.
                 let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx));
                 match idx_ty.kind() {
-                    ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
-                        len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
+                    ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len
+                        .try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all())
+                        .unwrap_or_else(|| {
                             span_bug!(span, "could not evaluate shuffle index array length")
-                        }).try_into().unwrap()
-                    }
+                        })
+                        .try_into()
+                        .unwrap(),
                     _ => {
                         fx.tcx.sess.span_err(
                             span,
@@ -154,24 +178,30 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
 
             let indexes = {
                 use rustc_middle::mir::interpret::*;
-                let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const");
+                let idx_const = crate::constant::mir_operand_get_const_val(fx, idx)
+                    .expect("simd_shuffle* idx not const");
 
                 let idx_bytes = match idx_const {
                     ConstValue::ByRef { alloc, offset } => {
-                        let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */);
+                        let size = Size::from_bytes(
+                            4 * ret_lane_count, /* size_of([u32; ret_lane_count]) */
+                        );
                         alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap()
                     }
                     _ => unreachable!("{:?}", idx_const),
                 };
 
-                (0..ret_lane_count).map(|i| {
-                    let i = usize::try_from(i).unwrap();
-                    let idx = rustc_middle::mir::interpret::read_target_uint(
-                        fx.tcx.data_layout.endian,
-                        &idx_bytes[4*i.. 4*i + 4],
-                    ).expect("read_target_uint");
-                    u16::try_from(idx).expect("try_from u32")
-                }).collect::<Vec<u16>>()
+                (0..ret_lane_count)
+                    .map(|i| {
+                        let i = usize::try_from(i).unwrap();
+                        let idx = rustc_middle::mir::interpret::read_target_uint(
+                            fx.tcx.data_layout.endian,
+                            &idx_bytes[4 * i..4 * i + 4],
+                        )
+                        .expect("read_target_uint");
+                        u16::try_from(idx).expect("try_from u32")
+                    })
+                    .collect::<Vec<u16>>()
             };
 
             for &idx in &indexes {
@@ -187,43 +217,63 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let out_lane = ret.place_lane(fx, u64::try_from(out_idx).unwrap());
                 out_lane.write_cvalue(fx, in_lane);
             }
-        };
+        }
+
+        sym::simd_insert => {
+            let (base, idx, val) = match args {
+                [base, idx, val] => (base, idx, val),
+                _ => {
+                    bug!("wrong number of args for intrinsic {intrinsic}");
+                }
+            };
+            let base = codegen_operand(fx, base);
+            let val = codegen_operand(fx, val);
 
-        simd_insert, (c base, o idx, c val) {
             // FIXME validate
-            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
+            let idx_const = if let Some(idx_const) =
+                crate::constant::mir_operand_get_const_val(fx, idx)
+            {
                 idx_const
             } else {
-                fx.tcx.sess.span_fatal(
-                    span,
-                    "Index argument for `simd_insert` is not a constant",
-                );
+                fx.tcx.sess.span_fatal(span, "Index argument for `simd_insert` is not a constant");
             };
 
-            let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
+            let idx = idx_const
+                .try_to_bits(Size::from_bytes(4 /* u32*/))
+                .unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
             let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
             if idx >= lane_count.into() {
-                fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
+                fx.tcx.sess.span_fatal(
+                    fx.mir.span,
+                    &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count),
+                );
             }
 
             ret.write_cvalue(fx, base);
             let ret_lane = ret.place_field(fx, mir::Field::new(idx.try_into().unwrap()));
             ret_lane.write_cvalue(fx, val);
-        };
+        }
+
+        sym::simd_extract => {
+            let (v, idx) = match args {
+                [v, idx] => (v, idx),
+                _ => {
+                    bug!("wrong number of args for intrinsic {intrinsic}");
+                }
+            };
+            let v = codegen_operand(fx, v);
 
-        simd_extract, (c v, o idx) {
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
                 return;
             }
 
-            let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
+            let idx_const = if let Some(idx_const) =
+                crate::constant::mir_operand_get_const_val(fx, idx)
+            {
                 idx_const
             } else {
-                fx.tcx.sess.span_warn(
-                    span,
-                    "Index argument for `simd_extract` is not a constant",
-                );
+                fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant");
                 let res = crate::trap::trap_unimplemented_ret_value(
                     fx,
                     ret.layout(),
@@ -233,89 +283,105 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 return;
             };
 
-            let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
+            let idx = idx_const
+                .try_to_bits(Size::from_bytes(4 /* u32*/))
+                .unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
             let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
             if idx >= lane_count.into() {
-                fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
+                fx.tcx.sess.span_fatal(
+                    fx.mir.span,
+                    &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count),
+                );
             }
 
             let ret_lane = v.value_lane(fx, idx.try_into().unwrap());
             ret.write_cvalue(fx, ret_lane);
-        };
+        }
+
+        sym::simd_neg => {
+            intrinsic_args!(fx, args => (a); intrinsic);
 
-        simd_neg, (c a) {
             if !a.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
                 return;
             }
 
-            simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
-                match lane_ty.kind() {
+            simd_for_each_lane(
+                fx,
+                a,
+                ret,
+                &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() {
                     ty::Int(_) => fx.bcx.ins().ineg(lane),
                     ty::Float(_) => fx.bcx.ins().fneg(lane),
                     _ => unreachable!(),
-                }
-            });
-        };
-
-        simd_add | simd_sub | simd_mul | simd_div | simd_rem
-        | simd_shl | simd_shr | simd_and | simd_or | simd_xor, (c x, c y) {
-            if !x.layout().ty.is_simd() {
-                report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
-                return;
-            }
+                },
+            );
+        }
+
+        sym::simd_add
+        | sym::simd_sub
+        | sym::simd_mul
+        | sym::simd_div
+        | sym::simd_rem
+        | sym::simd_shl
+        | sym::simd_shr
+        | sym::simd_and
+        | sym::simd_or
+        | sym::simd_xor => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
 
             // FIXME use vector instructions when possible
-            simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| match (
-                lane_ty.kind(),
-                intrinsic,
-            ) {
-                (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
-                (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
-                (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
-                (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane),
-                (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane),
-
-                (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
-                (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
-                (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
-                (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane),
-                (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane),
-
-                (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane),
-                (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane),
-                (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane),
-                (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane),
-                (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call(
-                    "fmodf",
-                    vec![AbiParam::new(types::F32), AbiParam::new(types::F32)],
-                    vec![AbiParam::new(types::F32)],
-                    &[x_lane, y_lane],
-                )[0],
-                (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call(
-                    "fmod",
-                    vec![AbiParam::new(types::F64), AbiParam::new(types::F64)],
-                    vec![AbiParam::new(types::F64)],
-                    &[x_lane, y_lane],
-                )[0],
-
-                (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
-                (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane),
-                (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
-                (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
-                (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
-
-                (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
-                (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane),
-                (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
-                (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
-                (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
-
-                _ => unreachable!(),
+            simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| {
+                match (lane_ty.kind(), intrinsic) {
+                    (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane),
+
+                    (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane),
+                    (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane),
+                    (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane),
+                    (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane),
+                    (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane),
+
+                    (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane),
+                    (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane),
+                    (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane),
+                    (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane),
+                    (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call(
+                        "fmodf",
+                        vec![AbiParam::new(types::F32), AbiParam::new(types::F32)],
+                        vec![AbiParam::new(types::F32)],
+                        &[x_lane, y_lane],
+                    )[0],
+                    (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call(
+                        "fmod",
+                        vec![AbiParam::new(types::F64), AbiParam::new(types::F64)],
+                        vec![AbiParam::new(types::F64)],
+                        &[x_lane, y_lane],
+                    )[0],
+
+                    (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
+                    (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
+
+                    (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane),
+                    (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane),
+                    (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane),
+                    (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane),
+                    (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane),
+
+                    _ => unreachable!(),
+                }
             });
-        };
+        }
+
+        sym::simd_fma => {
+            intrinsic_args!(fx, args => (a, b, c); intrinsic);
 
-        simd_fma, (c a, c b, c c) {
             if !a.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
                 return;
@@ -333,16 +399,22 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let c_lane = c.value_lane(fx, lane);
 
                 let res_lane = match lane_ty.kind() {
-                    ty::Float(FloatTy::F32) => fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty),
-                    ty::Float(FloatTy::F64) => fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty),
+                    ty::Float(FloatTy::F32) => {
+                        fx.easy_call("fmaf", &[a_lane, b_lane, c_lane], lane_ty)
+                    }
+                    ty::Float(FloatTy::F64) => {
+                        fx.easy_call("fma", &[a_lane, b_lane, c_lane], lane_ty)
+                    }
                     _ => unreachable!(),
                 };
 
                 ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
             }
-        };
+        }
+
+        sym::simd_fmin | sym::simd_fmax => {
+            intrinsic_args!(fx, args => (x, y); intrinsic);
 
-        simd_fmin | simd_fmax, (c x, c y) {
             if !x.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty);
                 return;
@@ -351,7 +423,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             // FIXME use vector instructions when possible
             simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| {
                 match lane_ty.kind() {
-                    ty::Float(_) => {},
+                    ty::Float(_) => {}
                     _ => unreachable!("{:?}", lane_ty),
                 }
                 match intrinsic {
@@ -360,16 +432,21 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     _ => unreachable!(),
                 }
             });
-        };
+        }
+
+        sym::simd_round => {
+            intrinsic_args!(fx, args => (a); intrinsic);
 
-        simd_round, (c a) {
             if !a.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
                 return;
             }
 
-            simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
-                match lane_ty.kind() {
+            simd_for_each_lane(
+                fx,
+                a,
+                ret,
+                &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() {
                     ty::Float(FloatTy::F32) => fx.lib_call(
                         "roundf",
                         vec![AbiParam::new(types::F32)],
@@ -383,11 +460,13 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                         &[lane],
                     )[0],
                     _ => unreachable!("{:?}", lane_ty),
-                }
-            });
-        };
+                },
+            );
+        }
+
+        sym::simd_fabs | sym::simd_fsqrt | sym::simd_ceil | sym::simd_floor | sym::simd_trunc => {
+            intrinsic_args!(fx, args => (a); intrinsic);
 
-        simd_fabs | simd_fsqrt | simd_ceil | simd_floor | simd_trunc, (c a) {
             if !a.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty);
                 return;
@@ -395,7 +474,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
 
             simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| {
                 match lane_ty.kind() {
-                    ty::Float(_) => {},
+                    ty::Float(_) => {}
                     _ => unreachable!("{:?}", lane_ty),
                 }
                 match intrinsic {
@@ -407,9 +486,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     _ => unreachable!(),
                 }
             });
-        };
+        }
+
+        sym::simd_reduce_add_ordered | sym::simd_reduce_add_unordered => {
+            intrinsic_args!(fx, args => (v, acc); intrinsic);
+            let acc = acc.load_scalar(fx);
 
-        simd_reduce_add_ordered | simd_reduce_add_unordered, (c v, v acc) {
             // FIXME there must be no acc param for integer vectors
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
@@ -423,9 +505,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     fx.bcx.ins().iadd(a, b)
                 }
             });
-        };
+        }
+
+        sym::simd_reduce_mul_ordered | sym::simd_reduce_mul_unordered => {
+            intrinsic_args!(fx, args => (v, acc); intrinsic);
+            let acc = acc.load_scalar(fx);
 
-        simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v, v acc) {
             // FIXME there must be no acc param for integer vectors
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
@@ -439,54 +524,66 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     fx.bcx.ins().imul(a, b)
                 }
             });
-        };
+        }
+
+        sym::simd_reduce_all => {
+            intrinsic_args!(fx, args => (v); intrinsic);
 
-        simd_reduce_all, (c v) {
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
                 return;
             }
 
             simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().band(a, b));
-        };
+        }
+
+        sym::simd_reduce_any => {
+            intrinsic_args!(fx, args => (v); intrinsic);
 
-        simd_reduce_any, (c v) {
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
                 return;
             }
 
             simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().bor(a, b));
-        };
+        }
+
+        sym::simd_reduce_and => {
+            intrinsic_args!(fx, args => (v); intrinsic);
 
-        simd_reduce_and, (c v) {
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
                 return;
             }
 
             simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().band(a, b));
-        };
+        }
+
+        sym::simd_reduce_or => {
+            intrinsic_args!(fx, args => (v); intrinsic);
 
-        simd_reduce_or, (c v) {
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
                 return;
             }
 
             simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bor(a, b));
-        };
+        }
+
+        sym::simd_reduce_xor => {
+            intrinsic_args!(fx, args => (v); intrinsic);
 
-        simd_reduce_xor, (c v) {
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
                 return;
             }
 
             simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bxor(a, b));
-        };
+        }
+
+        sym::simd_reduce_min => {
+            intrinsic_args!(fx, args => (v); intrinsic);
 
-        simd_reduce_min, (c v) {
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
                 return;
@@ -501,9 +598,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 };
                 fx.bcx.ins().select(lt, a, b)
             });
-        };
+        }
+
+        sym::simd_reduce_max => {
+            intrinsic_args!(fx, args => (v); intrinsic);
 
-        simd_reduce_max, (c v) {
             if !v.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty);
                 return;
@@ -518,9 +617,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 };
                 fx.bcx.ins().select(gt, a, b)
             });
-        };
+        }
+
+        sym::simd_select => {
+            intrinsic_args!(fx, args => (m, a, b); intrinsic);
 
-        simd_select, (c m, c a, c b) {
             if !m.layout().ty.is_simd() {
                 report_simd_type_validation_error(fx, intrinsic, span, m.layout().ty);
                 return;
@@ -540,15 +641,19 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 let b_lane = b.value_lane(fx, lane).load_scalar(fx);
 
                 let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0);
-                let res_lane = CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout);
+                let res_lane =
+                    CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout);
 
                 ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
             }
-        };
+        }
 
         // simd_saturating_*
         // simd_bitmask
         // simd_scatter
         // simd_gather
+        _ => {
+            fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
+        }
     }
 }
index 3ed3453c6c7b32f3b6e15310d04ad64e17b54d86..568bb20a3f4a7614ab35b22a8931291695e824be 100644 (file)
@@ -141,7 +141,11 @@ fn new(
 
         let unwind_context =
             UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
-        let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
+        let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows {
+            Some(DebugContext::new(tcx, isa))
+        } else {
+            None
+        };
         CodegenCx {
             tcx,
             global_asm: String::new(),
@@ -243,6 +247,7 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
     flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
     let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
     flags_builder.set("enable_verifier", enable_verifier).unwrap();
+    flags_builder.set("regalloc_checker", enable_verifier).unwrap();
 
     let tls_model = match target_triple.binary_format {
         BinaryFormat::Elf => "elf_gd",
index 2f71a70a4494615529fd859c4d86c3178a5fe0c0..c67b6e98b32c7daeeca8558ed2882f082cd0b103 100644 (file)
@@ -109,7 +109,8 @@ fn create_entry_fn(
                     tcx.mk_substs([GenericArg::from(main_ret_ty)].iter()),
                 )
                 .unwrap()
-                .unwrap();
+                .unwrap()
+                .polymorphize(tcx);
 
                 let report_name = tcx.symbol_name(report).name;
                 let report_sig = get_function_sig(tcx, m.isa().triple(), report);
index ca7116b887d5a622a298d336ade72684f18413df..1d1ec21680e30a7dc981c262b4fc7b172b12a013 100644 (file)
@@ -66,7 +66,7 @@
 
 use crate::prelude::*;
 
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub(crate) struct CommentWriter {
     enabled: bool,
     global_comments: Vec<String>,
@@ -237,6 +237,7 @@ pub(crate) fn write_clif_file<'tcx>(
     func: &cranelift_codegen::ir::Function,
     mut clif_comments: &CommentWriter,
 ) {
+    // FIXME work around filename too long errors
     write_ir_file(
         tcx,
         || format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
index fd63c3ecddbdfd9cdb2365ca0aec9bca6bc18d5e..052ca0a082b3c62261bea1e2d36a3a93936d84a4 100644 (file)
@@ -153,11 +153,7 @@ pub(crate) fn size_and_align_of_dst<'tcx>(
     layout: TyAndLayout<'tcx>,
     info: Value,
 ) -> (Value, Value) {
-    if !layout.is_unsized() {
-        let size = fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64);
-        let align = fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64);
-        return (size, align);
-    }
+    assert!(layout.is_unsized() || layout.abi == Abi::Uninhabited);
     match layout.ty.kind() {
         ty::Dynamic(..) => {
             // load size/align from vtable
index a68225de58b32d160dd2302ed54eaf352b3d8831..45ae2bd8f07cb1c28003790b49344db68481307d 100644 (file)
@@ -324,6 +324,12 @@ pub(crate) fn new_stack_slot(
             };
         }
 
+        if layout.size.bytes() >= u64::from(u32::MAX - 16) {
+            fx.tcx
+                .sess
+                .fatal(&format!("values of type {} are too big to store on the stack", layout.ty));
+        }
+
         let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
             kind: StackSlotKind::ExplicitSlot,
             // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
@@ -420,7 +426,7 @@ pub(crate) fn to_ptr_maybe_unsized(self) -> (Pointer, Option<Value>) {
     }
 
     pub(crate) fn write_cvalue(self, fx: &mut FunctionCx<'_, '_, 'tcx>, from: CValue<'tcx>) {
-        assert_assignable(fx, from.layout().ty, self.layout().ty);
+        assert_assignable(fx, from.layout().ty, self.layout().ty, 16);
 
         self.write_cvalue_maybe_transmute(fx, from, "write_cvalue");
     }
@@ -774,18 +780,25 @@ pub(crate) fn assert_assignable<'tcx>(
     fx: &FunctionCx<'_, '_, 'tcx>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
+    limit: usize,
 ) {
+    if limit == 0 {
+        // assert_assignable exists solely to catch bugs in cg_clif. it isn't necessary for
+        // soundness. don't attempt to check deep types to avoid exponential behavior in certain
+        // cases.
+        return;
+    }
     match (from_ty.kind(), to_ty.kind()) {
         (ty::Ref(_, a, _), ty::Ref(_, b, _))
         | (
             ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
             ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }),
         ) => {
-            assert_assignable(fx, *a, *b);
+            assert_assignable(fx, *a, *b, limit - 1);
         }
         (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }))
         | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => {
-            assert_assignable(fx, *a, *b);
+            assert_assignable(fx, *a, *b, limit - 1);
         }
         (ty::FnPtr(_), ty::FnPtr(_)) => {
             let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
@@ -815,6 +828,17 @@ pub(crate) fn assert_assignable<'tcx>(
             }
             // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed
         }
+        (&ty::Tuple(types_a), &ty::Tuple(types_b)) => {
+            let mut types_a = types_a.iter();
+            let mut types_b = types_b.iter();
+            loop {
+                match (types_a.next(), types_b.next()) {
+                    (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1),
+                    (None, None) => return,
+                    (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty),
+                }
+            }
+        }
         (&ty::Adt(adt_def_a, substs_a), &ty::Adt(adt_def_b, substs_b))
             if adt_def_a.did() == adt_def_b.did() =>
         {
@@ -822,18 +846,37 @@ pub(crate) fn assert_assignable<'tcx>(
             let mut types_b = substs_b.types();
             loop {
                 match (types_a.next(), types_b.next()) {
-                    (Some(a), Some(b)) => assert_assignable(fx, a, b),
+                    (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1),
                     (None, None) => return,
                     (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty),
                 }
             }
         }
-        (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b),
+        (ty::Array(a, _), ty::Array(b, _)) => assert_assignable(fx, *a, *b, limit - 1),
+        (&ty::Closure(def_id_a, substs_a), &ty::Closure(def_id_b, substs_b))
+            if def_id_a == def_id_b =>
+        {
+            let mut types_a = substs_a.types();
+            let mut types_b = substs_b.types();
+            loop {
+                match (types_a.next(), types_b.next()) {
+                    (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1),
+                    (None, None) => return,
+                    (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty),
+                }
+            }
+        }
+        (ty::Param(_), _) | (_, ty::Param(_)) if fx.tcx.sess.opts.unstable_opts.polymorphize => {
+            // No way to check if it is correct or not with polymorphization enabled
+        }
         _ => {
             assert_eq!(
-                from_ty, to_ty,
+                from_ty,
+                to_ty,
                 "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}",
-                from_ty, to_ty, fx,
+                from_ty.kind(),
+                to_ty.kind(),
+                fx,
             );
         }
     }
index 411ec27139e426d20968c8e7ba8091f5c3e9f291..21f62a6b0096a20cdb76b3e7bafbfafb9d325bb9 100644 (file)
@@ -4,7 +4,6 @@
 use rustc_codegen_ssa::back::archive::ArchiveBuilder;
 use rustc_session::Session;
 
-use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_session::cstore::DllImport;
 
 struct ArchiveConfig<'a> {
@@ -177,7 +176,16 @@ enum BuilderKind<'a> {
         any_members
     }
 
-    fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
+    fn sess(&self) -> &Session {
+        self.config.sess
+    }
+
+    fn create_dll_import_lib(
+        _sess: &Session,
+        _lib_name: &str,
+        _dll_imports: &[DllImport],
+        _tmpdir: &Path,
+    ) -> PathBuf {
         unimplemented!();
     }
 }
index 1a96dd8bec47a606eef74a08ee39dd116522dbfc..aabbe8ac276d7ca7233618dcee8c3944da1fecdc 100644 (file)
@@ -13,7 +13,7 @@
 
 use crate::attributes;
 use crate::llvm::AttributePlace::Function;
-use crate::llvm::{self, Attribute, AttributeKind, AttributePlace};
+use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace};
 use crate::llvm_util;
 pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 
@@ -227,6 +227,10 @@ pub(crate) fn default_optimisation_attrs<'ll>(
     attrs
 }
 
+fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
+    llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
+}
+
 /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
 /// attributes.
 pub fn from_fn_attrs<'ll, 'tcx>(
@@ -309,11 +313,54 @@ pub fn from_fn_attrs<'ll, 'tcx>(
         // Need this for AArch64.
         to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
     }
-    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
+        || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
+    {
+        if llvm_util::get_version() >= (15, 0, 0) {
+            to_add.push(create_alloc_family_attr(cx.llcx));
+            // apply to argument place instead of function
+            let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
+            attributes::apply_to_llfn(llfn, AttributePlace::Argument(1), &[alloc_align]);
+            to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 0));
+            let mut flags = AllocKindFlags::Alloc | AllocKindFlags::Aligned;
+            if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
+                flags |= AllocKindFlags::Uninitialized;
+            } else {
+                flags |= AllocKindFlags::Zeroed;
+            }
+            to_add.push(llvm::CreateAllocKindAttr(cx.llcx, flags));
+        }
         // apply to return place instead of function (unlike all other attributes applied in this function)
         let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
         attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
     }
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::REALLOCATOR) {
+        if llvm_util::get_version() >= (15, 0, 0) {
+            to_add.push(create_alloc_family_attr(cx.llcx));
+            to_add.push(llvm::CreateAllocKindAttr(
+                cx.llcx,
+                AllocKindFlags::Realloc | AllocKindFlags::Aligned,
+            ));
+            // applies to argument place instead of function place
+            let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
+            attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
+            // apply to argument place instead of function
+            let alloc_align = AttributeKind::AllocAlign.create_attr(cx.llcx);
+            attributes::apply_to_llfn(llfn, AttributePlace::Argument(2), &[alloc_align]);
+            to_add.push(llvm::CreateAllocSizeAttr(cx.llcx, 3));
+        }
+        let no_alias = AttributeKind::NoAlias.create_attr(cx.llcx);
+        attributes::apply_to_llfn(llfn, AttributePlace::ReturnValue, &[no_alias]);
+    }
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::DEALLOCATOR) {
+        if llvm_util::get_version() >= (15, 0, 0) {
+            to_add.push(create_alloc_family_attr(cx.llcx));
+            to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
+            // applies to argument place instead of function place
+            let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
+            attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
+        }
+    }
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) {
         to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"));
     }
index bccc2a995a30cd96e9bbe615301a402969854753..baa858709a0c6b7c87309c025302de6532b6c132 100644 (file)
@@ -11,7 +11,6 @@
 use crate::llvm::archive_ro::{ArchiveRO, Child};
 use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
 use rustc_codegen_ssa::back::archive::ArchiveBuilder;
-use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_session::cstore::{DllCallingConvention, DllImport};
 use rustc_session::Session;
 
@@ -96,19 +95,23 @@ fn build(mut self) -> bool {
         }
     }
 
-    fn inject_dll_import_lib(
-        &mut self,
+    fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    fn create_dll_import_lib(
+        sess: &Session,
         lib_name: &str,
         dll_imports: &[DllImport],
-        tmpdir: &MaybeTempDir,
-    ) {
+        tmpdir: &Path,
+    ) -> PathBuf {
         let output_path = {
-            let mut output_path: PathBuf = tmpdir.as_ref().to_path_buf();
+            let mut output_path: PathBuf = tmpdir.to_path_buf();
             output_path.push(format!("{}_imports", lib_name));
             output_path.with_extension("lib")
         };
 
-        let target = &self.sess.target;
+        let target = &sess.target;
         let mingw_gnu_toolchain = target.vendor == "pc"
             && target.os == "windows"
             && target.env == "gnu"
@@ -117,7 +120,7 @@ fn inject_dll_import_lib(
         let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
             .iter()
             .map(|import: &DllImport| {
-                if self.sess.target.arch == "x86" {
+                if sess.target.arch == "x86" {
                     (
                         LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
                         import.ordinal,
@@ -134,8 +137,7 @@ fn inject_dll_import_lib(
             // that loaded but crashed with an AV upon calling one of the imported
             // functions.  Therefore, use binutils to create the import library instead,
             // by writing a .DEF file to the temp dir and calling binutils's dlltool.
-            let def_file_path =
-                tmpdir.as_ref().join(format!("{}_imports", lib_name)).with_extension("def");
+            let def_file_path = tmpdir.join(format!("{}_imports", lib_name)).with_extension("def");
 
             let def_file_content = format!(
                 "EXPORTS\n{}",
@@ -154,11 +156,11 @@ fn inject_dll_import_lib(
             match std::fs::write(&def_file_path, def_file_content) {
                 Ok(_) => {}
                 Err(e) => {
-                    self.sess.fatal(&format!("Error writing .DEF file: {}", e));
+                    sess.fatal(&format!("Error writing .DEF file: {}", e));
                 }
             };
 
-            let dlltool = find_binutils_dlltool(self.sess);
+            let dlltool = find_binutils_dlltool(sess);
             let result = std::process::Command::new(dlltool)
                 .args([
                     "-d",
@@ -172,9 +174,9 @@ fn inject_dll_import_lib(
 
             match result {
                 Err(e) => {
-                    self.sess.fatal(&format!("Error calling dlltool: {}", e));
+                    sess.fatal(&format!("Error calling dlltool: {}", e));
                 }
-                Ok(output) if !output.status.success() => self.sess.fatal(&format!(
+                Ok(output) if !output.status.success() => sess.fatal(&format!(
                     "Dlltool could not create import library: {}\n{}",
                     String::from_utf8_lossy(&output.stdout),
                     String::from_utf8_lossy(&output.stderr)
@@ -220,13 +222,13 @@ fn inject_dll_import_lib(
                     output_path_z.as_ptr(),
                     ffi_exports.as_ptr(),
                     ffi_exports.len(),
-                    llvm_machine_type(&self.sess.target.arch) as u16,
-                    !self.sess.target.is_like_msvc,
+                    llvm_machine_type(&sess.target.arch) as u16,
+                    !sess.target.is_like_msvc,
                 )
             };
 
             if result == crate::llvm::LLVMRustResult::Failure {
-                self.sess.fatal(&format!(
+                sess.fatal(&format!(
                     "Error creating import library for {}: {}",
                     lib_name,
                     llvm::last_error().unwrap_or("unknown LLVM error".to_string())
@@ -234,13 +236,7 @@ fn inject_dll_import_lib(
             }
         };
 
-        self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
-            self.sess.fatal(&format!(
-                "failed to add native library {}: {}",
-                output_path.display(),
-                e
-            ));
-        });
+        output_path
     }
 }
 
index e2fa5e488edd04f2b67634f7fa5ee6a72de14304..45de284d22a6735bafb39d1d8eead2604de9cf95 100644 (file)
@@ -20,19 +20,6 @@ pub enum OptimizationDiagnosticKind {
     OptimizationRemarkOther,
 }
 
-impl OptimizationDiagnosticKind {
-    pub fn describe(self) -> &'static str {
-        match self {
-            OptimizationRemark | OptimizationRemarkOther => "remark",
-            OptimizationMissed => "missed",
-            OptimizationAnalysis => "analysis",
-            OptimizationAnalysisFPCommute => "floating-point",
-            OptimizationAnalysisAliasing => "aliasing",
-            OptimizationFailure => "failure",
-        }
-    }
-}
-
 pub struct OptimizationDiagnostic<'ll> {
     pub kind: OptimizationDiagnosticKind,
     pub pass_name: String,
index f64eb79b0a8e2b545b41f09ce0e5d1f7a3dcb83b..9ee6d39fdc9bf95095f14d1a86cb0086db1b52a7 100644 (file)
@@ -193,6 +193,9 @@ pub enum AttributeKind {
     SanitizeMemTag = 34,
     NoCfCheck = 35,
     ShadowCallStack = 36,
+    AllocSize = 37,
+    AllocatedPointer = 38,
+    AllocAlign = 39,
 }
 
 /// LLVMIntPredicate
@@ -569,16 +572,6 @@ pub enum ArchiveKind {
     K_COFF,
 }
 
-/// LLVMRustPassKind
-#[derive(Copy, Clone, PartialEq, Debug)]
-#[repr(C)]
-#[allow(dead_code)] // Variants constructed by C++.
-pub enum PassKind {
-    Other,
-    Function,
-    Module,
-}
-
 // LLVMRustThinLTOData
 extern "C" {
     pub type ThinLTOData;
@@ -589,10 +582,6 @@ pub enum PassKind {
     pub type ThinLTOBuffer;
 }
 
-// LLVMRustModuleNameCallback
-pub type ThinLTOModuleNameCallback =
-    unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char);
-
 /// LLVMRustThinLTOModule
 #[repr(C)]
 pub struct ThinLTOModule {
@@ -658,9 +647,6 @@ struct InvariantOpaque<'a> {
 }
 #[repr(C)]
 pub struct Builder<'a>(InvariantOpaque<'a>);
-extern "C" {
-    pub type MemoryBuffer;
-}
 #[repr(C)]
 pub struct PassManager<'a>(InvariantOpaque<'a>);
 extern "C" {
@@ -986,6 +972,22 @@ pub fn from_generic(kind: rustc_session::config::DebugInfo) -> Self {
     }
 }
 
+use bitflags::bitflags;
+// These values **must** match with LLVMRustAllocKindFlags
+bitflags! {
+    #[repr(transparent)]
+    #[derive(Default)]
+    pub struct AllocKindFlags : u64 {
+        const Unknown = 0;
+        const Alloc = 1;
+        const Realloc = 1 << 1;
+        const Free = 1 << 2;
+        const Uninitialized = 1 << 3;
+        const Zeroed = 1 << 4;
+        const Aligned = 1 << 5;
+    }
+}
+
 extern "C" {
     pub type ModuleBuffer;
 }
@@ -1013,7 +1015,6 @@ pub fn from_generic(kind: rustc_session::config::DebugInfo) -> Self {
     pub fn LLVMSetDataLayout(M: &Module, Triple: *const c_char);
 
     /// See Module::setModuleInlineAsm.
-    pub fn LLVMSetModuleInlineAsm2(M: &Module, Asm: *const c_char, AsmLen: size_t);
     pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char, AsmLen: size_t);
 
     /// See llvm::LLVMTypeKind::getTypeID.
@@ -1167,7 +1168,6 @@ pub fn LLVMRustGetOrInsertGlobal<'a>(
     pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
     pub fn LLVMSetInitializer<'a>(GlobalVar: &'a Value, ConstantVal: &'a Value);
     pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
-    pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool);
     pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
     pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
     pub fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
@@ -1193,6 +1193,8 @@ pub fn LLVMCreateStringAttribute(
     pub fn LLVMRustCreateByValAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute;
     pub fn LLVMRustCreateStructRetAttr<'a>(C: &'a Context, ty: &'a Type) -> &'a Attribute;
     pub fn LLVMRustCreateUWTableAttr(C: &Context, async_: bool) -> &Attribute;
+    pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute;
+    pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute;
 
     // Operations on functions
     pub fn LLVMRustGetOrInsertFunction<'a>(
@@ -2246,7 +2248,6 @@ pub fn LLVMRustDIBuilderCreateDebugLocation<'a>(
 
     pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
 
-    pub fn LLVMRustPassKind(Pass: &Pass) -> PassKind;
     pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> Option<&'static mut Pass>;
     pub fn LLVMRustCreateAddressSanitizerFunctionPass(Recover: bool) -> &'static mut Pass;
     pub fn LLVMRustCreateModuleAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
@@ -2363,7 +2364,6 @@ pub fn LLVMRustPrintModule(
     ) -> LLVMRustResult;
     pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char);
     pub fn LLVMRustPrintPasses();
-    pub fn LLVMRustGetInstructionCount(M: &Module) -> u32;
     pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
     pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool);
     pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
@@ -2461,7 +2461,6 @@ pub fn LLVMRustBuildOperandBundleDef<'a>(
     pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
 
     pub fn LLVMRustSetComdat<'a>(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
-    pub fn LLVMRustUnsetComdat(V: &Value);
     pub fn LLVMRustSetModulePICLevel(M: &Module);
     pub fn LLVMRustSetModulePIELevel(M: &Module);
     pub fn LLVMRustSetModuleCodeModel(M: &Module, Model: CodeModel);
@@ -2493,11 +2492,6 @@ pub fn LLVMRustPrepareThinLTOImport(
         Module: &Module,
         Target: &TargetMachine,
     ) -> bool;
-    pub fn LLVMRustGetThinLTOModuleImports(
-        Data: *const ThinLTOData,
-        ModuleNameCallback: ThinLTOModuleNameCallback,
-        CallbackPayload: *mut c_void,
-    );
     pub fn LLVMRustFreeThinLTOData(Data: &'static mut ThinLTOData);
     pub fn LLVMRustParseBitcodeForLTO(
         Context: &Context,
index 48fbc1de8ee4407adbf323e87430a66ad98ff3c2..6602a4ab8636cc0be034fbbaacabbef009b94667 100644 (file)
@@ -95,6 +95,14 @@ pub fn CreateUWTableAttr(llcx: &Context, async_: bool) -> &Attribute {
     unsafe { LLVMRustCreateUWTableAttr(llcx, async_) }
 }
 
+pub fn CreateAllocSizeAttr(llcx: &Context, size_arg: u32) -> &Attribute {
+    unsafe { LLVMRustCreateAllocSizeAttr(llcx, size_arg) }
+}
+
+pub fn CreateAllocKindAttr(llcx: &Context, kind_arg: AllocKindFlags) -> &Attribute {
+    unsafe { LLVMRustCreateAllocKindAttr(llcx, kind_arg.bits()) }
+}
+
 #[derive(Copy, Clone)]
 pub enum AttributePlace {
     ReturnValue,
@@ -158,12 +166,6 @@ pub fn SetUniqueComdat(llmod: &Module, val: &Value) {
     }
 }
 
-pub fn UnsetComdat(val: &Value) {
-    unsafe {
-        LLVMRustUnsetComdat(val);
-    }
-}
-
 pub fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
     unsafe {
         LLVMSetUnnamedAddress(global, unnamed);
index 1cb8d3423812937658391356d9b8ec3a9c2ef9e1..53550b049db09d745748d313134a1c48f3240892 100644 (file)
@@ -51,10 +51,37 @@ fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
 
     fn build(self) -> bool;
 
+    fn sess(&self) -> &Session;
+
+    /// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>.
+    /// and returns the path on disk to that import library.
+    /// This functions doesn't take `self` so that it can be called from
+    /// `linker_with_args`, which is specialized on `ArchiveBuilder` but
+    /// doesn't take or create an instance of that type.
+    fn create_dll_import_lib(
+        sess: &Session,
+        lib_name: &str,
+        dll_imports: &[DllImport],
+        tmpdir: &Path,
+    ) -> PathBuf;
+
+    /// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>
+    /// and adds it to the current compilation's set of archives.
     fn inject_dll_import_lib(
         &mut self,
         lib_name: &str,
         dll_imports: &[DllImport],
         tmpdir: &MaybeTempDir,
-    );
+    ) {
+        let output_path =
+            Self::create_dll_import_lib(self.sess(), lib_name, dll_imports, tmpdir.as_ref());
+
+        self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
+            self.sess().fatal(&format!(
+                "failed to add native library {}: {}",
+                output_path.display(),
+                e
+            ));
+        });
+    }
 }
index 878a670cba3efeded5fbe32795bfbc74f6359b99..f0d320c7c21c96752ab5b625da1e40d48e319099 100644 (file)
@@ -120,7 +120,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
                         &out_filename,
                         codegen_results,
                         path.as_ref(),
-                    );
+                    )?;
                 }
             }
             if sess.opts.json_artifact_notifications {
@@ -650,7 +650,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     out_filename: &Path,
     codegen_results: &CodegenResults,
     tmpdir: &Path,
-) {
+) -> Result<(), ErrorGuaranteed> {
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let (linker_path, flavor) = linker_and_flavor(sess);
     let mut cmd = linker_with_args::<B>(
@@ -661,7 +661,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         tmpdir,
         out_filename,
         codegen_results,
-    );
+    )?;
 
     linker::disable_localization(&mut cmd);
 
@@ -1000,6 +1000,8 @@ fn is_illegal_instruction(_status: &ExitStatus) -> bool {
             (Strip::None, _) => {}
         }
     }
+
+    Ok(())
 }
 
 // Temporarily support both -Z strip and -C strip
@@ -1848,7 +1850,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     tmpdir: &Path,
     out_filename: &Path,
     codegen_results: &CodegenResults,
-) -> Command {
+) -> Result<Command, ErrorGuaranteed> {
     let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
     let cmd = &mut *super::linker::get_linker(
         sess,
@@ -1955,6 +1957,18 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
         add_upstream_native_libraries(cmd, sess, codegen_results);
     }
 
+    // Link with the import library generated for any raw-dylib functions.
+    for (raw_dylib_name, raw_dylib_imports) in
+        collate_raw_dylibs(sess, &codegen_results.crate_info.used_libraries)?
+    {
+        cmd.add_object(&B::create_dll_import_lib(
+            sess,
+            &raw_dylib_name,
+            &raw_dylib_imports,
+            tmpdir,
+        ));
+    }
+
     // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
     // command line shorter, reset it to default here before adding more libraries.
     cmd.reset_per_library_state();
@@ -1998,7 +2012,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // to it and remove the option.
     add_post_link_args(cmd, sess, flavor);
 
-    cmd.take_cmd()
+    Ok(cmd.take_cmd())
 }
 
 fn add_order_independent_options(
@@ -2082,7 +2096,12 @@ fn add_order_independent_options(
         // sections to ensure we have all the data for PGO.
         let keep_metadata =
             crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled();
-        cmd.gc_sections(keep_metadata);
+        if crate_type != CrateType::Executable || !sess.opts.unstable_opts.export_executable_symbols
+        {
+            cmd.gc_sections(keep_metadata);
+        } else {
+            cmd.no_gc_sections();
+        }
     }
 
     cmd.set_output_kind(link_output_kind, out_filename);
@@ -2222,8 +2241,7 @@ fn add_local_native_libraries(
                 }
             }
             NativeLibKind::RawDylib => {
-                // FIXME(#58713): Proper handling for raw dylibs.
-                bug!("raw_dylib feature not yet implemented");
+                // Ignore RawDylib here, they are handled separately in linker_with_args().
             }
         }
     }
index d4a9db4af23a2461264def0acc66108456054d22..8e5ac9da4ac50652b62a39e7d760ee18e14ad163 100644 (file)
@@ -640,9 +640,14 @@ fn no_default_libraries(&mut self) {
 
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
         // Symbol visibility in object files typically takes care of this.
-        if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none()
-        {
-            return;
+        if crate_type == CrateType::Executable {
+            let should_export_executable_symbols =
+                self.sess.opts.unstable_opts.export_executable_symbols;
+            if self.sess.target.override_export_symbols.is_none()
+                && !should_export_executable_symbols
+            {
+                return;
+            }
         }
 
         // We manually create a list of exported symbols to ensure we don't expose any more.
@@ -969,7 +974,11 @@ fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]) {
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
         // Symbol visibility takes care of this typically
         if crate_type == CrateType::Executable {
-            return;
+            let should_export_executable_symbols =
+                self.sess.opts.unstable_opts.export_executable_symbols;
+            if !should_export_executable_symbols {
+                return;
+            }
         }
 
         let path = tmpdir.join("lib.def");
index 58cee0c8bb0dbf166d9d7fbb827e44d319607e1a..268c4d765030568f074d975153a2bd6fa30a8f1b 100644 (file)
@@ -435,18 +435,12 @@ pub fn codegen_place(
             LocalRef::Place(place) => place,
             LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx),
             LocalRef::Operand(..) => {
-                if let Some(elem) = place_ref
-                    .projection
-                    .iter()
-                    .enumerate()
-                    .find(|elem| matches!(elem.1, mir::ProjectionElem::Deref))
-                {
-                    base = elem.0 + 1;
+                if place_ref.has_deref() {
+                    base = 1;
                     let cg_base = self.codegen_consume(
                         bx,
-                        mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref },
+                        mir::PlaceRef { projection: &place_ref.projection[..0], ..place_ref },
                     );
-
                     cg_base.deref(bx.cx())
                 } else {
                     bug!("using operand local {:?} as place", place_ref);
index bfdef2dc0e80c802894518c24638ab8c575c9c9b..ecad0518533ec7ef0511b2da25e23d21dc2a7a75 100644 (file)
     ("bulk-memory", Some(sym::wasm_target_feature)),
     ("mutable-globals", Some(sym::wasm_target_feature)),
     ("reference-types", Some(sym::wasm_target_feature)),
+    ("sign-ext", Some(sym::wasm_target_feature)),
 ];
 
 const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
index 025f8647c95b554438155445e7b9fd55cb63ef05..08209eb793216543453e86a23a3a15d08d3bec80 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     self,
-    interpret::{ConstValue, GlobalId, InterpResult, Scalar},
+    interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
     BinOp,
 };
 use rustc_middle::ty;
@@ -328,7 +328,7 @@ pub fn emulate_intrinsic(
                             // We managed to find a valid allocation for one pointer, but not the other.
                             // That means they are definitely not pointing to the same allocation.
                             throw_ub_format!(
-                                "{} called on pointers into different allocations",
+                                "`{}` called on pointers into different allocations",
                                 intrinsic_name
                             );
                         }
@@ -336,7 +336,7 @@ pub fn emulate_intrinsic(
                             // Found allocation for both. They must be into the same allocation.
                             if a_alloc_id != b_alloc_id {
                                 throw_ub_format!(
-                                    "{} called on pointers into different allocations",
+                                    "`{}` called on pointers into different allocations",
                                     intrinsic_name
                                 );
                             }
@@ -346,47 +346,71 @@ pub fn emulate_intrinsic(
                     };
 
                 // Compute distance.
-                let distance = {
-                    // The subtraction is always done in `isize` to enforce
-                    // the "no more than `isize::MAX` apart" requirement.
-                    let a_offset = ImmTy::from_uint(a_offset, isize_layout);
-                    let b_offset = ImmTy::from_uint(b_offset, isize_layout);
-                    let (val, overflowed, _ty) =
-                        self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
+                let dist = {
+                    // Addresses are unsigned, so this is a `usize` computation. We have to do the
+                    // overflow check separately anyway.
+                    let (val, overflowed, _ty) = {
+                        let a_offset = ImmTy::from_uint(a_offset, usize_layout);
+                        let b_offset = ImmTy::from_uint(b_offset, usize_layout);
+                        self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?
+                    };
                     if overflowed {
-                        throw_ub_format!("pointers were too far apart for {}", intrinsic_name);
+                        // a < b
+                        if intrinsic_name == sym::ptr_offset_from_unsigned {
+                            throw_ub_format!(
+                                "`{}` called when first pointer has smaller offset than second: {} < {}",
+                                intrinsic_name,
+                                a_offset,
+                                b_offset,
+                            );
+                        }
+                        // The signed form of the intrinsic allows this. If we interpret the
+                        // difference as isize, we'll get the proper signed difference. If that
+                        // seems *positive*, they were more than isize::MAX apart.
+                        let dist = val.to_machine_isize(self)?;
+                        if dist >= 0 {
+                            throw_ub_format!(
+                                "`{}` called when first pointer is too far before second",
+                                intrinsic_name
+                            );
+                        }
+                        dist
+                    } else {
+                        // b >= a
+                        let dist = val.to_machine_isize(self)?;
+                        // If converting to isize produced a *negative* result, we had an overflow
+                        // because they were more than isize::MAX apart.
+                        if dist < 0 {
+                            throw_ub_format!(
+                                "`{}` called when first pointer is too far ahead of second",
+                                intrinsic_name
+                            );
+                        }
+                        dist
                     }
-                    val.to_machine_isize(self)?
                 };
 
                 // Check that the range between them is dereferenceable ("in-bounds or one past the
                 // end of the same allocation"). This is like the check in ptr_offset_inbounds.
-                let min_ptr = if distance >= 0 { b } else { a };
+                let min_ptr = if dist >= 0 { b } else { a };
                 self.check_ptr_access_align(
                     min_ptr,
-                    Size::from_bytes(distance.unsigned_abs()),
+                    Size::from_bytes(dist.unsigned_abs()),
                     Align::ONE,
                     CheckInAllocMsg::OffsetFromTest,
                 )?;
 
-                if intrinsic_name == sym::ptr_offset_from_unsigned && distance < 0 {
-                    throw_ub_format!(
-                        "{} called when first pointer has smaller offset than second: {} < {}",
-                        intrinsic_name,
-                        a_offset,
-                        b_offset,
-                    );
-                }
-
                 // Perform division by size to compute return value.
                 let ret_layout = if intrinsic_name == sym::ptr_offset_from_unsigned {
+                    assert!(0 <= dist && dist <= self.machine_isize_max());
                     usize_layout
                 } else {
+                    assert!(self.machine_isize_min() <= dist && dist <= self.machine_isize_max());
                     isize_layout
                 };
                 let pointee_layout = self.layout_of(substs.type_at(0))?;
                 // If ret_layout is unsigned, we checked that so is the distance, so we are good.
-                let val = ImmTy::from_int(distance, ret_layout);
+                let val = ImmTy::from_int(dist, ret_layout);
                 let size = ImmTy::from_int(pointee_layout.size.bytes(), ret_layout);
                 self.exact_div(&val, &size, dest)?;
             }
index 42de0dbdca92868b45a2eb18bb3a15077a675290..d563e35f9102d1e059f89958c7c3891690323967 100644 (file)
@@ -571,8 +571,8 @@ pub(crate) fn eval_fn_call(
 
                 // Now determine the actual method to call. We can do that in two different ways and
                 // compare them to ensure everything fits.
-                let ty::VtblEntry::Method(fn_inst) = self.get_vtable_entries(vptr)?[idx] else {
-                    span_bug!(self.cur_span(), "dyn call index points at something that is not a method")
+                let Some(ty::VtblEntry::Method(fn_inst)) = self.get_vtable_entries(vptr)?.get(idx).copied() else {
+                    throw_ub_format!("`dyn` call trying to call something that is not a method")
                 };
                 if cfg!(debug_assertions) {
                     let tcx = *self.tcx;
index 1d083b0bf8268b011cab72d22a78e66227bf6f07..3380226164460c74254966bf27dc14c15a564887 100644 (file)
@@ -23,8 +23,8 @@
 
 use super::ConstCx;
 use crate::errors::{
-    MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrComparisonErr, RawPtrToIntErr,
-    StaticAccessErr, TransientMutBorrowErr, TransientMutBorrowErrRaw,
+    MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrToIntErr, StaticAccessErr,
+    TransientMutBorrowErr, TransientMutBorrowErrRaw,
 };
 use crate::util::{call_kind, CallDesugaringKind, CallKind};
 
@@ -654,10 +654,10 @@ fn build_error(
 impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
     fn build_error(
         &self,
-        ccx: &ConstCx<'_, 'tcx>,
+        _: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.create_err(RawPtrComparisonErr { span })
+        span_bug!(span, "raw ptr comparison should already be caught in the trait system");
     }
 }
 
index 04c67cf8ff73ae3542c4ee5676c0876d9f5a555c..f95e33cd16a7ddfcb48434e0fd1c6f01a81ba22e 100644 (file)
@@ -149,3 +149,110 @@ passes-cold = {passes-should-be-applied-to-fn}
 passes-link = attribute should be applied to an `extern` block with non-Rust ABI
     .warn = {-passes-previously-accepted}
     .label = not an `extern` block
+
+passes-link-name = attribute should be applied to a foreign function or static
+    .warn = {-passes-previously-accepted}
+    .label = not a foreign function or static
+    .help = try `#[link(name = "{$value}")]` instead
+
+passes-no-link = attribute should be applied to an `extern crate` item
+    .label = not an `extern crate` item
+
+passes-export-name = attribute should be applied to a free function, impl method or static
+    .label = not a free function, impl method or static
+
+passes-rustc-layout-scalar-valid-range-not-struct = attribute should be applied to a struct
+    .label = not a struct
+
+passes-rustc-layout-scalar-valid-range-arg = expected exactly one integer literal argument
+
+passes-rustc-legacy-const-generics-only = #[rustc_legacy_const_generics] functions must only have const generics
+    .label = non-const generic parameter
+
+passes-rustc-legacy-const-generics-index = #[rustc_legacy_const_generics] must have one index for each generic parameter
+    .label = generic parameters
+
+passes-rustc-legacy-const-generics-index-exceed = index exceeds number of arguments
+    .label = there {$arg_count ->
+        [one] is
+        *[other] are
+    } only {$arg_count} {$arg_count ->
+        [one] argument
+        *[other] arguments
+    }
+
+passes-rustc-legacy-const-generics-index-negative = arguments should be non-negative integers
+
+passes-rustc-dirty-clean = attribute requires -Z query-dep-graph to be enabled
+
+passes-link-section = attribute should be applied to a function or static
+    .warn = {-passes-previously-accepted}
+    .label = not a function or static
+
+passes-no-mangle-foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
+    .warn = {-passes-previously-accepted}
+    .label = foreign {$foreign_item_kind}
+    .note = symbol names in extern blocks are not mangled
+    .suggestion = remove this attribute
+
+passes-no-mangle = attribute should be applied to a free function, impl method or static
+    .warn = {-passes-previously-accepted}
+    .label = not a free function, impl method or static
+
+passes-repr-ident = meta item in `repr` must be an identifier
+
+passes-repr-conflicting = conflicting representation hints
+
+passes-used-static = attribute must be applied to a `static` variable
+
+passes-used-compiler-linker = `used(compiler)` and `used(linker)` can't be used together
+
+passes-allow-internal-unstable = attribute should be applied to a macro
+    .label = not a macro
+
+passes-debug-visualizer-placement = attribute should be applied to a module
+
+passes-debug-visualizer-invalid = invalid argument
+    .note-1 = expected: `natvis_file = "..."`
+    .note-2 = OR
+    .note-3 = expected: `gdb_script_file = "..."`
+
+passes-rustc-allow-const-fn-unstable = attribute should be applied to `const fn`
+    .label = not a `const fn`
+
+passes-rustc-std-internal-symbol = attribute should be applied to functions or statics
+    .label = not a function or static
+
+passes-const-trait = attribute should be applied to a trait
+
+passes-stability-promotable = attribute cannot be applied to an expression
+
+passes-deprecated = attribute is ignored here
+
+passes-macro-use = `#[{$name}]` only has an effect on `extern crate` and modules
+
+passes-macro-export = `#[macro_export]` only has an effect on macro definitions
+
+passes-plugin-registrar = `#[plugin_registrar]` only has an effect on functions
+
+passes-unused-empty-lints-note = attribute `{$name}` with an empty list has no effect
+
+passes-unused-no-lints-note = attribute `{$name}` without any lints has no effect
+
+passes-unused-default-method-body-const-note =
+    `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
+
+passes-unused = unused attribute
+    .suggestion = remove this attribute
+
+passes-non-exported-macro-invalid-attrs = attribute should be applied to function or closure
+    .label = not a function or closure
+
+passes-unused-duplicate = unused attribute
+    .suggestion = remove this attribute
+    .note = attribute also specified here
+    .warn = {-passes-previously-accepted}
+
+passes-unused-multiple = multiple `{$name}` attributes
+    .suggestion = remove this attribute
+    .note = attribute also specified here
index c806df8214586859883b28b34d6a97227d01153a..7b540e67aab3ddf7fa39931fb725e3ca65a1553b 100644 (file)
@@ -532,6 +532,9 @@ pub struct BuiltinAttribute {
 
     rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
     rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+    rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+    rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
+    rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
     gated!(
         alloc_error_handler, Normal, template!(Word), WarnFollowing,
         experimental!(alloc_error_handler)
index d0893cd09d8db845df30bdfd3537dc3f84104e09..c0d5d2bc46d0d31988583e85663e15cbf2fe32ae 100644 (file)
@@ -713,7 +713,7 @@ pub fn expected_in_unit_struct_pat(&self) -> bool {
 }
 
 /// Resolution for a lifetime appearing in a type.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum LifetimeRes {
     /// Successfully linked the lifetime to a generic parameter.
     Param {
index 4e87ec86658f81503f29af7340dae6dbee9b6705..39faed0bf365cbbb8a9e772fb5c5c7484b0f994f 100644 (file)
@@ -237,12 +237,14 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
     span: Span,
     hidden_ty: Ty<'tcx>,
     hidden_region: ty::Region<'tcx>,
+    opaque_ty: ty::OpaqueTypeKey<'tcx>,
 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+    let opaque_ty = tcx.mk_opaque(opaque_ty.def_id.to_def_id(), opaque_ty.substs);
     let mut err = struct_span_err!(
         tcx.sess,
         span,
         E0700,
-        "hidden type for `impl Trait` captures lifetime that does not appear in bounds",
+        "hidden type for `{opaque_ty}` captures lifetime that does not appear in bounds",
     );
 
     // Explain the region we are capturing.
@@ -1883,7 +1885,7 @@ fn suggest_await_on_expect_found(
             exp_span, exp_found.expected, exp_found.found,
         );
 
-        if let ObligationCauseCode::CompareImplMethodObligation { .. } = cause.code() {
+        if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() {
             return;
         }
 
@@ -2351,7 +2353,7 @@ pub fn construct_generic_bound_failure(
             GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
         };
 
-        if let Some(SubregionOrigin::CompareImplMethodObligation {
+        if let Some(SubregionOrigin::CompareImplItemObligation {
             span,
             impl_item_def_id,
             trait_item_def_id,
@@ -2410,9 +2412,9 @@ fn binding_suggestion<'tcx, S: fmt::Display>(
         #[derive(Debug)]
         enum SubOrigin<'hir> {
             GAT(&'hir hir::Generics<'hir>),
-            Impl(&'hir hir::Generics<'hir>),
-            Trait(&'hir hir::Generics<'hir>),
-            Fn(&'hir hir::Generics<'hir>),
+            Impl,
+            Trait,
+            Fn,
             Unknown,
         }
         let sub_origin = 'origin: {
@@ -2427,34 +2429,30 @@ enum SubOrigin<'hir> {
                                         kind: hir::ImplItemKind::TyAlias(..),
                                         generics,
                                         ..
-                                    }) => SubOrigin::GAT(generics),
-                                    Node::ImplItem(hir::ImplItem {
-                                        kind: hir::ImplItemKind::Fn(..),
-                                        generics,
-                                        ..
-                                    }) => SubOrigin::Fn(generics),
-                                    Node::TraitItem(hir::TraitItem {
+                                    })
+                                    | Node::TraitItem(hir::TraitItem {
                                         kind: hir::TraitItemKind::Type(..),
                                         generics,
                                         ..
                                     }) => SubOrigin::GAT(generics),
-                                    Node::TraitItem(hir::TraitItem {
-                                        kind: hir::TraitItemKind::Fn(..),
-                                        generics,
+                                    Node::ImplItem(hir::ImplItem {
+                                        kind: hir::ImplItemKind::Fn(..),
                                         ..
-                                    }) => SubOrigin::Fn(generics),
-                                    Node::Item(hir::Item {
-                                        kind: hir::ItemKind::Trait(_, _, generics, _, _),
+                                    })
+                                    | Node::TraitItem(hir::TraitItem {
+                                        kind: hir::TraitItemKind::Fn(..),
                                         ..
-                                    }) => SubOrigin::Trait(generics),
+                                    })
+                                    | Node::Item(hir::Item {
+                                        kind: hir::ItemKind::Fn(..), ..
+                                    }) => SubOrigin::Fn,
                                     Node::Item(hir::Item {
-                                        kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
+                                        kind: hir::ItemKind::Trait(..),
                                         ..
-                                    }) => SubOrigin::Impl(generics),
+                                    }) => SubOrigin::Trait,
                                     Node::Item(hir::Item {
-                                        kind: hir::ItemKind::Fn(_, generics, _),
-                                        ..
-                                    }) => SubOrigin::Fn(generics),
+                                        kind: hir::ItemKind::Impl(..), ..
+                                    }) => SubOrigin::Impl,
                                     _ => continue,
                                 };
                             }
@@ -2788,8 +2786,15 @@ fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode {
         use self::FailureCode::*;
         use crate::traits::ObligationCauseCode::*;
         match self.code() {
-            CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
-            CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"),
+            CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
+                Error0308("method not compatible with trait")
+            }
+            CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
+                Error0308("type not compatible with trait")
+            }
+            CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
+                Error0308("const not compatible with trait")
+            }
             MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
                 Error0308(match source {
                     hir::MatchSource::TryDesugar => "`?` operator has incompatible types",
@@ -2823,8 +2828,15 @@ fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode {
     fn as_requirement_str(&self) -> &'static str {
         use crate::traits::ObligationCauseCode::*;
         match self.code() {
-            CompareImplMethodObligation { .. } => "method type is compatible with trait",
-            CompareImplTypeObligation { .. } => "associated type is compatible with trait",
+            CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
+                "method type is compatible with trait"
+            }
+            CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
+                "associated type is compatible with trait"
+            }
+            CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
+                "const is compatible with trait"
+            }
             ExprAssignable => "expression is assignable",
             IfExpression { .. } => "`if` and `else` have incompatible types",
             IfExpressionWithNoElse => "`if` missing an `else` returns `()`",
index 91bf9695dfc140ab2fc052b6abb3911b7fadf7e8..da465a764299270ec845383fc8547f869631bef8 100644 (file)
@@ -2,17 +2,17 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{SubregionOrigin, Subtype};
-use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
+use crate::infer::Subtype;
+use crate::traits::ObligationCauseCode::CompareImplItemObligation;
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 
 use std::ops::ControlFlow;
 
@@ -22,38 +22,22 @@ pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorGuar
         let error = self.error.as_ref()?;
         debug!("try_report_impl_not_conforming_to_trait {:?}", error);
         if let RegionResolutionError::SubSupConflict(
-                _, var_origin, sub_origin, _sub, sup_origin, _sup, _,
+                _,
+                var_origin,
+                sub_origin,
+                _sub,
+                sup_origin,
+                _sup,
+                _,
             ) = error.clone()
-            && let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin)
-            && let (
-                sub_expected_found @ Some((sub_expected, sub_found)),
-                sup_expected_found @ Some(_),
-                CompareImplMethodObligation { trait_item_def_id, .. },
-            ) = (sub_trace.values.ty(), sup_trace.values.ty(), sub_trace.cause.code())
+            && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
+            && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
+            && let sup_expected_found @ Some(_) = sup_trace.values.ty()
+            && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
             && sup_expected_found == sub_expected_found
         {
-            let guar = self.emit_err(
-                var_origin.span(),
-                sub_expected,
-                sub_found,
-                *trait_item_def_id,
-            );
-            return Some(guar);
-        }
-        if let RegionResolutionError::ConcreteFailure(origin, _, _)
-            | RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone()
-            && let SubregionOrigin::CompareImplTypeObligation {
-                span,
-                impl_item_def_id,
-                trait_item_def_id,
-            } = origin
-        {
-            let guar = self.emit_associated_type_err(
-                span,
-                self.infcx.tcx.item_name(impl_item_def_id.to_def_id()),
-                impl_item_def_id,
-                trait_item_def_id,
-            );
+            let guar =
+                self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
             return Some(guar);
         }
         None
@@ -147,25 +131,6 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         }
         err.emit()
     }
-
-    fn emit_associated_type_err(
-        &self,
-        span: Span,
-        item_name: Symbol,
-        impl_item_def_id: LocalDefId,
-        trait_item_def_id: DefId,
-    ) -> ErrorGuaranteed {
-        let impl_sp = self.tcx().def_span(impl_item_def_id);
-        let trait_sp = self.tcx().def_span(trait_item_def_id);
-        let mut err = self
-            .tcx()
-            .sess
-            .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name));
-        err.span_label(impl_sp, "found");
-        err.span_label(trait_sp, "expected");
-
-        err.emit()
-    }
 }
 
 struct TypeParamSpanVisitor<'tcx> {
index b6d41bedd56d83ebf80596799015a5c13436869d..c1940c5c0824a3e096f40f61e0622f0b1cbe6015 100644 (file)
@@ -86,13 +86,7 @@ pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &Subregion
                     "...so that the declared lifetime parameter bounds are satisfied",
                 );
             }
-            infer::CompareImplMethodObligation { span, .. } => {
-                label_or_note(
-                    span,
-                    "...so that the definition in impl matches the definition from the trait",
-                );
-            }
-            infer::CompareImplTypeObligation { span, .. } => {
+            infer::CompareImplItemObligation { span, .. } => {
                 label_or_note(
                     span,
                     "...so that the definition in impl matches the definition from the trait",
@@ -329,15 +323,7 @@ pub(super) fn report_concrete_failure(
                 );
                 err
             }
-            infer::CompareImplMethodObligation { span, impl_item_def_id, trait_item_def_id } => {
-                self.report_extra_impl_obligation(
-                    span,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                    &format!("`{}: {}`", sup, sub),
-                )
-            }
-            infer::CompareImplTypeObligation { span, impl_item_def_id, trait_item_def_id } => self
+            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
                 .report_extra_impl_obligation(
                     span,
                     impl_item_def_id,
index 85692e109be4a32d0b1cb5bb3f9eb70cd7952964..0ac6e8c541b5511e9c81cad62e10ae5456f5f519 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::traits::select;
-use rustc_middle::ty::abstract_const::AbstractConst;
+use rustc_middle::ty::abstract_const::{AbstractConst, FailureKind};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::relate::RelateResult;
@@ -405,15 +405,7 @@ pub enum SubregionOrigin<'tcx> {
 
     /// Comparing the signature and requirements of an impl method against
     /// the containing trait.
-    CompareImplMethodObligation {
-        span: Span,
-        impl_item_def_id: LocalDefId,
-        trait_item_def_id: DefId,
-    },
-
-    /// Comparing the signature and requirements of an impl associated type
-    /// against the containing trait
-    CompareImplTypeObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId },
+    CompareImplItemObligation { span: Span, impl_item_def_id: LocalDefId, trait_item_def_id: DefId },
 
     /// Checking that the bounds of a trait's associated type hold for a given impl
     CheckAssociatedTypeBounds {
@@ -974,14 +966,14 @@ pub fn sub_regions(
     #[instrument(skip(self), level = "debug")]
     pub fn member_constraint(
         &self,
-        opaque_type_def_id: LocalDefId,
+        key: ty::OpaqueTypeKey<'tcx>,
         definition_span: Span,
         hidden_ty: Ty<'tcx>,
         region: ty::Region<'tcx>,
         in_regions: &Lrc<Vec<ty::Region<'tcx>>>,
     ) {
         self.inner.borrow_mut().unwrap_region_constraints().member_constraint(
-            opaque_type_def_id,
+            key,
             definition_span,
             hidden_ty,
             region,
@@ -1683,7 +1675,7 @@ pub fn try_const_eval_resolve(
     #[instrument(skip(self), level = "debug")]
     pub fn const_eval_resolve(
         &self,
-        param_env: ty::ParamEnv<'tcx>,
+        mut param_env: ty::ParamEnv<'tcx>,
         unevaluated: ty::Unevaluated<'tcx>,
         span: Option<Span>,
     ) -> EvalToValTreeResult<'tcx> {
@@ -1694,10 +1686,19 @@ pub fn const_eval_resolve(
         // variables
         if substs.has_infer_types_or_consts() {
             let ac = AbstractConst::new(self.tcx, unevaluated.shrink());
-            if let Ok(None) = ac {
-                substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
-            } else {
-                return Err(ErrorHandled::TooGeneric);
+            match ac {
+                Ok(None) => {
+                    substs = InternalSubsts::identity_for_item(self.tcx, unevaluated.def.did);
+                    param_env = self.tcx.param_env(unevaluated.def.did);
+                }
+                Ok(Some(ct)) => {
+                    if ct.unify_failure_kind(self.tcx) == FailureKind::Concrete {
+                        substs = replace_param_and_infer_substs_with_placeholder(self.tcx, substs);
+                    } else {
+                        return Err(ErrorHandled::TooGeneric);
+                    }
+                }
+                Err(guar) => return Err(ErrorHandled::Reported(guar)),
             }
         }
 
@@ -1945,8 +1946,7 @@ pub fn span(&self) -> Span {
             ReborrowUpvar(a, _) => a,
             DataBorrowed(_, a) => a,
             ReferenceOutlivesReferent(_, a) => a,
-            CompareImplMethodObligation { span, .. } => span,
-            CompareImplTypeObligation { span, .. } => span,
+            CompareImplItemObligation { span, .. } => span,
             CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
         }
     }
@@ -1960,19 +1960,11 @@ pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default:
                 SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span)
             }
 
-            traits::ObligationCauseCode::CompareImplMethodObligation {
+            traits::ObligationCauseCode::CompareImplItemObligation {
                 impl_item_def_id,
                 trait_item_def_id,
-            } => SubregionOrigin::CompareImplMethodObligation {
-                span: cause.span,
-                impl_item_def_id,
-                trait_item_def_id,
-            },
-
-            traits::ObligationCauseCode::CompareImplTypeObligation {
-                impl_item_def_id,
-                trait_item_def_id,
-            } => SubregionOrigin::CompareImplTypeObligation {
+                kind: _,
+            } => SubregionOrigin::CompareImplItemObligation {
                 span: cause.span,
                 impl_item_def_id,
                 trait_item_def_id,
@@ -2017,3 +2009,43 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         )
     }
 }
+
+/// Replaces substs that reference param or infer variables with suitable
+/// placeholders. This function is meant to remove these param and infer
+/// substs when they're not actually needed to evaluate a constant.
+fn replace_param_and_infer_substs_with_placeholder<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    substs: SubstsRef<'tcx>,
+) -> SubstsRef<'tcx> {
+    tcx.mk_substs(substs.iter().enumerate().map(|(idx, arg)| {
+        match arg.unpack() {
+            GenericArgKind::Type(_)
+                if arg.has_param_types_or_consts() || arg.has_infer_types_or_consts() =>
+            {
+                tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+                    universe: ty::UniverseIndex::ROOT,
+                    name: ty::BoundVar::from_usize(idx),
+                }))
+                .into()
+            }
+            GenericArgKind::Const(ct)
+                if ct.has_infer_types_or_consts() || ct.has_param_types_or_consts() =>
+            {
+                let ty = ct.ty();
+                // If the type references param or infer, replace that too...
+                if ty.has_param_types_or_consts() || ty.has_infer_types_or_consts() {
+                    bug!("const `{ct}`'s type should not reference params or types");
+                }
+                tcx.mk_const(ty::ConstS {
+                    ty,
+                    kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
+                        universe: ty::UniverseIndex::ROOT,
+                        name: ty::BoundConst { ty, var: ty::BoundVar::from_usize(idx) },
+                    }),
+                })
+                .into()
+            }
+            _ => arg,
+        }
+    }))
+}
index 7b0ff9552a3a407ff852fa97c15758dc3da9bfa8..a1c7b70bd9cdf5e72f3f207176fb3bc77e91f484 100644 (file)
@@ -394,15 +394,7 @@ pub fn register_member_constraints(
         );
 
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
-            op: |r| {
-                self.member_constraint(
-                    opaque_type_key.def_id,
-                    span,
-                    concrete_ty,
-                    r,
-                    &choice_regions,
-                )
-            },
+            op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
         });
     }
 
@@ -438,7 +430,7 @@ pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<Opaqu
     }
 
     #[instrument(skip(self), level = "trace")]
-    pub fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
+    fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
         let origin = match self.tcx.hir().expect_item(def_id).kind {
             hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
             ref itemkind => {
index 551f398e0c2c41b75667078f8ce45fbbb3029901..0d4472a1cfd9c11944821f2992dca524e9458c39 100644 (file)
@@ -12,7 +12,6 @@
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify as ut;
-use rustc_hir::def_id::LocalDefId;
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
 use rustc_middle::ty::ReStatic;
@@ -533,7 +532,7 @@ pub fn make_eqregion(
 
     pub fn member_constraint(
         &mut self,
-        opaque_type_def_id: LocalDefId,
+        key: ty::OpaqueTypeKey<'tcx>,
         definition_span: Span,
         hidden_ty: Ty<'tcx>,
         member_region: ty::Region<'tcx>,
@@ -546,7 +545,7 @@ pub fn member_constraint(
         }
 
         self.data.member_constraints.push(MemberConstraint {
-            opaque_type_def_id,
+            key,
             definition_span,
             hidden_ty,
             member_region,
index d07e17f6792516fb51862c5063bd240b35dfe62b..0a0eb99cd926644b447eac8be1353caddd8c3efe 100644 (file)
@@ -733,6 +733,7 @@ macro_rules! tracked {
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
     tracked!(drop_tracking, true);
+    tracked!(export_executable_symbols, true);
     tracked!(dual_proc_macros, true);
     tracked!(dwarf_version, Some(5));
     tracked!(emit_thin_lto, false);
index bca5425e7287c947d10a29e53e2af42e8710c247..93f302b44e87cc58c67bb6496f17ef8258ef9b0d 100644 (file)
@@ -86,6 +86,9 @@ enum LLVMRustAttribute {
   SanitizeMemTag = 34,
   NoCfCheck = 35,
   ShadowCallStack = 36,
+  AllocSize = 37,
+  AllocatedPointer = 38,
+  AllocAlign = 39,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
index e0f10f77e89b0d74cc92c44d1c8fe985b5677ab2..0a6bd49992d9932f37326f75cfba45d046ed6e1e 100644 (file)
@@ -90,23 +90,6 @@ extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) {
   timeTraceProfilerCleanup();
 }
 
-enum class LLVMRustPassKind {
-  Other,
-  Function,
-  Module,
-};
-
-static LLVMRustPassKind toRust(PassKind Kind) {
-  switch (Kind) {
-  case PT_Function:
-    return LLVMRustPassKind::Function;
-  case PT_Module:
-    return LLVMRustPassKind::Module;
-  default:
-    return LLVMRustPassKind::Other;
-  }
-}
-
 extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) {
 #if LLVM_VERSION_LT(15, 0)
   StringRef SR(PassName);
@@ -172,12 +155,6 @@ extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
 #endif
 }
 
-extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
-  assert(RustPass);
-  Pass *Pass = unwrap(RustPass);
-  return toRust(Pass->getPassKind());
-}
-
 extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) {
 #if LLVM_VERSION_LT(15, 0)
   assert(RustPass);
@@ -1604,28 +1581,6 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
   return true;
 }
 
-extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload
-                                                      const char*, // importing module name
-                                                      const char*); // imported module name
-
-// Calls `module_name_callback` for each module import done by ThinLTO.
-// The callback is provided with regular null-terminated C strings.
-extern "C" void
-LLVMRustGetThinLTOModules(const LLVMRustThinLTOData *data,
-                                LLVMRustModuleNameCallback module_name_callback,
-                                void* callback_payload) {
-  for (const auto& importing_module : data->ImportLists) {
-    const std::string importing_module_id = importing_module.getKey().str();
-    const auto& imports = importing_module.getValue();
-    for (const auto& imported_module : imports) {
-      const std::string imported_module_id = imported_module.getKey().str();
-      module_name_callback(callback_payload,
-                           importing_module_id.c_str(),
-                           imported_module_id.c_str());
-    }
-  }
-}
-
 // This struct and various functions are sort of a hack right now, but the
 // problem is that we've got in-memory LLVM modules after we generate and
 // optimize all codegen-units for one compilation in rustc. To be compatible
index 4615558b912984e4537e058c82e8aad292369e7f..ef1a65488e2e4fff51f64b3e3bde106dac51c4ee 100644 (file)
@@ -88,10 +88,6 @@ extern "C" char *LLVMRustGetLastError(void) {
   return Ret;
 }
 
-extern "C" unsigned int LLVMRustGetInstructionCount(LLVMModuleRef M) {
-  return unwrap(M)->getInstructionCount();
-}
-
 extern "C" void LLVMRustSetLastError(const char *Err) {
   free((void *)LastError);
   LastError = strdup(Err);
@@ -234,6 +230,14 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::SanitizeMemTag;
   case ShadowCallStack:
     return Attribute::ShadowCallStack;
+  case AllocSize:
+    return Attribute::AllocSize;
+#if LLVM_VERSION_GE(15, 0)
+  case AllocatedPointer:
+    return Attribute::AllocatedPointer;
+  case AllocAlign:
+    return Attribute::AllocAlign;
+#endif
   }
   report_fatal_error("bad AttributeKind");
 }
@@ -305,6 +309,67 @@ extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Asy
 #endif
 }
 
+extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) {
+  return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg, None));
+}
+
+#if LLVM_VERSION_GE(15, 0)
+
+// These values **must** match ffi::AllocKindFlags.
+// It _happens_ to match the LLVM values of llvm::AllocFnKind,
+// but that's happenstance and we do explicit conversions before
+// passing them to LLVM.
+enum class LLVMRustAllocKindFlags : uint64_t {
+  Unknown = 0,
+  Alloc = 1,
+  Realloc = 1 << 1,
+  Free = 1 << 2,
+  Uninitialized = 1 << 3,
+  Zeroed = 1 << 4,
+  Aligned = 1 << 5,
+};
+
+static LLVMRustAllocKindFlags operator&(LLVMRustAllocKindFlags A, LLVMRustAllocKindFlags B) {
+  return static_cast<LLVMRustAllocKindFlags>(static_cast<uint64_t>(A) &
+                                      static_cast<uint64_t>(B));
+}
+
+static bool isSet(LLVMRustAllocKindFlags F) { return F != LLVMRustAllocKindFlags::Unknown; }
+
+static llvm::AllocFnKind allocKindFromRust(LLVMRustAllocKindFlags F) {
+  llvm::AllocFnKind AFK = llvm::AllocFnKind::Unknown;
+  if (isSet(F & LLVMRustAllocKindFlags::Alloc)) {
+    AFK |= llvm::AllocFnKind::Alloc;
+  }
+  if (isSet(F & LLVMRustAllocKindFlags::Realloc)) {
+    AFK |= llvm::AllocFnKind::Realloc;
+  }
+  if (isSet(F & LLVMRustAllocKindFlags::Free)) {
+    AFK |= llvm::AllocFnKind::Free;
+  }
+  if (isSet(F & LLVMRustAllocKindFlags::Uninitialized)) {
+    AFK |= llvm::AllocFnKind::Uninitialized;
+  }
+  if (isSet(F & LLVMRustAllocKindFlags::Zeroed)) {
+    AFK |= llvm::AllocFnKind::Zeroed;
+  }
+  if (isSet(F & LLVMRustAllocKindFlags::Aligned)) {
+    AFK |= llvm::AllocFnKind::Aligned;
+  }
+  return AFK;
+}
+#endif
+
+extern "C" LLVMAttributeRef LLVMRustCreateAllocKindAttr(LLVMContextRef C, uint64_t AllocKindArg) {
+#if LLVM_VERSION_GE(15, 0)
+  return wrap(Attribute::get(*unwrap(C), Attribute::AllocKind,
+      static_cast<uint64_t>(allocKindFromRust(static_cast<LLVMRustAllocKindFlags>(AllocKindArg)))));
+#else
+  report_fatal_error(
+      "allockind attributes are new in LLVM 15 and should not be used on older LLVMs");
+#endif
+}
+
 // Enable a fast-math flag
 //
 // https://llvm.org/docs/LangRef.html#fast-math-flags
@@ -1460,11 +1525,6 @@ extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V,
   }
 }
 
-extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) {
-  GlobalObject *GV = unwrap<GlobalObject>(V);
-  GV->setComdat(nullptr);
-}
-
 enum class LLVMRustLinkage {
   ExternalLinkage = 0,
   AvailableExternallyLinkage = 1,
index aa5705d3fcdc3c368820455749c6d6906e893ee5..8fa703a77607579aaa9b6a51635030cd0d166e2b 100644 (file)
@@ -41,7 +41,7 @@
 use std::iter::TrustedLen;
 use std::mem;
 use std::num::NonZeroUsize;
-use std::path::PathBuf;
+use std::path::Path;
 use tracing::debug;
 
 pub(super) use cstore_impl::provide;
@@ -1474,30 +1474,30 @@ fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash)
     /// Proc macro crates don't currently export spans, so this function does not have
     /// to work for them.
     fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] {
+        fn filter<'a>(sess: &Session, path: Option<&'a Path>) -> Option<&'a Path> {
+            path.filter(|_| {
+                // Only spend time on further checks if we have what to translate *to*.
+                sess.opts.real_rust_source_base_dir.is_some()
+                // Some tests need the translation to be always skipped.
+                && sess.opts.unstable_opts.translate_remapped_path_to_local_path
+            })
+            .filter(|virtual_dir| {
+                // Don't translate away `/rustc/$hash` if we're still remapping to it,
+                // since that means we're still building `std`/`rustc` that need it,
+                // and we don't want the real path to leak into codegen/debuginfo.
+                !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir)
+            })
+        }
+
         // Translate the virtual `/rustc/$hash` prefix back to a real directory
         // that should hold actual sources, where possible.
         //
         // NOTE: if you update this, you might need to also update bootstrap's code for generating
         // the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`.
         let virtual_rust_source_base_dir = [
-            option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(PathBuf::from),
-            sess.opts.unstable_opts.simulate_remapped_rust_src_base.clone(),
-        ]
-        .into_iter()
-        .filter(|_| {
-            // Only spend time on further checks if we have what to translate *to*.
-            sess.opts.real_rust_source_base_dir.is_some()
-                // Some tests need the translation to be always skipped.
-                && sess.opts.unstable_opts.translate_remapped_path_to_local_path
-        })
-        .flatten()
-        .filter(|virtual_dir| {
-            // Don't translate away `/rustc/$hash` if we're still remapping to it,
-            // since that means we're still building `std`/`rustc` that need it,
-            // and we don't want the real path to leak into codegen/debuginfo.
-            !sess.opts.remap_path_prefix.iter().any(|(_from, to)| to == virtual_dir)
-        })
-        .collect::<Vec<_>>();
+            filter(sess, option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(Path::new)),
+            filter(sess, sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref()),
+        ];
 
         let try_to_translate_virtual_to_real = |name: &mut rustc_span::FileName| {
             debug!(
@@ -1506,7 +1506,7 @@ fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] {
                 name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir,
             );
 
-            for virtual_dir in &virtual_rust_source_base_dir {
+            for virtual_dir in virtual_rust_source_base_dir.iter().flatten() {
                 if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
                     if let rustc_span::FileName::Real(old_name) = name {
                         if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
index 65cae29c58dcbdd21accf3086843208d21f3f1de..6bf237b8ed5dfc5482e3fa76b1408b050768980b 100644 (file)
@@ -375,9 +375,13 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
             use std::collections::vec_deque::VecDeque;
 
             let mut visible_parent_map: DefIdMap<DefId> = Default::default();
-            // This is a secondary visible_parent_map, storing the DefId of parents that re-export
-            // the child as `_`. Since we prefer parents that don't do this, merge this map at the
-            // end, only if we're missing any keys from the former.
+            // This is a secondary visible_parent_map, storing the DefId of
+            // parents that re-export the child as `_` or module parents
+            // which are `#[doc(hidden)]`. Since we prefer paths that don't
+            // do this, merge this map at the end, only if we're missing
+            // keys from the former.
+            // This is a rudimentary check that does not catch all cases,
+            // just the easiest.
             let mut fallback_map: DefIdMap<DefId> = Default::default();
 
             // Issue 46112: We want the map to prefer the shortest
@@ -412,6 +416,11 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                         return;
                     }
 
+                    if ty::util::is_doc_hidden(tcx, parent) {
+                        fallback_map.insert(def_id, parent);
+                        return;
+                    }
+
                     match visible_parent_map.entry(def_id) {
                         Entry::Occupied(mut entry) => {
                             // If `child` is defined in crate `cnum`, ensure
@@ -439,8 +448,9 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                 }
             }
 
-            // Fill in any missing entries with the (less preferable) path ending in `::_`.
-            // We still use this path in a diagnostic that suggests importing `::*`.
+            // Fill in any missing entries with the less preferable path.
+            // If this path re-exports the child as `_`, we still use this
+            // path in a diagnostic that suggests importing `::*`.
             for (child, parent) in fallback_map {
                 visible_parent_map.entry(child).or_insert(parent);
             }
index 8b2f9bdfd486bdd4555e353a9a07eebbfc4a3b48..38868c210495374dacfdec9431410001cad04000 100644 (file)
@@ -2,9 +2,8 @@
 pub mod unify_key;
 
 use crate::ty::Region;
-use crate::ty::Ty;
+use crate::ty::{OpaqueTypeKey, Ty};
 use rustc_data_structures::sync::Lrc;
-use rustc_hir::def_id::LocalDefId;
 use rustc_span::Span;
 
 /// Requires that `region` must be equal to one of the regions in `choice_regions`.
@@ -15,8 +14,9 @@
 /// ```
 #[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct MemberConstraint<'tcx> {
-    /// The `DefId` of the opaque type causing this constraint: used for error reporting.
-    pub opaque_type_def_id: LocalDefId,
+    /// The `DefId` and substs of the opaque type causing this constraint.
+    /// Used for error reporting.
+    pub key: OpaqueTypeKey<'tcx>,
 
     /// The span where the hidden type was instantiated.
     pub definition_span: Span,
index 321fcd43797cc18f5feb7e0739264548dd9e29ee..45d33a1659ffa42fbc0ae603025f44c80bdbda4a 100644 (file)
@@ -50,7 +50,7 @@ pub struct CodegenFnAttrFlags: u32 {
         /// the hot path.
         const COLD                      = 1 << 0;
         /// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
-        /// function is never null.
+        /// function is never null and the function has no side effects other than allocating.
         const ALLOCATOR                 = 1 << 1;
         /// An indicator that function will never unwind. Will become obsolete
         /// once C-unwind is fully stabilized.
@@ -91,6 +91,12 @@ pub struct CodegenFnAttrFlags: u32 {
         const NO_COVERAGE               = 1 << 15;
         /// `#[used(linker)]`: indicates that LLVM nor the linker can eliminate this function.
         const USED_LINKER               = 1 << 16;
+        /// `#[rustc_deallocator]`: a hint to LLVM that the function only deallocates memory.
+        const DEALLOCATOR               = 1 << 17;
+        /// `#[rustc_reallocator]`: a hint to LLVM that the function only reallocates memory.
+        const REALLOCATOR               = 1 << 18;
+        /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
+        const ALLOCATOR_ZEROED          = 1 << 19;
     }
 }
 
index 0fbad3f0f0f06761c56b77ce6740cfdc936eb1ba..414912dd0f7d897bdbaee48eda11d8b733be1519 100644 (file)
@@ -475,7 +475,13 @@ pub fn eval_stability_allow_unstable(
                 }
 
                 let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
-                EvalResult::Deny { feature, reason, issue, suggestion, is_soft }
+                EvalResult::Deny {
+                    feature,
+                    reason: reason.to_opt_reason(),
+                    issue,
+                    suggestion,
+                    is_soft,
+                }
             }
             Some(_) => {
                 // Stable APIs are always ok to call and deprecated APIs are
index 702cc48ff7bb3cc13b37b84af5c92fdc1c837221..f7311ebdabfd91bcb235b98cfa6236f146000206 100644 (file)
@@ -1461,6 +1461,14 @@ pub fn is_indirect(&self) -> bool {
         self.projection.iter().any(|elem| elem.is_indirect())
     }
 
+    /// If MirPhase >= Derefered and if projection contains Deref,
+    /// It's guaranteed to be in the first place
+    pub fn has_deref(&self) -> bool {
+        // To make sure this is not accidently used in wrong mir phase
+        debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref));
+        self.projection.first() == Some(&PlaceElem::Deref)
+    }
+
     /// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
     /// a single deref of a local.
     #[inline(always)]
@@ -1533,6 +1541,12 @@ pub fn local_or_deref_local(&self) -> Option<Local> {
         }
     }
 
+    /// If MirPhase >= Derefered and if projection contains Deref,
+    /// It's guaranteed to be in the first place
+    pub fn has_deref(&self) -> bool {
+        self.projection.first() == Some(&PlaceElem::Deref)
+    }
+
     /// If this place represents a local variable like `_X` with no
     /// projections, return `Some(_X)`.
     #[inline]
index c55971557fac1967551d819554b9ffc0e8d947c8..72b848c3ee2dd150728d09ba9a05e1d556597b2a 100644 (file)
@@ -311,18 +311,10 @@ pub enum ObligationCauseCode<'tcx> {
     },
 
     /// Error derived when matching traits/impls; see ObligationCause for more details
-    CompareImplConstObligation,
-
-    /// Error derived when matching traits/impls; see ObligationCause for more details
-    CompareImplMethodObligation {
-        impl_item_def_id: LocalDefId,
-        trait_item_def_id: DefId,
-    },
-
-    /// Error derived when matching traits/impls; see ObligationCause for more details
-    CompareImplTypeObligation {
+    CompareImplItemObligation {
         impl_item_def_id: LocalDefId,
         trait_item_def_id: DefId,
+        kind: ty::AssocKind,
     },
 
     /// Checking that the bounds of a trait's associated type hold for a given impl
index 2c93af506679d08c6789b491ef0778c89a867c1e..eb732148e3eb4ad7f1122de80a3799d3cbe27318 100644 (file)
@@ -105,6 +105,16 @@ pub fn as_def_kind(&self) -> DefKind {
     }
 }
 
+impl std::fmt::Display for AssocKind {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            AssocKind::Fn => write!(f, "method"),
+            AssocKind::Const => write!(f, "associated const"),
+            AssocKind::Type => write!(f, "associated type"),
+        }
+    }
+}
+
 /// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
 ///
 /// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
index c7653bdbe84a2f9cf841a11bee7ad84ce465997d..93707bb18ceec4c4f6a0341edea391c07d2f2f68 100644 (file)
@@ -80,31 +80,25 @@ pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
     }
 
     /// Get the values inside the ValTree as a slice of bytes. This only works for
-    /// constants with types &str and &[u8].
+    /// constants with types &str, &[u8], or [u8; _].
     pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> {
         match ty.kind() {
             ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
-                ty::Str => {
-                    let leafs = self
-                        .unwrap_branch()
-                        .into_iter()
-                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap());
-
-                    return Some(tcx.arena.alloc_from_iter(leafs));
-                }
-                ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {
-                    let leafs = self
-                        .unwrap_branch()
-                        .into_iter()
-                        .map(|v| v.unwrap_leaf().try_to_u8().unwrap());
-
-                    return Some(tcx.arena.alloc_from_iter(leafs));
-                }
-                _ => {}
+                // `&str` can be interpreted as raw bytes
+                ty::Str => {}
+                // `&[u8]` can be interpreted as raw bytes
+                ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {}
+                // other `&_` can't be interpreted as raw bytes
+                _ => return None,
             },
-            _ => {}
+            // `[u8; N]` can be interpreted as raw bytes
+            ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {}
+            // Otherwise, type cannot be interpreted as raw bytes
+            _ => return None,
         }
 
-        None
+        Some(tcx.arena.alloc_from_iter(
+            self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().try_to_u8().unwrap()),
+        ))
     }
 }
index 49a518b101dd156415c9a559624c41d15b767d25..91246051316fa42ec6cb440f78323913af29e240 100644 (file)
@@ -660,12 +660,8 @@ fn expected_projection(
                     | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
             )
         );
-        let impl_comparison = matches!(
-            cause_code,
-            ObligationCauseCode::CompareImplMethodObligation { .. }
-                | ObligationCauseCode::CompareImplTypeObligation { .. }
-                | ObligationCauseCode::CompareImplConstObligation
-        );
+        let impl_comparison =
+            matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
         let assoc = self.associated_item(proj_ty.item_def_id);
         if !callable_scope || impl_comparison {
             // We do not want to suggest calling functions when the reason of the
index 281a12655469494fce2d668a2132199e0615411a..31c523aaca9ae39614fea9658eb9c4322fb2646e 100644 (file)
@@ -829,6 +829,14 @@ pub fn self_ty(self) -> Ty<'tcx> {
     pub fn is_const_if_const(self) -> bool {
         self.constness == BoundConstness::ConstIfConst
     }
+
+    pub fn is_constness_satisfied_by(self, constness: hir::Constness) -> bool {
+        match (self.constness, constness) {
+            (BoundConstness::NotConst, _)
+            | (BoundConstness::ConstIfConst, hir::Constness::Const) => true,
+            (BoundConstness::ConstIfConst, hir::Constness::NotConst) => false,
+        }
+    }
 }
 
 impl<'tcx> PolyTraitPredicate<'tcx> {
index 03bb515904cd01e0b5719e035582785b5941de26..7f2e81a71a93d16cd773eeb221339fa8eeca15df 100644 (file)
@@ -1452,7 +1452,7 @@ fn pretty_print_const_valtree(
                 }
             },
             (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
-                let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| {
+                let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
                     bug!("expected to convert valtree to raw bytes for type {:?}", t)
                 });
                 p!("*");
@@ -2556,7 +2556,7 @@ pub fn print_modifiers_and_trait_path(
 
     ty::TraitPredicate<'tcx> {
         p!(print(self.trait_ref.self_ty()), ": ");
-        if let ty::BoundConstness::ConstIfConst = self.constness {
+        if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
             p!("~const ");
         }
         p!(print(self.trait_ref.print_only_trait_path()))
index a4be3d02d19359e1d9cb908d0589654e81ff9054..7660a2f3af60a51c64a374fb35a374e1bdccc665 100644 (file)
@@ -224,6 +224,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     // general `Region`.
     crate::ty::BoundRegionKind,
     crate::ty::AssocItem,
+    crate::ty::AssocKind,
     crate::ty::Placeholder<crate::ty::BoundRegionKind>,
     crate::ty::ClosureKind,
     crate::ty::FreeRegion,
@@ -1122,6 +1123,7 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::Br
         visitor.visit_predicate(*self)
     }
 
+    #[inline]
     fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
         self.outer_exclusive_binder() > binder
     }
index 3a524d7b0f30716fb448006d0bddd374141cbe04..b4fa9837aed91b2aa05b35417d0057f37878e26c 100644 (file)
@@ -11,7 +11,6 @@
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_serialize::{self, Decodable, Encodable};
-use rustc_span::DUMMY_SP;
 use smallvec::SmallVec;
 
 use core::intrinsics;
@@ -525,6 +524,7 @@ struct SubstFolder<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
+    #[inline]
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -540,6 +540,16 @@ fn fold_binder<T: TypeFoldable<'tcx>>(
     }
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        #[cold]
+        #[inline(never)]
+        fn region_param_out_of_range(data: ty::EarlyBoundRegion) -> ! {
+            bug!(
+                "Region parameter out of range when substituting in region {} (index={})",
+                data.name,
+                data.index
+            )
+        }
+
         // Note: This routine only handles regions that are bound on
         // type declarations and other outer declarations, not those
         // bound in *fn types*. Region substitution of the bound
@@ -550,14 +560,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                 let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
                 match rk {
                     Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
-                    _ => {
-                        let msg = format!(
-                            "Region parameter out of range \
-                             when substituting in region {} (index={})",
-                            data.name, data.index
-                        );
-                        span_bug!(DUMMY_SP, "{}", msg);
-                    }
+                    _ => region_param_out_of_range(data),
                 }
             }
             _ => r,
@@ -595,67 +598,80 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
         let opt_ty = self.substs.get(p.index as usize).map(|k| k.unpack());
         let ty = match opt_ty {
             Some(GenericArgKind::Type(ty)) => ty,
-            Some(kind) => {
-                span_bug!(
-                    DUMMY_SP,
-                    "expected type for `{:?}` ({:?}/{}) but found {:?} \
-                     when substituting, substs={:?}",
-                    p,
-                    source_ty,
-                    p.index,
-                    kind,
-                    self.substs,
-                );
-            }
-            None => {
-                span_bug!(
-                    DUMMY_SP,
-                    "type parameter `{:?}` ({:?}/{}) out of range \
-                     when substituting, substs={:?}",
-                    p,
-                    source_ty,
-                    p.index,
-                    self.substs,
-                );
-            }
+            Some(kind) => self.type_param_expected(p, source_ty, kind),
+            None => self.type_param_out_of_range(p, source_ty),
         };
 
         self.shift_vars_through_binders(ty)
     }
 
+    #[cold]
+    #[inline(never)]
+    fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! {
+        bug!(
+            "expected type for `{:?}` ({:?}/{}) but found {:?} when substituting, substs={:?}",
+            p,
+            ty,
+            p.index,
+            kind,
+            self.substs,
+        )
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! {
+        bug!(
+            "type parameter `{:?}` ({:?}/{}) out of range when substituting, substs={:?}",
+            p,
+            ty,
+            p.index,
+            self.substs,
+        )
+    }
+
     fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         // Look up the const in the substitutions. It really should be in there.
         let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack());
         let ct = match opt_ct {
             Some(GenericArgKind::Const(ct)) => ct,
-            Some(kind) => {
-                span_bug!(
-                    DUMMY_SP,
-                    "expected const for `{:?}` ({:?}/{}) but found {:?} \
-                     when substituting substs={:?}",
-                    p,
-                    source_ct,
-                    p.index,
-                    kind,
-                    self.substs,
-                );
-            }
-            None => {
-                span_bug!(
-                    DUMMY_SP,
-                    "const parameter `{:?}` ({:?}/{}) out of range \
-                     when substituting substs={:?}",
-                    p,
-                    source_ct,
-                    p.index,
-                    self.substs,
-                );
-            }
+            Some(kind) => self.const_param_expected(p, source_ct, kind),
+            None => self.const_param_out_of_range(p, source_ct),
         };
 
         self.shift_vars_through_binders(ct)
     }
 
+    #[cold]
+    #[inline(never)]
+    fn const_param_expected(
+        &self,
+        p: ty::ParamConst,
+        ct: ty::Const<'tcx>,
+        kind: GenericArgKind<'tcx>,
+    ) -> ! {
+        bug!(
+            "expected const for `{:?}` ({:?}/{}) but found {:?} when substituting substs={:?}",
+            p,
+            ct,
+            p.index,
+            kind,
+            self.substs,
+        )
+    }
+
+    #[cold]
+    #[inline(never)]
+    fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! {
+        bug!(
+            "const parameter `{:?}` ({:?}/{}) out of range when substituting substs={:?}",
+            p,
+            ct,
+            p.index,
+            self.substs,
+        )
+    }
+
     /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs
     /// when we are substituting a type with escaping bound vars into a context where we have
     /// passed through binders. That's quite a mouthful. Let's see an example:
index 5bd1fad0bcb9f9cbbe1e9ec2edfff178451afd97..3435f127c72e2420306ef0895b5cdf9dbd7ee30a 100644 (file)
@@ -951,7 +951,7 @@ fn adt_defined_here<'p, 'tcx>(
         let mut span: MultiSpan =
             if spans.is_empty() { def_span.into() } else { spans.clone().into() };
 
-        span.push_span_label(def_span, String::new());
+        span.push_span_label(def_span, "");
         for pat in spans {
             span.push_span_label(pat, "not covered");
         }
index b91ae083cf594e10bec90714a67d525407592139..9c5896c4e4aedef2008e849348559d97ffdabb9b 100644 (file)
 /// (Concurrent accesses by other threads are no problem as these are anyway non-atomic
 /// copies.  Data races are UB.)
 fn is_stable(place: PlaceRef<'_>) -> bool {
-    place.projection.iter().all(|elem| {
-        match elem {
-            // Which place this evaluates to can change with any memory write,
-            // so cannot assume this to be stable.
-            ProjectionElem::Deref => false,
-            // Array indices are interesting, but MIR building generates a *fresh*
-            // temporary for every array access, so the index cannot be changed as
-            // a side-effect.
-            ProjectionElem::Index { .. } |
-            // The rest is completely boring, they just offset by a constant.
-            ProjectionElem::Field { .. } |
-            ProjectionElem::ConstantIndex { .. } |
-            ProjectionElem::Subslice { .. } |
-            ProjectionElem::Downcast { .. } => true,
-        }
-    })
+    // Which place this evaluates to can change with any memory write,
+    // so cannot assume deref to be stable.
+    !place.has_deref()
 }
 
 /// Determine whether this type may contain a reference (or box), and thus needs retagging.
@@ -91,11 +78,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         };
         let place_base_raw = |place: &Place<'tcx>| {
             // If this is a `Deref`, get the type of what we are deref'ing.
-            let deref_base =
-                place.projection.iter().rposition(|p| matches!(p, ProjectionElem::Deref));
-            if let Some(deref_base) = deref_base {
-                let base_proj = &place.projection[..deref_base];
-                let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty;
+            if place.has_deref() {
+                let ty = &local_decls[place.local].ty;
                 ty.is_unsafe_ptr()
             } else {
                 // Not a deref, and thus not raw.
index 2eb38941f1a5084b993f20d724361d4ab67cec24..3b7ba3f9a67ac97096d1dd166aff9992babc1aee 100644 (file)
@@ -36,13 +36,16 @@ fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| {
         // FIXME: when we make this a hard error, this should have its
         // own error code.
-        let message = if tcx.generics_of(def_id).own_requires_monomorphization() {
-            "`#[derive]` can't be used on a `#[repr(packed)]` struct with \
-             type or const parameters (error E0133)"
+        let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
+            "with type or const parameters"
         } else {
-            "`#[derive]` can't be used on a `#[repr(packed)]` struct that \
-             does not derive Copy (error E0133)"
+            "that does not derive `Copy`"
         };
+        let message = format!(
+            "`{}` can't be derived on this `#[repr(packed)]` struct {}",
+            tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
+            extra
+        );
         lint.build(message).emit();
     });
 }
index f6484a9b54d3c6d0db8f5b8be5401a2ab608e878..85ad6b8f2feff052b70b19c74fb2a3244a1f5226 100644 (file)
@@ -155,18 +155,18 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     }
 }
 
-struct ConstPropMachine<'mir, 'tcx> {
+pub struct ConstPropMachine<'mir, 'tcx> {
     /// The virtual call stack.
     stack: Vec<Frame<'mir, 'tcx>>,
     /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
-    written_only_inside_own_block_locals: FxHashSet<Local>,
+    pub written_only_inside_own_block_locals: FxHashSet<Local>,
     /// Locals that need to be cleared after every block terminates.
-    only_propagate_inside_block_locals: BitSet<Local>,
-    can_const_prop: IndexVec<Local, ConstPropMode>,
+    pub only_propagate_inside_block_locals: BitSet<Local>,
+    pub can_const_prop: IndexVec<Local, ConstPropMode>,
 }
 
 impl ConstPropMachine<'_, '_> {
-    fn new(
+    pub fn new(
         only_propagate_inside_block_locals: BitSet<Local>,
         can_const_prop: IndexVec<Local, ConstPropMode>,
     ) -> Self {
@@ -816,7 +816,7 @@ fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool {
 
 /// The mode that `ConstProp` is allowed to run in for a given `Local`.
 #[derive(Clone, Copy, Debug, PartialEq)]
-enum ConstPropMode {
+pub enum ConstPropMode {
     /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
     FullConstProp,
     /// The `Local` can only be propagated into and from its own block.
@@ -828,7 +828,7 @@ enum ConstPropMode {
     NoPropagation,
 }
 
-struct CanConstProp {
+pub struct CanConstProp {
     can_const_prop: IndexVec<Local, ConstPropMode>,
     // False at the beginning. Once set, no more assignments are allowed to that local.
     found_assignment: BitSet<Local>,
@@ -838,7 +838,7 @@ struct CanConstProp {
 
 impl CanConstProp {
     /// Returns true if `local` can be propagated
-    fn check<'tcx>(
+    pub fn check<'tcx>(
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
         body: &Body<'tcx>,
index 97b1433f5d27aba406036306e0c8082a91665025..3ae6a88a140ead840ecbe322b11078fa74ad0202 100644 (file)
@@ -1,19 +1,24 @@
 //! Propagates constants for early reporting of statically known
 //! assertion failures
 
-use std::cell::Cell;
-
-use rustc_ast::Mutability;
-use rustc_data_structures::fx::FxHashSet;
+use crate::const_prop::CanConstProp;
+use crate::const_prop::ConstPropMachine;
+use crate::const_prop::ConstPropMode;
+use crate::MirLint;
+use rustc_const_eval::const_eval::ConstEvalErr;
+use rustc_const_eval::interpret::{
+    self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar,
+    ScalarMaybeUninit, StackPopCleanup,
+};
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
-use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::{
-    AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind,
-    Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement,
-    StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
+    AssertKind, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, Location, Operand, Place,
+    Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator,
+    TerminatorKind, UnOp, RETURN_PLACE,
 };
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
     TypeVisitable,
 };
 use rustc_session::lint;
-use rustc_span::{def_id::DefId, Span};
+use rustc_span::Span;
 use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
-use rustc_target::spec::abi::Abi as CallAbi;
 use rustc_trait_selection::traits;
-
-use crate::MirLint;
-use rustc_const_eval::const_eval::ConstEvalErr;
-use rustc_const_eval::interpret::{
-    self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
-    LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
-    StackPopCleanup, StackPopUnwind,
-};
+use std::cell::Cell;
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
 /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
 /// Severely regress performance.
 const MAX_ALLOC_LIMIT: u64 = 1024;
-
-/// Macro for machine-specific `InterpError` without allocation.
-/// (These will never be shown to the user, but they help diagnose ICEs.)
-macro_rules! throw_machine_stop_str {
-    ($($tt:tt)*) => {{
-        // We make a new local type for it. The type itself does not carry any information,
-        // but its vtable (for the `MachineStopType` trait) does.
-        struct Zst;
-        // Printing this type shows the desired string.
-        impl std::fmt::Display for Zst {
-            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                write!(f, $($tt)*)
-            }
-        }
-        impl rustc_middle::mir::interpret::MachineStopType for Zst {}
-        throw_machine_stop!(Zst)
-    }};
-}
-
 pub struct ConstProp;
 
 impl<'tcx> MirLint<'tcx> for ConstProp {
@@ -151,172 +129,6 @@ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     }
 }
 
-struct ConstPropMachine<'mir, 'tcx> {
-    /// The virtual call stack.
-    stack: Vec<Frame<'mir, 'tcx>>,
-    /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
-    written_only_inside_own_block_locals: FxHashSet<Local>,
-    /// Locals that need to be cleared after every block terminates.
-    only_propagate_inside_block_locals: BitSet<Local>,
-    can_const_prop: IndexVec<Local, ConstPropMode>,
-}
-
-impl ConstPropMachine<'_, '_> {
-    fn new(
-        only_propagate_inside_block_locals: BitSet<Local>,
-        can_const_prop: IndexVec<Local, ConstPropMode>,
-    ) -> Self {
-        Self {
-            stack: Vec::new(),
-            written_only_inside_own_block_locals: Default::default(),
-            only_propagate_inside_block_locals,
-            can_const_prop,
-        }
-    }
-}
-
-impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> {
-    compile_time_machine!(<'mir, 'tcx>);
-    const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`)
-
-    type MemoryKind = !;
-
-    fn load_mir(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::InstanceDef<'tcx>,
-    ) -> InterpResult<'tcx, &'tcx Body<'tcx>> {
-        throw_machine_stop_str!("calling functions isn't supported in ConstProp")
-    }
-
-    fn find_mir_or_eval_fn(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _abi: CallAbi,
-        _args: &[OpTy<'tcx>],
-        _destination: &PlaceTy<'tcx>,
-        _target: Option<BasicBlock>,
-        _unwind: StackPopUnwind,
-    ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
-        Ok(None)
-    }
-
-    fn call_intrinsic(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _args: &[OpTy<'tcx>],
-        _destination: &PlaceTy<'tcx>,
-        _target: Option<BasicBlock>,
-        _unwind: StackPopUnwind,
-    ) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
-    }
-
-    fn assert_panic(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _msg: &rustc_middle::mir::AssertMessage<'tcx>,
-        _unwind: Option<rustc_middle::mir::BasicBlock>,
-    ) -> InterpResult<'tcx> {
-        bug!("panics terminators are not evaluated in ConstProp")
-    }
-
-    fn binary_ptr_op(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        _bin_op: BinOp,
-        _left: &ImmTy<'tcx>,
-        _right: &ImmTy<'tcx>,
-    ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
-        // We can't do this because aliasing of memory can differ between const eval and llvm
-        throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
-    }
-
-    fn access_local<'a>(
-        frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
-        local: Local,
-    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::Provenance>> {
-        let l = &frame.locals[local];
-
-        if matches!(
-            l.value,
-            LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit))
-        ) {
-            // For us "uninit" means "we don't know its value, might be initiailized or not".
-            // So stop here.
-            throw_machine_stop_str!("tried to access a local with unknown value")
-        }
-
-        l.access()
-    }
-
-    fn access_local_mut<'a>(
-        ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-        frame: usize,
-        local: Local,
-    ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::Provenance>> {
-        if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
-            throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
-        }
-        if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
-            trace!(
-                "mutating local {:?} which is restricted to its block. \
-                Will remove it from const-prop after block is finished.",
-                local
-            );
-            ecx.machine.written_only_inside_own_block_locals.insert(local);
-        }
-        ecx.machine.stack[frame].locals[local].access_mut()
-    }
-
-    fn before_access_global(
-        _tcx: TyCtxt<'tcx>,
-        _machine: &Self,
-        _alloc_id: AllocId,
-        alloc: ConstAllocation<'tcx, Self::Provenance, Self::AllocExtra>,
-        _static_def_id: Option<DefId>,
-        is_write: bool,
-    ) -> InterpResult<'tcx> {
-        if is_write {
-            throw_machine_stop_str!("can't write to global");
-        }
-        // If the static allocation is mutable, then we can't const prop it as its content
-        // might be different at runtime.
-        if alloc.inner().mutability == Mutability::Mut {
-            throw_machine_stop_str!("can't access mutable globals in ConstProp");
-        }
-
-        Ok(())
-    }
-
-    #[inline(always)]
-    fn expose_ptr(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _ptr: Pointer<AllocId>,
-    ) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("exposing pointers isn't supported in ConstProp")
-    }
-
-    #[inline(always)]
-    fn init_frame_extra(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        frame: Frame<'mir, 'tcx>,
-    ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
-        Ok(frame)
-    }
-
-    #[inline(always)]
-    fn stack<'a>(
-        ecx: &'a InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] {
-        &ecx.machine.stack
-    }
-
-    #[inline(always)]
-    fn stack_mut<'a>(
-        ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
-        &mut ecx.machine.stack
-    }
-}
-
 /// Finds optimization opportunities on the MIR.
 struct ConstPropagator<'mir, 'tcx> {
     ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
@@ -711,139 +523,6 @@ fn const_prop(
     }
 }
 
-/// The mode that `ConstProp` is allowed to run in for a given `Local`.
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum ConstPropMode {
-    /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
-    FullConstProp,
-    /// The `Local` can only be propagated into and from its own block.
-    OnlyInsideOwnBlock,
-    /// The `Local` can be propagated into but reads cannot be propagated.
-    OnlyPropagateInto,
-    /// The `Local` cannot be part of propagation at all. Any statement
-    /// referencing it either for reading or writing will not get propagated.
-    NoPropagation,
-}
-
-struct CanConstProp {
-    can_const_prop: IndexVec<Local, ConstPropMode>,
-    // False at the beginning. Once set, no more assignments are allowed to that local.
-    found_assignment: BitSet<Local>,
-    // Cache of locals' information
-    local_kinds: IndexVec<Local, LocalKind>,
-}
-
-impl CanConstProp {
-    /// Returns true if `local` can be propagated
-    fn check<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        body: &Body<'tcx>,
-    ) -> IndexVec<Local, ConstPropMode> {
-        let mut cpv = CanConstProp {
-            can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
-            found_assignment: BitSet::new_empty(body.local_decls.len()),
-            local_kinds: IndexVec::from_fn_n(
-                |local| body.local_kind(local),
-                body.local_decls.len(),
-            ),
-        };
-        for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
-            let ty = body.local_decls[local].ty;
-            match tcx.layout_of(param_env.and(ty)) {
-                Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
-                // Either the layout fails to compute, then we can't use this local anyway
-                // or the local is too large, then we don't want to.
-                _ => {
-                    *val = ConstPropMode::NoPropagation;
-                    continue;
-                }
-            }
-            // Cannot use args at all
-            // Cannot use locals because if x < y { y - x } else { x - y } would
-            //        lint for x != y
-            // FIXME(oli-obk): lint variables until they are used in a condition
-            // FIXME(oli-obk): lint if return value is constant
-            if cpv.local_kinds[local] == LocalKind::Arg {
-                *val = ConstPropMode::OnlyPropagateInto;
-                trace!(
-                    "local {:?} can't be const propagated because it's a function argument",
-                    local
-                );
-            } else if cpv.local_kinds[local] == LocalKind::Var {
-                *val = ConstPropMode::OnlyInsideOwnBlock;
-                trace!(
-                    "local {:?} will only be propagated inside its block, because it's a user variable",
-                    local
-                );
-            }
-        }
-        cpv.visit_body(&body);
-        cpv.can_const_prop
-    }
-}
-
-impl Visitor<'_> for CanConstProp {
-    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
-        use rustc_middle::mir::visit::PlaceContext::*;
-        match context {
-            // Projections are fine, because `&mut foo.x` will be caught by
-            // `MutatingUseContext::Borrow` elsewhere.
-            MutatingUse(MutatingUseContext::Projection)
-            // These are just stores, where the storing is not propagatable, but there may be later
-            // mutations of the same local via `Store`
-            | MutatingUse(MutatingUseContext::Call)
-            | MutatingUse(MutatingUseContext::AsmOutput)
-            | MutatingUse(MutatingUseContext::Deinit)
-            // Actual store that can possibly even propagate a value
-            | MutatingUse(MutatingUseContext::SetDiscriminant)
-            | MutatingUse(MutatingUseContext::Store) => {
-                if !self.found_assignment.insert(local) {
-                    match &mut self.can_const_prop[local] {
-                        // If the local can only get propagated in its own block, then we don't have
-                        // to worry about multiple assignments, as we'll nuke the const state at the
-                        // end of the block anyway, and inside the block we overwrite previous
-                        // states as applicable.
-                        ConstPropMode::OnlyInsideOwnBlock => {}
-                        ConstPropMode::NoPropagation => {}
-                        ConstPropMode::OnlyPropagateInto => {}
-                        other @ ConstPropMode::FullConstProp => {
-                            trace!(
-                                "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
-                                local, other,
-                            );
-                            *other = ConstPropMode::OnlyInsideOwnBlock;
-                        }
-                    }
-                }
-            }
-            // Reading constants is allowed an arbitrary number of times
-            NonMutatingUse(NonMutatingUseContext::Copy)
-            | NonMutatingUse(NonMutatingUseContext::Move)
-            | NonMutatingUse(NonMutatingUseContext::Inspect)
-            | NonMutatingUse(NonMutatingUseContext::Projection)
-            | NonUse(_) => {}
-
-            // These could be propagated with a smarter analysis or just some careful thinking about
-            // whether they'd be fine right now.
-            MutatingUse(MutatingUseContext::Yield)
-            | MutatingUse(MutatingUseContext::Drop)
-            | MutatingUse(MutatingUseContext::Retag)
-            // These can't ever be propagated under any scheme, as we can't reason about indirect
-            // mutation.
-            | NonMutatingUse(NonMutatingUseContext::SharedBorrow)
-            | NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
-            | NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
-            | NonMutatingUse(NonMutatingUseContext::AddressOf)
-            | MutatingUse(MutatingUseContext::Borrow)
-            | MutatingUse(MutatingUseContext::AddressOf) => {
-                trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
-                self.can_const_prop[local] = ConstPropMode::NoPropagation;
-            }
-        }
-    }
-}
-
 impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
     fn visit_body(&mut self, body: &Body<'tcx>) {
         for (bb, data) in body.basic_blocks().iter_enumerated() {
index d305960b4856d23540a251ba2689ccbf0d8a9c54..180f4c7dcd6e80d1a1dac8e1c0f7c0623147ebff 100644 (file)
@@ -315,7 +315,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 /// with `0` executions.
 ///
 /// If there are no live `Counter` `Coverage` statements remaining, we remove
-/// dead `Coverage` statements along with the dead blocks. Since at least one
+/// `Coverage` statements along with the dead blocks. Since at least one
 /// counter per function is required by LLVM (and necessary, to add the
 /// `function_hash` to the counter's call to the LLVM intrinsic
 /// `instrprof.increment()`).
@@ -342,6 +342,16 @@ fn save_unreachable_coverage(
         }
     }
 
+    for block in &mut basic_blocks.raw[..first_dead_block] {
+        for statement in &mut block.statements {
+            let StatementKind::Coverage(_) = &statement.kind else { continue };
+            let instance = statement.source_info.scope.inlined_instance(source_scopes);
+            if !live.contains(&instance) {
+                statement.make_nop();
+            }
+        }
+    }
+
     if live.is_empty() {
         return;
     }
index f88997f884a4478bf5f5618fc14ab356e7631c9e..f3ccbbb56792dc3493c88a2487fec396a6ecb669 100644 (file)
@@ -7,7 +7,7 @@
 use crate::errors;
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{fluent, pluralize, struct_span_err, Applicability, MultiSpan};
+use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan};
 use rustc_expand::base::resolve_path;
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
@@ -1180,30 +1180,22 @@ fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: T
             _ => {
                 // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
                 // used this, so only emit a warning.
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    let mut diag =
-                        lint.build("attribute should be applied to a foreign function or static");
-                    diag.warn(
-                        "this was previously accepted by the compiler but is \
-                         being phased out; it will become a hard error in \
-                         a future release!",
+                let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span);
+                if let Some(s) = attr.value_str() {
+                    self.tcx.emit_spanned_lint(
+                        UNUSED_ATTRIBUTES,
+                        hir_id,
+                        attr.span,
+                        errors::LinkName { span, attr_span, value: s.as_str() },
                     );
-
-                    // See issue #47725
-                    if let Target::ForeignMod = target {
-                        if let Some(value) = attr.value_str() {
-                            diag.span_help(
-                                attr.span,
-                                &format!(r#"try `#[link(name = "{value}")]` instead"#),
-                            );
-                        } else {
-                            diag.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#);
-                        }
-                    }
-
-                    diag.span_label(span, "not a foreign function or static");
-                    diag.emit();
-                });
+                } else {
+                    self.tcx.emit_spanned_lint(
+                        UNUSED_ATTRIBUTES,
+                        hir_id,
+                        attr.span,
+                        errors::LinkName { span, attr_span, value: "..." },
+                    );
+                };
             }
         }
     }
@@ -1221,14 +1213,7 @@ fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Tar
                 true
             }
             _ => {
-                self.tcx
-                    .sess
-                    .struct_span_err(
-                        attr.span,
-                        "attribute should be applied to an `extern crate` item",
-                    )
-                    .span_label(span, "not an `extern crate` item")
-                    .emit();
+                self.tcx.sess.emit_err(errors::NoLink { attr_span: attr.span, span });
                 false
             }
         }
@@ -1258,14 +1243,7 @@ fn check_export_name(
                 true
             }
             _ => {
-                self.tcx
-                    .sess
-                    .struct_span_err(
-                        attr.span,
-                        "attribute should be applied to a free function, impl method or static",
-                    )
-                    .span_label(span, "not a free function, impl method or static")
-                    .emit();
+                self.tcx.sess.emit_err(errors::ExportName { attr_span: attr.span, span });
                 false
             }
         }
@@ -1278,11 +1256,10 @@ fn check_rustc_layout_scalar_valid_range(
         target: Target,
     ) -> bool {
         if target != Target::Struct {
-            self.tcx
-                .sess
-                .struct_span_err(attr.span, "attribute should be applied to a struct")
-                .span_label(span, "not a struct")
-                .emit();
+            self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
+                attr_span: attr.span,
+                span,
+            });
             return false;
         }
 
@@ -1293,10 +1270,7 @@ fn check_rustc_layout_scalar_valid_range(
         if matches!(&list[..], &[NestedMetaItem::Literal(Lit { kind: LitKind::Int(..), .. })]) {
             true
         } else {
-            self.tcx
-                .sess
-                .struct_span_err(attr.span, "expected exactly one integer literal argument")
-                .emit();
+            self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span });
             false
         }
     }
@@ -1311,11 +1285,10 @@ fn check_rustc_legacy_const_generics(
     ) -> bool {
         let is_function = matches!(target, Target::Fn);
         if !is_function {
-            self.tcx
-                .sess
-                .struct_span_err(attr.span, "attribute should be applied to a function")
-                .span_label(span, "not a function")
-                .emit();
+            self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+                attr_span: attr.span,
+                defn_span: span,
+            });
             return false;
         }
 
@@ -1335,29 +1308,20 @@ fn check_rustc_legacy_const_generics(
             match param.kind {
                 hir::GenericParamKind::Const { .. } => {}
                 _ => {
-                    self.tcx
-                        .sess
-                        .struct_span_err(
-                            attr.span,
-                            "#[rustc_legacy_const_generics] functions must \
-                             only have const generics",
-                        )
-                        .span_label(param.span, "non-const generic parameter")
-                        .emit();
+                    self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsOnly {
+                        attr_span: attr.span,
+                        param_span: param.span,
+                    });
                     return false;
                 }
             }
         }
 
         if list.len() != generics.params.len() {
-            self.tcx
-                .sess
-                .struct_span_err(
-                    attr.span,
-                    "#[rustc_legacy_const_generics] must have one index for each generic parameter",
-                )
-                .span_label(generics.span, "generic parameters")
-                .emit();
+            self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndex {
+                attr_span: attr.span,
+                generics_span: generics.span,
+            });
             return false;
         }
 
@@ -1367,19 +1331,10 @@ fn check_rustc_legacy_const_generics(
             if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) {
                 if *val >= arg_count {
                     let span = meta.span();
-                    self.tcx
-                        .sess
-                        .struct_span_err(span, "index exceeds number of arguments")
-                        .span_label(
-                            span,
-                            format!(
-                                "there {} only {} argument{}",
-                                pluralize!("is", arg_count),
-                                arg_count,
-                                pluralize!(arg_count)
-                            ),
-                        )
-                        .emit();
+                    self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexExceed {
+                        span,
+                        arg_count: arg_count as usize,
+                    });
                     return false;
                 }
             } else {
@@ -1388,10 +1343,7 @@ fn check_rustc_legacy_const_generics(
         }
 
         if !invalid_args.is_empty() {
-            self.tcx
-                .sess
-                .struct_span_err(invalid_args, "arguments should be non-negative integers")
-                .emit();
+            self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
             false
         } else {
             true
@@ -1403,11 +1355,10 @@ fn check_rustc_legacy_const_generics(
     fn check_applied_to_fn_or_method(&self, attr: &Attribute, span: Span, target: Target) -> bool {
         let is_function = matches!(target, Target::Fn | Target::Method(..));
         if !is_function {
-            self.tcx
-                .sess
-                .struct_span_err(attr.span, "attribute should be applied to a function")
-                .span_label(span, "not a function")
-                .emit();
+            self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+                attr_span: attr.span,
+                defn_span: span,
+            });
             false
         } else {
             true
@@ -1437,10 +1388,7 @@ fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool {
         if self.tcx.sess.opts.unstable_opts.query_dep_graph {
             true
         } else {
-            self.tcx
-                .sess
-                .struct_span_err(attr.span, "attribute requires -Z query-dep-graph to be enabled")
-                .emit();
+            self.tcx.sess.emit_err(errors::RustcDirtyClean { span: attr.span });
             false
         }
     }
@@ -1459,16 +1407,12 @@ fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target
             _ => {
                 // FIXME: #[link_section] was previously allowed on non-functions/statics and some
                 // crates used this, so only emit a warning.
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build("attribute should be applied to a function or static")
-                        .warn(
-                            "this was previously accepted by the compiler but is \
-                             being phased out; it will become a hard error in \
-                             a future release!",
-                        )
-                        .span_label(span, "not a function or static")
-                        .emit();
-                });
+                self.tcx.emit_spanned_lint(
+                    UNUSED_ATTRIBUTES,
+                    hir_id,
+                    attr.span,
+                    errors::LinkSection { span },
+                );
             }
         }
     }
@@ -1494,41 +1438,22 @@ fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: T
                     Target::ForeignStatic => "static",
                     _ => unreachable!(),
                 };
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build(&format!(
-                        "`#[no_mangle]` has no effect on a foreign {foreign_item_kind}"
-                    ))
-                    .warn(
-                        "this was previously accepted by the compiler but is \
-                            being phased out; it will become a hard error in \
-                            a future release!",
-                    )
-                    .span_label(span, format!("foreign {foreign_item_kind}"))
-                    .note("symbol names in extern blocks are not mangled")
-                    .span_suggestion(
-                        attr.span,
-                        "remove this attribute",
-                        "",
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
-                });
+                self.tcx.emit_spanned_lint(
+                    UNUSED_ATTRIBUTES,
+                    hir_id,
+                    attr.span,
+                    errors::NoMangleForeign { span, attr_span: attr.span, foreign_item_kind },
+                );
             }
             _ => {
                 // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
                 // crates used this, so only emit a warning.
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build(
-                        "attribute should be applied to a free function, impl method or static",
-                    )
-                    .warn(
-                        "this was previously accepted by the compiler but is \
-                         being phased out; it will become a hard error in \
-                         a future release!",
-                    )
-                    .span_label(span, "not a free function, impl method or static")
-                    .emit();
-                });
+                self.tcx.emit_spanned_lint(
+                    UNUSED_ATTRIBUTES,
+                    hir_id,
+                    attr.span,
+                    errors::NoMangle { span },
+                );
             }
         }
     }
@@ -1561,13 +1486,7 @@ fn check_repr(
 
         for hint in &hints {
             if !hint.is_meta_item() {
-                struct_span_err!(
-                    self.tcx.sess,
-                    hint.span(),
-                    E0565,
-                    "meta item in `repr` must be an identifier"
-                )
-                .emit();
+                self.tcx.sess.emit_err(errors::ReprIdent { span: hint.span() });
                 continue;
             }
 
@@ -1688,15 +1607,11 @@ fn check_repr(
                     return false;
                 }))
         {
-            self.tcx.struct_span_lint_hir(
+            self.tcx.emit_spanned_lint(
                 CONFLICTING_REPR_HINTS,
                 hir_id,
                 hint_spans.collect::<Vec<Span>>(),
-                |lint| {
-                    lint.build("conflicting representation hints")
-                        .code(rustc_errors::error_code!(E0566))
-                        .emit();
-                },
+                errors::ReprConflicting,
             );
         }
     }
@@ -1706,9 +1621,7 @@ fn check_used(&self, attrs: &[Attribute], target: Target) {
         let mut used_compiler_span = None;
         for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
             if target != Target::Static {
-                self.tcx
-                    .sess
-                    .span_err(attr.span, "attribute must be applied to a `static` variable");
+                self.tcx.sess.emit_err(errors::UsedStatic { span: attr.span });
             }
             let inner = attr.meta_item_list();
             match inner.as_deref() {
@@ -1734,14 +1647,9 @@ fn check_used(&self, attrs: &[Attribute], target: Target) {
             }
         }
         if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
-            let spans = vec![linker_span, compiler_span];
             self.tcx
                 .sess
-                .struct_span_err(
-                    spans,
-                    "`used(compiler)` and `used(linker)` can't be used together",
-                )
-                .emit();
+                .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
         }
     }
 
@@ -1783,9 +1691,7 @@ fn check_allow_internal_unstable(
             _ => {
                 self.tcx
                     .sess
-                    .struct_span_err(attr.span, "attribute should be applied to a macro")
-                    .span_label(span, "not a macro")
-                    .emit();
+                    .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span });
                 false
             }
         }
@@ -1796,29 +1702,26 @@ fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
         match target {
             Target::Mod => {}
             _ => {
-                self.tcx
-                    .sess
-                    .struct_span_err(attr.span, "attribute should be applied to a module")
-                    .emit();
+                self.tcx.sess.emit_err(errors::DebugVisualizerPlacement { span: attr.span });
                 return false;
             }
         }
 
         let Some(hints) = attr.meta_item_list() else {
-            self.emit_debugger_visualizer_err(attr.span);
+            self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
             return false;
         };
 
         let hint = match hints.len() {
             1 => &hints[0],
             _ => {
-                self.emit_debugger_visualizer_err(attr.span);
+                self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
                 return false;
             }
         };
 
         let Some(meta_item) = hint.meta_item() else {
-            self.emit_debugger_visualizer_err(attr.span);
+            self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
             return false;
         };
 
@@ -1826,7 +1729,7 @@ fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
             (sym::natvis_file, Some(value)) => value,
             (sym::gdb_script_file, Some(value)) => value,
             (_, _) => {
-                self.emit_debugger_visualizer_err(meta_item.span);
+                self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span });
                 return false;
             }
         };
@@ -1855,16 +1758,6 @@ fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
         }
     }
 
-    fn emit_debugger_visualizer_err(&self, span: Span) {
-        self.tcx
-            .sess
-            .struct_span_err(span, "invalid argument")
-            .note(r#"expected: `natvis_file = "..."`"#)
-            .note(r#"OR"#)
-            .note(r#"expected: `gdb_script_file = "..."`"#)
-            .emit();
-    }
-
     /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
     /// (Allows proc_macro functions)
     fn check_rustc_allow_const_fn_unstable(
@@ -1891,9 +1784,7 @@ fn check_rustc_allow_const_fn_unstable(
             _ => {
                 self.tcx
                     .sess
-                    .struct_span_err(attr.span, "attribute should be applied to `const fn`")
-                    .span_label(span, "not a `const fn`")
-                    .emit();
+                    .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span });
                 false
             }
         }
@@ -1910,9 +1801,7 @@ fn check_rustc_std_internal_symbol(
             _ => {
                 self.tcx
                     .sess
-                    .struct_span_err(attr.span, "attribute should be applied functions or statics")
-                    .span_label(span, "not a function or static")
-                    .emit();
+                    .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span });
                 false
             }
         }
@@ -1923,10 +1812,7 @@ fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bo
         match target {
             Target::Trait => true,
             _ => {
-                self.tcx
-                    .sess
-                    .struct_span_err(attr.span, "attribute should be applied to a trait")
-                    .emit();
+                self.tcx.sess.emit_err(errors::ConstTrait { attr_span: attr.span });
                 false
             }
         }
@@ -1935,10 +1821,7 @@ fn check_const_trait(&self, attr: &Attribute, _span: Span, target: Target) -> bo
     fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
         match target {
             Target::Expression => {
-                self.tcx
-                    .sess
-                    .struct_span_err(attr.span, "attribute cannot be applied to an expression")
-                    .emit();
+                self.tcx.sess.emit_err(errors::StabilityPromotable { attr_span: attr.span });
                 false
             }
             _ => true,
@@ -1948,9 +1831,12 @@ fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Targ
     fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
         match target {
             Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build("attribute is ignored here").emit();
-                });
+                self.tcx.emit_spanned_lint(
+                    UNUSED_ATTRIBUTES,
+                    hir_id,
+                    attr.span,
+                    errors::Deprecated,
+                );
             }
             _ => {}
         }
@@ -1961,29 +1847,30 @@ fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         match target {
             Target::ExternCrate | Target::Mod => {}
             _ => {
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build(&format!(
-                        "`#[{name}]` only has an effect on `extern crate` and modules"
-                    ))
-                    .emit();
-                });
+                self.tcx.emit_spanned_lint(
+                    UNUSED_ATTRIBUTES,
+                    hir_id,
+                    attr.span,
+                    errors::MacroUse { name },
+                );
             }
         }
     }
 
     fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         if target != Target::MacroDef {
-            self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                lint.build("`#[macro_export]` only has an effect on macro definitions").emit();
-            });
+            self.tcx.emit_spanned_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::MacroExport);
         }
     }
 
     fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         if target != Target::Fn {
-            self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                lint.build("`#[plugin_registrar]` only has an effect on functions").emit();
-            });
+            self.tcx.emit_spanned_lint(
+                UNUSED_ATTRIBUTES,
+                hir_id,
+                attr.span,
+                errors::PluginRegistrar,
+            );
         }
     }
 
@@ -2002,10 +1889,7 @@ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
                 | sym::target_feature
         ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
         {
-            format!(
-                "attribute `{}` with an empty list has no effect",
-                attr.name_or_empty()
-            )
+            errors::UnusedNote::EmptyList { name: attr.name_or_empty() }
         } else if matches!(
                 attr.name_or_empty(),
                 sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
@@ -2015,27 +1899,19 @@ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
             && let MetaItemKind::NameValue(_) = &item.kind
             && item.path == sym::reason
         {
-            format!(
-                "attribute `{}` without any lints has no effect",
-                attr.name_or_empty()
-            )
+            errors::UnusedNote::NoLints { name: attr.name_or_empty() }
         } else if attr.name_or_empty() == sym::default_method_body_is_const {
-            format!("`default_method_body_is_const` has been replaced with `#[const_trait]` on traits")
+            errors::UnusedNote::DefaultMethodBodyConst
         } else {
             return;
         };
 
-        self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-            lint.build("unused attribute")
-                .span_suggestion(
-                    attr.span,
-                    "remove this attribute",
-                    "",
-                    Applicability::MachineApplicable,
-                )
-                .note(&note)
-                .emit();
-        });
+        self.tcx.emit_spanned_lint(
+            UNUSED_ATTRIBUTES,
+            hir_id,
+            attr.span,
+            errors::Unused { attr_span: attr.span, note },
+        );
     }
 }
 
@@ -2206,14 +2082,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
 
     for attr in attrs {
         if attr.has_name(sym::inline) {
-            struct_span_err!(
-                tcx.sess,
-                attr.span,
-                E0518,
-                "attribute should be applied to function or closure",
-            )
-            .span_label(attr.span, "not a function or closure")
-            .emit();
+            tcx.sess.emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span });
         }
     }
 }
@@ -2253,23 +2122,20 @@ fn check_duplicates(
                     } else {
                         (attr.span, *entry.get())
                     };
-                    tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, this, |lint| {
-                        let mut db = lint.build("unused attribute");
-                        db.span_note(other, "attribute also specified here").span_suggestion(
+                    tcx.emit_spanned_lint(
+                        UNUSED_ATTRIBUTES,
+                        hir_id,
+                        this,
+                        errors::UnusedDuplicate {
                             this,
-                            "remove this attribute",
-                            "",
-                            Applicability::MachineApplicable,
-                        );
-                        if matches!(duplicates, FutureWarnFollowing | FutureWarnPreceding) {
-                            db.warn(
-                                "this was previously accepted by the compiler but is \
-                                 being phased out; it will become a hard error in \
-                                 a future release!",
-                            );
-                        }
-                        db.emit();
-                    });
+                            other,
+                            warning: matches!(
+                                duplicates,
+                                FutureWarnFollowing | FutureWarnPreceding
+                            )
+                            .then_some(()),
+                        },
+                    );
                 }
                 Entry::Vacant(entry) => {
                     entry.insert(attr.span);
@@ -2284,19 +2150,11 @@ fn check_duplicates(
                 } else {
                     (attr.span, *entry.get())
                 };
-                tcx.sess
-                    .struct_span_err(
-                        this,
-                        &format!("multiple `{}` attributes", attr.name_or_empty()),
-                    )
-                    .span_note(other, "attribute also specified here")
-                    .span_suggestion(
-                        this,
-                        "remove this attribute",
-                        "",
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
+                tcx.sess.emit_err(errors::UnusedMultiple {
+                    this,
+                    other,
+                    name: attr.name_or_empty(),
+                });
             }
             Entry::Vacant(entry) => {
                 entry.insert(attr.span);
index fcd1e9363b1bed01018495447afebf0d5e9fe647..0d4317f6b8881e1dbaff8c9234d49e6e351d3be8 100644 (file)
@@ -1,5 +1,5 @@
 use rustc_errors::{Applicability, MultiSpan};
-use rustc_macros::{LintDiagnostic, SessionDiagnostic};
+use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::{Span, Symbol};
 
 #[derive(LintDiagnostic)]
@@ -360,3 +360,268 @@ pub struct Link {
     #[label]
     pub span: Option<Span>,
 }
+
+#[derive(LintDiagnostic)]
+#[lint(passes::link_name)]
+#[warn_]
+pub struct LinkName<'a> {
+    #[help]
+    pub attr_span: Option<Span>,
+    #[label]
+    pub span: Span,
+    pub value: &'a str,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::no_link)]
+pub struct NoLink {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::export_name)]
+pub struct ExportName {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_layout_scalar_valid_range_not_struct)]
+pub struct RustcLayoutScalarValidRangeNotStruct {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_layout_scalar_valid_range_arg)]
+pub struct RustcLayoutScalarValidRangeArg {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_legacy_const_generics_only)]
+pub struct RustcLegacyConstGenericsOnly {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub param_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_legacy_const_generics_index)]
+pub struct RustcLegacyConstGenericsIndex {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub generics_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_legacy_const_generics_index_exceed)]
+pub struct RustcLegacyConstGenericsIndexExceed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub arg_count: usize,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_legacy_const_generics_index_negative)]
+pub struct RustcLegacyConstGenericsIndexNegative {
+    #[primary_span]
+    pub invalid_args: Vec<Span>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_dirty_clean)]
+pub struct RustcDirtyClean {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::link_section)]
+#[warn_]
+pub struct LinkSection {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::no_mangle_foreign)]
+#[warn_]
+#[note]
+pub struct NoMangleForeign {
+    #[label]
+    pub span: Span,
+    #[suggestion(applicability = "machine-applicable")]
+    pub attr_span: Span,
+    pub foreign_item_kind: &'static str,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::no_mangle)]
+#[warn_]
+pub struct NoMangle {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::repr_ident, code = "E0565")]
+pub struct ReprIdent {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::repr_conflicting, code = "E0566")]
+pub struct ReprConflicting;
+
+#[derive(SessionDiagnostic)]
+#[error(passes::used_static)]
+pub struct UsedStatic {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::used_compiler_linker)]
+pub struct UsedCompilerLinker {
+    #[primary_span]
+    pub spans: Vec<Span>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::allow_internal_unstable)]
+pub struct AllowInternalUnstable {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::debug_visualizer_placement)]
+pub struct DebugVisualizerPlacement {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::debug_visualizer_invalid)]
+#[note(passes::note_1)]
+#[note(passes::note_2)]
+#[note(passes::note_3)]
+pub struct DebugVisualizerInvalid {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_allow_const_fn_unstable)]
+pub struct RustcAllowConstFnUnstable {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::rustc_std_internal_symbol)]
+pub struct RustcStdInternalSymbol {
+    #[primary_span]
+    pub attr_span: Span,
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::const_trait)]
+pub struct ConstTrait {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::stability_promotable)]
+pub struct StabilityPromotable {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::deprecated)]
+pub struct Deprecated;
+
+#[derive(LintDiagnostic)]
+#[lint(passes::macro_use)]
+pub struct MacroUse {
+    pub name: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::macro_export)]
+pub struct MacroExport;
+
+#[derive(LintDiagnostic)]
+#[lint(passes::plugin_registrar)]
+pub struct PluginRegistrar;
+
+#[derive(SessionSubdiagnostic)]
+pub enum UnusedNote {
+    #[note(passes::unused_empty_lints_note)]
+    EmptyList { name: Symbol },
+    #[note(passes::unused_no_lints_note)]
+    NoLints { name: Symbol },
+    #[note(passes::unused_default_method_body_const_note)]
+    DefaultMethodBodyConst,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::unused)]
+pub struct Unused {
+    #[suggestion(applicability = "machine-applicable")]
+    pub attr_span: Span,
+    #[subdiagnostic]
+    pub note: UnusedNote,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::non_exported_macro_invalid_attrs, code = "E0518")]
+pub struct NonExportedMacroInvalidAttrs {
+    #[primary_span]
+    #[label]
+    pub attr_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(passes::unused_duplicate)]
+pub struct UnusedDuplicate {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub this: Span,
+    #[note]
+    pub other: Span,
+    #[warn_]
+    pub warning: Option<()>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(passes::unused_multiple)]
+pub struct UnusedMultiple {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub this: Span,
+    #[note]
+    pub other: Span,
+    pub name: Symbol,
+}
index 81b04c414ed9b6c11ba48e8f078310476b359407..ca6a2ac3db34cde86ea97f27e3333a8c08276473 100644 (file)
@@ -2,7 +2,7 @@
 //! propagating default levels lexically from parent to children ast nodes.
 
 use attr::StabilityLevel;
-use rustc_attr::{self as attr, ConstStability, Stability, Unstable};
+use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
@@ -634,12 +634,9 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
         // while maintaining the invariant that all sysroot crates are unstable
         // by default and are unable to be used.
         if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
-            let reason = "this crate is being loaded from the sysroot, an \
-                          unstable location; did you mean to load this crate \
-                          from crates.io via `Cargo.toml` instead?";
             let stability = Stability {
                 level: attr::StabilityLevel::Unstable {
-                    reason: Some(Symbol::intern(reason)),
+                    reason: UnstableReason::Default,
                     issue: NonZeroU32::new(27812),
                     is_soft: false,
                     implied_by: None,
index 6631470f2191ba27ed8be21956310bb642a2c9b0..e955a1798b73563199056b85371e71c56ed16475 100644 (file)
@@ -524,7 +524,7 @@ fn build_reduced_graph_for_use_tree(
                         let crate_root = self.r.resolve_crate_root(source.ident);
                         let crate_name = match crate_root.kind {
                             ModuleKind::Def(.., name) => name,
-                            ModuleKind::Block(..) => unreachable!(),
+                            ModuleKind::Block => unreachable!(),
                         };
                         // HACK(eddyb) unclear how good this is, but keeping `$crate`
                         // in `source` breaks `src/test/ui/imports/import-crate-var.rs`,
@@ -936,7 +936,7 @@ fn build_reduced_graph_for_block(&mut self, block: &Block) {
         if self.block_needs_anonymous_module(block) {
             let module = self.r.new_module(
                 Some(parent),
-                ModuleKind::Block(block.id),
+                ModuleKind::Block,
                 expansion.to_expn_id(),
                 block.span,
                 parent.no_implicit_prelude,
index d74e26fc84498cf6c3bf997ccd68b558ad64a5ca..0343e8d9b8ec34f5ac8181d90480f79f0e2a09a2 100644 (file)
@@ -163,7 +163,7 @@ pub(crate) fn report_conflict<'b>(
 
         let container = match parent.kind {
             ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
-            ModuleKind::Block(..) => "block",
+            ModuleKind::Block => "block",
         };
 
         let old_noun = match old_binding.is_import() {
@@ -565,8 +565,7 @@ pub(crate) fn into_struct_error(
                     } else if let Some(sp) = sm.generate_fn_name_span(span) {
                         err.span_label(
                             sp,
-                            "try adding a local generic parameter in this method instead"
-                                .to_string(),
+                            "try adding a local generic parameter in this method instead",
                         );
                     } else {
                         err.help("try using a local generic parameter instead");
index 0cc6d05d1d086ac072ea3c175978268e9cd36c51..6e6782881427b678e1ecc863a7bd31524dba17eb 100644 (file)
@@ -218,7 +218,7 @@ fn hygienic_lexical_parent(
             return Some((self.expn_def_scope(ctxt.remove_mark()), None));
         }
 
-        if let ModuleKind::Block(..) = module.kind {
+        if let ModuleKind::Block = module.kind {
             return Some((module.parent.unwrap().nearest_item_scope(), None));
         }
 
@@ -333,7 +333,7 @@ pub(crate) fn resolve_ident_in_lexical_scope(
             };
 
             match module.kind {
-                ModuleKind::Block(..) => {} // We can see through blocks
+                ModuleKind::Block => {} // We can see through blocks
                 _ => break,
             }
 
index e739ed678d8be8aa18f2256a0a3430ee22f028e5..9b5fd4ea6d133918a437bdf3afafa2d56af95c57 100644 (file)
@@ -21,6 +21,7 @@
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_middle::middle::resolve_lifetime::Set1;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 /// Map from the name in a pattern to its binding mode.
 type BindingMap = IdentMap<BindingInfo>;
 
+use diagnostics::{
+    ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind,
+};
+
 #[derive(Copy, Clone, Debug)]
 struct BindingInfo {
     span: Span,
@@ -258,7 +263,13 @@ enum LifetimeRibKind {
     AnonymousReportError,
 
     /// Pass responsibility to `resolve_lifetime` code for all cases.
-    AnonymousPassThrough(NodeId, /* in_fn_return */ bool),
+    AnonymousPassThrough(NodeId),
+
+    /// Replace all anonymous lifetimes by provided lifetime.
+    Elided(LifetimeRes),
+
+    /// Signal we cannot find which should be the anonymous lifetime.
+    ElisionFailure,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -522,6 +533,10 @@ struct DiagnosticMetadata<'ast> {
 
     /// When processing impl trait
     currently_processing_impl_trait: Option<(TraitRef, Ty)>,
+
+    /// Accumulate the errors due to missed lifetime elision,
+    /// and report them all at once for each function.
+    current_elision_failures: Vec<MissingLifetime>,
 }
 
 struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -540,6 +555,13 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
     /// The current set of local scopes for lifetimes.
     lifetime_ribs: Vec<LifetimeRib>,
 
+    /// We are looking for lifetimes in an elision context.
+    /// The set contains all the resolutions that we encountered so far.
+    /// They will be used to determine the correct lifetime for the fn return type.
+    /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
+    /// lifetimes.
+    lifetime_elision_candidates: Option<FxIndexMap<LifetimeRes, LifetimeElisionCandidate>>,
+
     /// The trait that the current context can refer to.
     current_trait_ref: Option<(Module<'a>, TraitRef)>,
 
@@ -580,7 +602,9 @@ fn visit_block(&mut self, block: &'ast Block) {
     fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
         // We deal with repeat expressions explicitly in `resolve_expr`.
         self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
-            this.resolve_anon_const(constant, IsRepeatExpr::No);
+            this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+                this.resolve_anon_const(constant, IsRepeatExpr::No);
+            })
         })
     }
     fn visit_expr(&mut self, expr: &'ast Expr) {
@@ -607,8 +631,10 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
             TyKind::Rptr(None, _) => {
                 // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
                 // NodeId `ty.id`.
+                // This span will be used in case of elision failure.
                 let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
                 self.resolve_elided_lifetime(ty.id, span);
+                visit::walk_ty(self, ty);
             }
             TyKind::Path(ref qself, ref path) => {
                 self.diagnostic_metadata.current_type_path = Some(ty);
@@ -634,8 +660,8 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                         },
                         |this| this.visit_path(&path, ty.id),
                     );
-                    self.diagnostic_metadata.current_type_path = prev_ty;
-                    return;
+                } else {
+                    visit::walk_ty(self, ty)
                 }
             }
             TyKind::ImplicitSelf => {
@@ -649,9 +675,16 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                     )
                     .map_or(Res::Err, |d| d.res());
                 self.r.record_partial_res(ty.id, PartialRes::new(res));
+                visit::walk_ty(self, ty)
+            }
+            TyKind::ImplTrait(..) => {
+                let candidates = self.lifetime_elision_candidates.take();
+                visit::walk_ty(self, ty);
+                self.lifetime_elision_candidates = candidates;
             }
             TyKind::TraitObject(ref bounds, ..) => {
                 self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
+                visit::walk_ty(self, ty)
             }
             TyKind::BareFn(ref bare_fn) => {
                 let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
@@ -665,25 +698,20 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                     },
                     |this| {
                         this.visit_generic_params(&bare_fn.generic_params, false);
-                        this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousCreateParameter {
-                                binder: ty.id,
-                                report_in_path: false,
-                            },
-                            |this| walk_list!(this, visit_param, &bare_fn.decl.inputs),
-                        );
-                        this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(ty.id, true),
-                            |this| this.visit_fn_ret_ty(&bare_fn.decl.output),
+                        this.resolve_fn_signature(
+                            ty.id,
+                            None,
+                            false,
+                            // We don't need to deal with patterns in parameters, because
+                            // they are not possible for foreign or bodiless functions.
+                            bare_fn.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
+                            &bare_fn.decl.output,
                         );
                     },
-                );
-                self.diagnostic_metadata.current_trait_object = prev;
-                return;
+                )
             }
-            _ => (),
+            _ => visit::walk_ty(self, ty),
         }
-        visit::walk_ty(self, ty);
         self.diagnostic_metadata.current_trait_object = prev;
         self.diagnostic_metadata.current_type_path = prev_ty;
     }
@@ -757,18 +785,12 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
             | FnKind::Fn(_, _, sig, _, generics, None) => {
                 self.visit_fn_header(&sig.header);
                 self.visit_generics(generics);
-                // We don't need to deal with patterns in parameters, because
-                // they are not possible for foreign or bodiless functions.
-                self.with_lifetime_rib(
-                    LifetimeRibKind::AnonymousCreateParameter {
-                        binder: fn_id,
-                        report_in_path: false,
-                    },
-                    |this| walk_list!(this, visit_param, &sig.decl.inputs),
-                );
-                self.with_lifetime_rib(
-                    LifetimeRibKind::AnonymousPassThrough(fn_id, true),
-                    |this| this.visit_fn_ret_ty(&sig.decl.output),
+                self.resolve_fn_signature(
+                    fn_id,
+                    None,
+                    sig.decl.has_self(),
+                    sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
+                    &sig.decl.output,
                 );
                 return;
             }
@@ -793,19 +815,15 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
                         let declaration = &sig.decl;
                         let async_node_id = sig.header.asyncness.opt_return_id();
 
-                        // Argument-position elided lifetimes must be transformed into fresh
-                        // generic parameters.  This is especially useful for `async fn`, where
-                        // these fresh generic parameters can be applied to the opaque `impl Trait`
-                        // return type.
-                        this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousCreateParameter {
-                                binder: fn_id,
-                                // Only emit a hard error for `async fn`, since this kind of
-                                // elision has always been allowed in regular `fn`s.
-                                report_in_path: async_node_id.is_some(),
-                            },
-                            // Add each argument to the rib.
-                            |this| this.resolve_params(&declaration.inputs),
+                        this.resolve_fn_signature(
+                            fn_id,
+                            async_node_id,
+                            declaration.has_self(),
+                            declaration
+                                .inputs
+                                .iter()
+                                .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
+                            &declaration.output,
                         );
 
                         // Construct the list of in-scope lifetime parameters for async lowering.
@@ -844,23 +862,13 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
                                 .insert(async_node_id, extra_lifetime_params);
                         }
 
-                        this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(
-                                // For async fn, the return type appears inside a custom
-                                // `impl Future` RPIT, so we override the binder's id.
-                                async_node_id.unwrap_or(fn_id),
-                                true,
-                            ),
-                            |this| visit::walk_fn_ret_ty(this, &declaration.output),
-                        );
-
                         if let Some(body) = body {
                             // 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
                             this.with_lifetime_rib(
-                                LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                                LifetimeRibKind::AnonymousPassThrough(fn_id),
                                 |this| this.visit_block(body),
                             );
 
@@ -888,7 +896,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
                         this.with_lifetime_rib(
                             match binder {
                                 ClosureBinder::NotPresent => {
-                                    LifetimeRibKind::AnonymousPassThrough(fn_id, true)
+                                    LifetimeRibKind::AnonymousPassThrough(fn_id)
                                 }
                                 ClosureBinder::For { .. } => LifetimeRibKind::AnonymousReportError,
                             },
@@ -900,7 +908,7 @@ fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
                         let previous_state = replace(&mut this.in_func_body, true);
                         // Resolve the function body, potentially inside the body of an async closure
                         this.with_lifetime_rib(
-                            LifetimeRibKind::AnonymousPassThrough(fn_id, false),
+                            LifetimeRibKind::AnonymousPassThrough(fn_id),
                             |this| this.visit_expr(body),
                         );
 
@@ -1030,16 +1038,12 @@ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegmen
                                 kind: LifetimeBinderKind::PolyTrait,
                                 ..
                             } => {
-                                self.with_lifetime_rib(
-                                    LifetimeRibKind::AnonymousCreateParameter {
-                                        binder,
-                                        report_in_path: false,
-                                    },
-                                    |this| walk_list!(this, visit_ty, &p_args.inputs),
-                                );
-                                self.with_lifetime_rib(
-                                    LifetimeRibKind::AnonymousPassThrough(binder, true),
-                                    |this| visit::walk_fn_ret_ty(this, &p_args.output),
+                                self.resolve_fn_signature(
+                                    binder,
+                                    None,
+                                    false,
+                                    p_args.inputs.iter().map(|ty| (None, &**ty)),
+                                    &p_args.output,
                                 );
                                 break;
                             }
@@ -1052,6 +1056,8 @@ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegmen
                             LifetimeRibKind::AnonymousPassThrough(..)
                             | LifetimeRibKind::AnonymousCreateParameter { .. }
                             | LifetimeRibKind::AnonymousReportError
+                            | LifetimeRibKind::Elided(_)
+                            | LifetimeRibKind::ElisionFailure
                             | LifetimeRibKind::AnonConst
                             | LifetimeRibKind::ConstGeneric => {}
                         }
@@ -1156,6 +1162,7 @@ fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> {
             },
             label_ribs: Vec::new(),
             lifetime_ribs: Vec::new(),
+            lifetime_elision_candidates: None,
             current_trait_ref: None,
             diagnostic_metadata: Box::new(DiagnosticMetadata::default()),
             // errors at module scope should always be reported
@@ -1362,7 +1369,9 @@ fn with_lifetime_rib<T>(
         work: impl FnOnce(&mut Self) -> T,
     ) -> T {
         self.lifetime_ribs.push(LifetimeRib::new(kind));
+        let outer_elision_candidates = self.lifetime_elision_candidates.take();
         let ret = work(self);
+        self.lifetime_elision_candidates = outer_elision_candidates;
         self.lifetime_ribs.pop();
         ret
     }
@@ -1372,7 +1381,11 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::Lifeti
         let ident = lifetime.ident;
 
         if ident.name == kw::StaticLifetime {
-            self.record_lifetime_res(lifetime.id, LifetimeRes::Static);
+            self.record_lifetime_res(
+                lifetime.id,
+                LifetimeRes::Static,
+                LifetimeElisionCandidate::Named,
+            );
             return;
         }
 
@@ -1385,7 +1398,7 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::Lifeti
             let rib = &self.lifetime_ribs[i];
             let normalized_ident = ident.normalize_to_macros_2_0();
             if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
-                self.record_lifetime_res(lifetime.id, res);
+                self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
 
                 if let LifetimeRes::Param { param, .. } = res {
                     match self.lifetime_uses.entry(param) {
@@ -1399,15 +1412,20 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::Lifeti
                                     // Do not suggest eliding a lifetime where an anonymous
                                     // lifetime would be illegal.
                                     LifetimeRibKind::Item
-                                    | LifetimeRibKind::AnonymousPassThrough(_, true)
-                                    | LifetimeRibKind::AnonymousReportError => {
-                                        Some(LifetimeUseSet::Many)
-                                    }
+                                    | LifetimeRibKind::AnonymousReportError
+                                    | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
                                     // An anonymous lifetime is legal here, go ahead.
-                                    LifetimeRibKind::AnonymousPassThrough(_, false)
+                                    LifetimeRibKind::AnonymousPassThrough(_)
                                     | LifetimeRibKind::AnonymousCreateParameter { .. } => {
                                         Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
                                     }
+                                    // Only report if eliding the lifetime would have the same
+                                    // semantics.
+                                    LifetimeRibKind::Elided(r) => Some(if res == r {
+                                        LifetimeUseSet::One { use_span: ident.span, use_ctxt }
+                                    } else {
+                                        LifetimeUseSet::Many
+                                    }),
                                     LifetimeRibKind::Generics { .. }
                                     | LifetimeRibKind::ConstGeneric
                                     | LifetimeRibKind::AnonConst => None,
@@ -1429,12 +1447,20 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::Lifeti
                 LifetimeRibKind::Item => break,
                 LifetimeRibKind::ConstGeneric => {
                     self.emit_non_static_lt_in_const_generic_error(lifetime);
-                    self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
+                    self.record_lifetime_res(
+                        lifetime.id,
+                        LifetimeRes::Error,
+                        LifetimeElisionCandidate::Ignore,
+                    );
                     return;
                 }
                 LifetimeRibKind::AnonConst => {
                     self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
-                    self.r.lifetimes_res_map.insert(lifetime.id, LifetimeRes::Error);
+                    self.record_lifetime_res(
+                        lifetime.id,
+                        LifetimeRes::Error,
+                        LifetimeElisionCandidate::Ignore,
+                    );
                     return;
                 }
                 _ => {}
@@ -1452,19 +1478,31 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::Lifeti
         }
 
         self.emit_undeclared_lifetime_error(lifetime, outer_res);
-        self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
+        self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named);
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
     fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
         debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
 
+        let missing_lifetime = MissingLifetime {
+            id: lifetime.id,
+            span: lifetime.ident.span,
+            kind: if elided {
+                MissingLifetimeKind::Ampersand
+            } else {
+                MissingLifetimeKind::Underscore
+            },
+            count: 1,
+        };
+        let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
         for i in (0..self.lifetime_ribs.len()).rev() {
             let rib = &mut self.lifetime_ribs[i];
+            debug!(?rib.kind);
             match rib.kind {
                 LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
                     let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder);
-                    self.record_lifetime_res(lifetime.id, res);
+                    self.record_lifetime_res(lifetime.id, res, elision_candidate);
                     return;
                 }
                 LifetimeRibKind::AnonymousReportError => {
@@ -1486,39 +1524,46 @@ fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
                     .span_label(lifetime.ident.span, note)
                     .emit();
 
-                    self.record_lifetime_res(lifetime.id, LifetimeRes::Error);
+                    self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
                     return;
                 }
-                LifetimeRibKind::AnonymousPassThrough(node_id, _) => {
+                LifetimeRibKind::AnonymousPassThrough(node_id) => {
                     self.record_lifetime_res(
                         lifetime.id,
                         LifetimeRes::Anonymous { binder: node_id, elided },
+                        elision_candidate,
                     );
                     return;
                 }
+                LifetimeRibKind::Elided(res) => {
+                    self.record_lifetime_res(lifetime.id, res, elision_candidate);
+                    return;
+                }
+                LifetimeRibKind::ElisionFailure => {
+                    self.diagnostic_metadata.current_elision_failures.push(missing_lifetime);
+                    self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
+                    return;
+                }
                 LifetimeRibKind::Item => break,
                 LifetimeRibKind::Generics { .. }
                 | LifetimeRibKind::ConstGeneric
                 | LifetimeRibKind::AnonConst => {}
             }
         }
-        // This resolution is wrong, it passes the work to HIR lifetime resolution.
-        // We cannot use `LifetimeRes::Error` because we do not emit a diagnostic.
-        self.record_lifetime_res(
-            lifetime.id,
-            LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided },
-        );
+        self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
+        self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
     }
 
     #[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.record_lifetime_res(
             anchor_id,
             LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
+            LifetimeElisionCandidate::Ignore,
         );
-
-        let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) };
         self.resolve_anonymous_lifetime(&lt, true);
     }
 
@@ -1603,16 +1648,17 @@ fn resolve_elided_lifetimes_in_path(
             self.record_lifetime_res(
                 segment_id,
                 LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+                LifetimeElisionCandidate::Ignore,
             );
 
             if !missing {
                 // Do not create a parameter for patterns and expressions.
                 for rib in self.lifetime_ribs.iter().rev() {
                     match rib.kind {
-                        LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+                        LifetimeRibKind::AnonymousPassThrough(binder) => {
                             let res = LifetimeRes::Anonymous { binder, elided: true };
                             for id in node_ids {
-                                self.record_lifetime_res(id, res);
+                                self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
                             }
                             break;
                         }
@@ -1627,11 +1673,13 @@ fn resolve_elided_lifetimes_in_path(
                             let res =
                                 LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
                             for id in node_ids {
-                                self.record_lifetime_res(id, res);
+                                self.record_lifetime_res(id, res, LifetimeElisionCandidate::Named);
                             }
                             break;
                         }
                         LifetimeRibKind::AnonymousCreateParameter { .. }
+                        | LifetimeRibKind::Elided(_)
+                        | LifetimeRibKind::ElisionFailure
                         | LifetimeRibKind::Generics { .. }
                         | LifetimeRibKind::ConstGeneric
                         | LifetimeRibKind::AnonConst => {}
@@ -1640,6 +1688,16 @@ fn resolve_elided_lifetimes_in_path(
                 continue;
             }
 
+            let missing_lifetime = MissingLifetime {
+                id: node_ids.start,
+                span: elided_lifetime_span,
+                kind: if segment.has_generic_args {
+                    MissingLifetimeKind::Comma
+                } else {
+                    MissingLifetimeKind::Brackets
+                },
+                count: expected_lifetimes,
+            };
             let mut should_lint = true;
             for rib in self.lifetime_ribs.iter().rev() {
                 match rib.kind {
@@ -1670,23 +1728,60 @@ fn resolve_elided_lifetimes_in_path(
                         should_lint = false;
 
                         for id in node_ids {
-                            self.record_lifetime_res(id, LifetimeRes::Error);
+                            self.record_lifetime_res(
+                                id,
+                                LifetimeRes::Error,
+                                LifetimeElisionCandidate::Named,
+                            );
                         }
                         break;
                     }
                     // Do not create a parameter for patterns and expressions.
                     LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
+                        // Group all suggestions into the first record.
+                        let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
                         for id in node_ids {
                             let res = self.create_fresh_lifetime(id, ident, binder);
-                            self.record_lifetime_res(id, res);
+                            self.record_lifetime_res(
+                                id,
+                                res,
+                                replace(&mut candidate, LifetimeElisionCandidate::Named),
+                            );
                         }
                         break;
                     }
                     // `PassThrough` is the normal case.
-                    LifetimeRibKind::AnonymousPassThrough(binder, _) => {
+                    LifetimeRibKind::AnonymousPassThrough(binder) => {
                         let res = LifetimeRes::Anonymous { binder, elided: true };
+                        let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
                         for id in node_ids {
-                            self.record_lifetime_res(id, res);
+                            self.record_lifetime_res(
+                                id,
+                                res,
+                                replace(&mut candidate, LifetimeElisionCandidate::Ignore),
+                            );
+                        }
+                        break;
+                    }
+                    LifetimeRibKind::Elided(res) => {
+                        let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
+                        for id in node_ids {
+                            self.record_lifetime_res(
+                                id,
+                                res,
+                                replace(&mut candidate, LifetimeElisionCandidate::Ignore),
+                            );
+                        }
+                        break;
+                    }
+                    LifetimeRibKind::ElisionFailure => {
+                        self.diagnostic_metadata.current_elision_failures.push(missing_lifetime);
+                        for id in node_ids {
+                            self.record_lifetime_res(
+                                id,
+                                LifetimeRes::Error,
+                                LifetimeElisionCandidate::Ignore,
+                            );
                         }
                         break;
                     }
@@ -1695,13 +1790,14 @@ fn resolve_elided_lifetimes_in_path(
                     // we simply resolve to an implicit lifetime, which will be checked later, at
                     // which point a suitable error will be emitted.
                     LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => {
-                        // FIXME(cjgillot) This resolution is wrong, but this does not matter
-                        // since these cases are erroneous anyway.  Lifetime resolution should
-                        // emit a "missing lifetime specifier" diagnostic.
-                        let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true };
                         for id in node_ids {
-                            self.record_lifetime_res(id, res);
+                            self.record_lifetime_res(
+                                id,
+                                LifetimeRes::Error,
+                                LifetimeElisionCandidate::Ignore,
+                            );
                         }
+                        self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
                         break;
                     }
                     LifetimeRibKind::Generics { .. }
@@ -1728,13 +1824,223 @@ fn resolve_elided_lifetimes_in_path(
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
-    fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) {
+    fn record_lifetime_res(
+        &mut self,
+        id: NodeId,
+        res: LifetimeRes,
+        candidate: LifetimeElisionCandidate,
+    ) {
         if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
             panic!(
                 "lifetime {:?} resolved multiple times ({:?} before, {:?} now)",
                 id, prev_res, res
             )
         }
+        match res {
+            LifetimeRes::Param { .. }
+            | LifetimeRes::Fresh { .. }
+            | LifetimeRes::Anonymous { .. }
+            | LifetimeRes::Static => {
+                if let Some(ref mut candidates) = self.lifetime_elision_candidates {
+                    candidates.insert(res, candidate);
+                }
+            }
+            LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {}
+        }
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) {
+        if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
+            panic!(
+                "lifetime parameter {:?} resolved multiple times ({:?} before, {:?} now)",
+                id, prev_res, res
+            )
+        }
+    }
+
+    /// Perform resolution of a function signature, accounting for lifetime elision.
+    #[tracing::instrument(level = "debug", skip(self, inputs))]
+    fn resolve_fn_signature(
+        &mut self,
+        fn_id: NodeId,
+        async_node_id: Option<NodeId>,
+        has_self: bool,
+        inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)> + Clone,
+        output_ty: &'ast FnRetTy,
+    ) {
+        // Add each argument to the rib.
+        let parameter_rib = LifetimeRibKind::AnonymousCreateParameter {
+            binder: fn_id,
+            report_in_path: async_node_id.is_some(),
+        };
+        let elision_lifetime =
+            self.with_lifetime_rib(parameter_rib, |this| this.resolve_fn_params(has_self, inputs));
+        debug!(?elision_lifetime);
+
+        let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures);
+        let output_rib = if let Ok(res) = elision_lifetime.as_ref() {
+            LifetimeRibKind::Elided(*res)
+        } else {
+            LifetimeRibKind::ElisionFailure
+        };
+        self.with_lifetime_rib(output_rib, |this| visit::walk_fn_ret_ty(this, &output_ty));
+        let elision_failures =
+            replace(&mut self.diagnostic_metadata.current_elision_failures, outer_failures);
+        if !elision_failures.is_empty() {
+            let Err(failure_info) = elision_lifetime else { bug!() };
+            self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info));
+        }
+    }
+
+    /// Resolve inside function parameters and parameter types.
+    /// Returns the lifetime for elision in fn return type,
+    /// or diagnostic information in case of elision failure.
+    fn resolve_fn_params(
+        &mut self,
+        has_self: bool,
+        inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>,
+    ) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> {
+        let outer_candidates =
+            replace(&mut self.lifetime_elision_candidates, Some(Default::default()));
+
+        let mut elision_lifetime = None;
+        let mut lifetime_count = 0;
+        let mut parameter_info = Vec::new();
+
+        let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
+        for (index, (pat, ty)) in inputs.enumerate() {
+            debug!(?pat, ?ty);
+            if let Some(pat) = pat {
+                self.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
+            }
+            self.visit_ty(ty);
+
+            if let Some(ref candidates) = self.lifetime_elision_candidates {
+                let new_count = candidates.len();
+                let local_count = new_count - lifetime_count;
+                if local_count != 0 {
+                    parameter_info.push(ElisionFnParameter {
+                        index,
+                        ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind {
+                            Some(ident)
+                        } else {
+                            None
+                        },
+                        lifetime_count: local_count,
+                        span: ty.span,
+                    });
+                }
+                lifetime_count = new_count;
+            }
+
+            // Handle `self` specially.
+            if index == 0 && has_self {
+                let self_lifetime = self.find_lifetime_for_self(ty);
+                if let Set1::One(lifetime) = self_lifetime {
+                    elision_lifetime = Some(lifetime);
+                    self.lifetime_elision_candidates = None;
+                } else {
+                    self.lifetime_elision_candidates = Some(Default::default());
+                    lifetime_count = 0;
+                }
+            }
+            debug!("(resolving function / closure) recorded parameter");
+        }
+
+        let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates);
+        debug!(?all_candidates);
+
+        if let Some(res) = elision_lifetime {
+            return Ok(res);
+        }
+
+        // We do not have a `self` candidate, look at the full list.
+        let all_candidates = all_candidates.unwrap();
+        if all_candidates.len() == 1 {
+            Ok(*all_candidates.first().unwrap().0)
+        } else {
+            let all_candidates = all_candidates
+                .into_iter()
+                .filter_map(|(_, candidate)| match candidate {
+                    LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None,
+                    LifetimeElisionCandidate::Missing(missing) => Some(missing),
+                })
+                .collect();
+            Err((all_candidates, parameter_info))
+        }
+    }
+
+    /// List all the lifetimes that appear in the provided type.
+    fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1<LifetimeRes> {
+        struct SelfVisitor<'r, 'a> {
+            r: &'r Resolver<'a>,
+            impl_self: Option<Res>,
+            lifetime: Set1<LifetimeRes>,
+        }
+
+        impl SelfVisitor<'_, '_> {
+            // Look for `self: &'a Self` - also desugared from `&'a self`,
+            // and if that matches, use it for elision and return early.
+            fn is_self_ty(&self, ty: &Ty) -> bool {
+                match ty.kind {
+                    TyKind::ImplicitSelf => true,
+                    TyKind::Path(None, _) => {
+                        let path_res = self.r.partial_res_map[&ty.id].base_res();
+                        if let Res::SelfTy { .. } = path_res {
+                            return true;
+                        }
+                        Some(path_res) == self.impl_self
+                    }
+                    _ => false,
+                }
+            }
+        }
+
+        impl<'a> Visitor<'a> for SelfVisitor<'_, '_> {
+            fn visit_ty(&mut self, ty: &'a Ty) {
+                trace!("SelfVisitor considering ty={:?}", ty);
+                if let TyKind::Rptr(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) {
+                    let lt_id = if let Some(lt) = lt {
+                        lt.id
+                    } else {
+                        let res = self.r.lifetimes_res_map[&ty.id];
+                        let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() };
+                        start
+                    };
+                    let lt_res = self.r.lifetimes_res_map[&lt_id];
+                    trace!("SelfVisitor inserting res={:?}", lt_res);
+                    self.lifetime.insert(lt_res);
+                }
+                visit::walk_ty(self, ty)
+            }
+        }
+
+        let impl_self = self
+            .diagnostic_metadata
+            .current_self_type
+            .as_ref()
+            .and_then(|ty| {
+                if let TyKind::Path(None, _) = ty.kind {
+                    self.r.partial_res_map.get(&ty.id)
+                } else {
+                    None
+                }
+            })
+            .map(|res| res.base_res())
+            .filter(|res| {
+                // Permit the types that unambiguously always
+                // result in the same type constructor being used
+                // (it can't differ between `Self` and `self`).
+                matches!(
+                    res,
+                    Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_)
+                )
+            });
+        let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty };
+        visitor.visit_ty(ty);
+        trace!("SelfVisitor found={:?}", visitor.lifetime);
+        visitor.lifetime
     }
 
     /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
@@ -1959,22 +2265,29 @@ fn resolve_item(&mut self, item: &'ast Item) {
 
             ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
                 self.with_item_rib(|this| {
-                    this.visit_ty(ty);
-                    if let Some(expr) = expr {
-                        let constant_item_kind = match item.kind {
-                            ItemKind::Const(..) => ConstantItemKind::Const,
-                            ItemKind::Static(..) => ConstantItemKind::Static,
-                            _ => unreachable!(),
-                        };
-                        // We already forbid generic params because of the above item rib,
-                        // so it doesn't matter whether this is a trivial constant.
-                        this.with_constant_rib(
-                            IsRepeatExpr::No,
-                            HasGenericParams::Yes,
-                            Some((item.ident, constant_item_kind)),
-                            |this| this.visit_expr(expr),
-                        );
-                    }
+                    this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+                        this.visit_ty(ty);
+                    });
+                    this.with_lifetime_rib(
+                        LifetimeRibKind::AnonymousPassThrough(item.id),
+                        |this| {
+                            if let Some(expr) = expr {
+                                let constant_item_kind = match item.kind {
+                                    ItemKind::Const(..) => ConstantItemKind::Const,
+                                    ItemKind::Static(..) => ConstantItemKind::Static,
+                                    _ => unreachable!(),
+                                };
+                                // We already forbid generic params because of the above item rib,
+                                // so it doesn't matter whether this is a trivial constant.
+                                this.with_constant_rib(
+                                    IsRepeatExpr::No,
+                                    HasGenericParams::Yes,
+                                    Some((item.ident, constant_item_kind)),
+                                    |this| this.visit_expr(expr),
+                                );
+                            }
+                        },
+                    );
                 });
             }
 
@@ -2045,7 +2358,7 @@ fn with_generic_param_rib<'c, F>(
             {
                 diagnostics::signal_lifetime_shadowing(self.r.session, original, param.ident);
                 // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_res(param.id, LifetimeRes::Error);
+                self.record_lifetime_param(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -2056,7 +2369,7 @@ fn with_generic_param_rib<'c, F>(
                     self.report_error(param.ident.span, err);
                     if let GenericParamKind::Lifetime = param.kind {
                         // Record lifetime res, so lowering knows there is something fishy.
-                        self.record_lifetime_res(param.id, LifetimeRes::Error);
+                        self.record_lifetime_param(param.id, LifetimeRes::Error);
                         continue;
                     }
                 }
@@ -2075,7 +2388,7 @@ fn with_generic_param_rib<'c, F>(
                 .span_label(param.ident.span, "`'_` is a reserved lifetime name")
                 .emit();
                 // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_res(param.id, LifetimeRes::Error);
+                self.record_lifetime_param(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -2090,7 +2403,7 @@ fn with_generic_param_rib<'c, F>(
                 .span_label(param.ident.span, "'static is a reserved lifetime name")
                 .emit();
                 // Record lifetime res, so lowering knows there is something fishy.
-                self.record_lifetime_res(param.id, LifetimeRes::Error);
+                self.record_lifetime_param(param.id, LifetimeRes::Error);
                 continue;
             }
 
@@ -2102,7 +2415,7 @@ fn with_generic_param_rib<'c, F>(
                 GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam),
                 GenericParamKind::Lifetime => {
                     let res = LifetimeRes::Param { param: def_id, binder };
-                    self.record_lifetime_res(param.id, res);
+                    self.record_lifetime_param(param.id, res);
                     function_lifetime_rib.bindings.insert(ident, (param.id, res));
                     continue;
                 }
@@ -2125,7 +2438,14 @@ fn with_generic_param_rib<'c, F>(
 
         self.ribs[TypeNS].pop();
         self.ribs[ValueNS].pop();
-        self.lifetime_ribs.pop();
+        let function_lifetime_rib = self.lifetime_ribs.pop().unwrap();
+
+        // Do not account for the parameters we just bound for function lifetime elision.
+        if let Some(ref mut candidates) = self.lifetime_elision_candidates {
+            for (_, res) in function_lifetime_rib.bindings.values() {
+                candidates.remove(res);
+            }
+        }
 
         if let LifetimeBinderKind::BareFnType
         | LifetimeBinderKind::WhereBound
@@ -2223,20 +2543,26 @@ fn resolve_trait_items(&mut self, trait_items: &'ast [P<AssocItem>]) {
                         //
                         // Type parameters can already be used and as associated consts are
                         // not used as part of the type system, this is far less surprising.
-                        self.with_constant_rib(
-                            IsRepeatExpr::No,
-                            HasGenericParams::Yes,
-                            None,
-                            |this| this.visit_expr(expr),
+                        self.with_lifetime_rib(
+                            LifetimeRibKind::AnonymousPassThrough(item.id),
+                            |this| {
+                                this.with_constant_rib(
+                                    IsRepeatExpr::No,
+                                    HasGenericParams::Yes,
+                                    None,
+                                    |this| this.visit_expr(expr),
+                                )
+                            },
                         );
                     }
                 }
                 AssocItemKind::Fn(box Fn { generics, .. }) => {
                     walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
                 }
-                AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
-                    walk_assoc_item(self, generics, LifetimeBinderKind::Item, item);
-                }
+                AssocItemKind::TyAlias(box TyAlias { generics, .. }) => self
+                    .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
+                        walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
+                    }),
                 AssocItemKind::MacCall(_) => {
                     panic!("unexpanded macro in resolve!")
                 }
@@ -2307,7 +2633,7 @@ fn resolve_implementation(
             LifetimeRibKind::Generics {
                 span: generics.span,
                 binder: item_id,
-                kind: LifetimeBinderKind::ImplBlock
+                kind: LifetimeBinderKind::ImplBlock,
             },
             |this| {
                 // Dummy self type for better errors if `Self` is used in the trait path.
@@ -2327,7 +2653,11 @@ fn resolve_implementation(
 
                                     // 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);
+                                        this.r
+                                            .trait_impls
+                                            .entry(trait_id)
+                                            .or_default()
+                                            .push(item_def_id);
                                     }
 
                                     let item_def_id = item_def_id.to_def_id();
@@ -2346,21 +2676,17 @@ fn resolve_implementation(
                                         this.visit_generics(generics);
 
                                         // Resolve the items within the impl.
-                                        this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false),
-                                            |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 {
-                                                            this.resolve_impl_item(&**item);
-                                                        }
-                                                    });
-                                                });
-                                            },
-                                        );
+                                        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 {
+                                                    this.resolve_impl_item(&**item);
+                                                }
+                                            });
+                                        });
                                     });
                                 },
-                            );
+                            )
                         },
                     );
                 });
@@ -2391,9 +2717,17 @@ fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
                     //
                     // Type parameters can already be used and as associated consts are
                     // not used as part of the type system, this is far less surprising.
-                    self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
-                        this.visit_expr(expr)
-                    });
+                    self.with_lifetime_rib(
+                        LifetimeRibKind::AnonymousPassThrough(item.id),
+                        |this| {
+                            this.with_constant_rib(
+                                IsRepeatExpr::No,
+                                HasGenericParams::Yes,
+                                None,
+                                |this| this.visit_expr(expr),
+                            )
+                        },
+                    );
                 }
             }
             AssocItemKind::Fn(box Fn { generics, .. }) => {
@@ -2435,18 +2769,20 @@ fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
                         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),
-                        );
+                        this.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |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)
+                            visit::walk_assoc_item(this, item, AssocCtxt::Impl)
+                        });
                     },
                 );
             }
@@ -3581,7 +3917,9 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
             ExprKind::Repeat(ref elem, ref ct) => {
                 self.visit_expr(elem);
                 self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
-                    this.resolve_anon_const(ct, IsRepeatExpr::Yes)
+                    this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
+                        this.resolve_anon_const(ct, IsRepeatExpr::Yes)
+                    })
                 });
             }
             ExprKind::ConstBlock(ref ct) => {
index e428bae479bc2f4d70258cfd172203db8502acde..6b49c6b1ac63eeaeb66086678a5c6e06d302791e 100644 (file)
@@ -1,7 +1,6 @@
 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
-use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
-use crate::late::{LifetimeBinderKind, LifetimeRibKind, LifetimeUseSet};
+use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
 use crate::path_names_to_string;
 use crate::{Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
@@ -9,10 +8,10 @@
 use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt};
 use rustc_ast::{
     self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind,
-    NodeId, Path, Ty, TyKind,
+    NodeId, Path, Ty, TyKind, DUMMY_NODE_ID,
 };
 use rustc_ast_pretty::pprust::path_segment_to_string;
-use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
     MultiSpan,
@@ -20,7 +19,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, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
@@ -29,7 +28,7 @@
 use rustc_span::hygiene::MacroKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, Span};
 
 use std::iter;
 use std::ops::Deref;
@@ -59,45 +58,6 @@ fn action(&self) -> &'static str {
     }
 }
 
-pub(crate) enum MissingLifetimeSpot<'tcx> {
-    Generics(&'tcx hir::Generics<'tcx>),
-    HigherRanked { span: Span, span_type: ForLifetimeSpanType },
-    Static,
-}
-
-pub(crate) enum ForLifetimeSpanType {
-    BoundEmpty,
-    BoundTail,
-    TypeEmpty,
-    TypeTail,
-    ClosureEmpty,
-    ClosureTail,
-}
-
-impl ForLifetimeSpanType {
-    pub(crate) fn descr(&self) -> &'static str {
-        match self {
-            Self::BoundEmpty | Self::BoundTail => "bound",
-            Self::TypeEmpty | Self::TypeTail => "type",
-            Self::ClosureEmpty | Self::ClosureTail => "closure",
-        }
-    }
-
-    pub(crate) fn suggestion(&self, sugg: impl std::fmt::Display) -> String {
-        match self {
-            Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg),
-            Self::ClosureEmpty => format!("for<{}>", sugg),
-            Self::BoundTail | Self::TypeTail | Self::ClosureTail => format!(", {}", sugg),
-        }
-    }
-}
-
-impl<'tcx> Into<MissingLifetimeSpot<'tcx>> for &&'tcx hir::Generics<'tcx> {
-    fn into(self) -> MissingLifetimeSpot<'tcx> {
-        MissingLifetimeSpot::Generics(self)
-    }
-}
-
 fn is_self_type(path: &[Segment], namespace: Namespace) -> bool {
     namespace == TypeNS && path.len() == 1 && path[0].ident.name == kw::SelfUpper
 }
@@ -122,6 +82,56 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
     (variant_path_string, enum_path_string)
 }
 
+/// Description of an elided lifetime.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub(super) struct MissingLifetime {
+    /// Used to overwrite the resolution with the suggestion, to avoid cascasing errors.
+    pub id: NodeId,
+    /// Where to suggest adding the lifetime.
+    pub span: Span,
+    /// How the lifetime was introduced, to have the correct space and comma.
+    pub kind: MissingLifetimeKind,
+    /// Number of elided lifetimes, used for elision in path.
+    pub count: usize,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub(super) enum MissingLifetimeKind {
+    /// An explicit `'_`.
+    Underscore,
+    /// An elided lifetime `&' ty`.
+    Ampersand,
+    /// An elided lifetime in brackets with written brackets.
+    Comma,
+    /// An elided lifetime with elided brackets.
+    Brackets,
+}
+
+/// Description of the lifetimes appearing in a function parameter.
+/// This is used to provide a literal explanation to the elision failure.
+#[derive(Clone, Debug)]
+pub(super) struct ElisionFnParameter {
+    /// The index of the argument in the original definition.
+    pub index: usize,
+    /// The name of the argument if it's a simple ident.
+    pub ident: Option<Ident>,
+    /// The number of lifetimes in the parameter.
+    pub lifetime_count: usize,
+    /// The span of the parameter.
+    pub span: Span,
+}
+
+/// Description of lifetimes that appear as candidates for elision.
+/// This is used to suggest introducing an explicit lifetime.
+#[derive(Debug)]
+pub(super) enum LifetimeElisionCandidate {
+    /// This is not a real lifetime.
+    Ignore,
+    /// There is a named lifetime, we won't suggest anything.
+    Named,
+    Missing(MissingLifetime),
+}
+
 impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
     fn def_span(&self, def_id: DefId) -> Option<Span> {
         match def_id.krate {
@@ -1434,7 +1444,7 @@ fn lookup_typo_candidate(
                     // Items from this module
                     self.r.add_module_candidates(module, &mut names, &filter_fn);
 
-                    if let ModuleKind::Block(..) = module.kind {
+                    if let ModuleKind::Block = module.kind {
                         // We can see through blocks
                     } else {
                         // Items from the prelude
@@ -2003,18 +2013,35 @@ pub(crate) fn emit_undeclared_lifetime_error(
             err.span_label(lifetime_ref.ident.span, "undeclared lifetime");
             err
         };
-        let mut suggest_note = true;
+        self.suggest_introducing_lifetime(
+            &mut err,
+            Some(lifetime_ref.ident.name.as_str()),
+            |err, _, span, message, suggestion| {
+                err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
+                true
+            },
+        );
+        err.emit();
+    }
 
+    fn suggest_introducing_lifetime(
+        &self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        name: Option<&str>,
+        suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool,
+    ) {
+        let mut suggest_note = true;
         for rib in self.lifetime_ribs.iter().rev() {
+            let mut should_continue = true;
             match rib.kind {
                 LifetimeRibKind::Generics { binder: _, span, kind } => {
-                    if !span.can_be_used_for_suggestions() && suggest_note {
+                    if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
                         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,
+                                name,
                             ),
                         );
                         continue;
@@ -2030,46 +2057,42 @@ pub(crate) fn emit_undeclared_lifetime_error(
                         let sugg = format!(
                             "{}<{}>{}",
                             if higher_ranked { "for" } else { "" },
-                            lifetime_ref.ident,
+                            name.unwrap_or("'a"),
                             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);
+                        let sugg = format!("{}, ", name.unwrap_or("'a"));
                         (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,
+                        let message = format!(
+                            "consider making the {} lifetime-generic with a new `{}` lifetime",
+                            kind.descr(),
+                            name.unwrap_or("'a"),
                         );
+                        should_continue = suggest(err, true, span, &message, sugg);
                         err.note_once(
                             "for more information on higher-ranked polymorphism, visit \
                              https://doc.rust-lang.org/nomicon/hrtb.html",
                         );
+                    } else if let Some(name) = name {
+                        let message = format!("consider introducing lifetime `{}` here", name);
+                        should_continue = suggest(err, false, span, &message, sugg);
                     } else {
-                        err.span_suggestion(
-                            span,
-                            &format!("consider introducing lifetime `{}` here", lifetime_ref.ident),
-                            sugg,
-                            Applicability::MaybeIncorrect,
-                        );
+                        let message = format!("consider introducing a named lifetime parameter");
+                        should_continue = suggest(err, false, span, &message, sugg);
                     }
                 }
                 LifetimeRibKind::Item => break,
                 _ => {}
             }
+            if !should_continue {
+                break;
+            }
         }
-
-        err.emit();
     }
 
     pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
@@ -2105,552 +2128,209 @@ pub(crate) fn maybe_emit_forbidden_non_static_lifetime_error(
             .emit();
         }
     }
-}
 
-/// Report lifetime/lifetime shadowing as an error.
-pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
-    let mut err = struct_span_err!(
-        sess,
-        shadower.span,
-        E0496,
-        "lifetime name `{}` shadows a lifetime name that is already in scope",
-        orig.name,
-    );
-    err.span_label(orig.span, "first declared here");
-    err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
-    err.emit();
-}
-
-/// Shadowing involving a label is only a warning for historical reasons.
-//FIXME: make this a proper lint.
-pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
-    let name = shadower.name;
-    let shadower = shadower.span;
-    let mut err = sess.struct_span_warn(
-        shadower,
-        &format!("label name `{}` shadows a label name that is already in scope", name),
-    );
-    err.span_label(orig, "first declared here");
-    err.span_label(shadower, format!("label `{}` already in scope", name));
-    err.emit();
-}
-
-impl<'tcx> LifetimeContext<'_, 'tcx> {
     pub(crate) fn report_missing_lifetime_specifiers(
-        &self,
-        spans: Vec<Span>,
-        count: usize,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        struct_span_err!(
-            self.tcx.sess,
+        &mut self,
+        lifetime_refs: Vec<MissingLifetime>,
+        function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
+    ) -> ErrorGuaranteed {
+        let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum();
+        let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
+
+        let mut err = struct_span_err!(
+            self.r.session,
             spans,
             E0106,
             "missing lifetime specifier{}",
-            pluralize!(count)
-        )
+            pluralize!(num_lifetimes)
+        );
+        self.add_missing_lifetime_specifiers_label(
+            &mut err,
+            lifetime_refs,
+            function_param_lifetimes,
+        );
+        err.emit()
     }
 
-    /// Returns whether to add `'static` lifetime to the suggested lifetime list.
-    pub(crate) fn report_elision_failure(
-        &self,
-        diag: &mut Diagnostic,
-        params: &[ElisionFailureInfo],
-    ) -> bool {
-        let mut m = String::new();
-        let len = params.len();
+    pub(crate) fn add_missing_lifetime_specifiers_label(
+        &mut self,
+        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        lifetime_refs: Vec<MissingLifetime>,
+        function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
+    ) {
+        for &lt in &lifetime_refs {
+            err.span_label(
+                lt.span,
+                format!(
+                    "expected {} lifetime parameter{}",
+                    if lt.count == 1 { "named".to_string() } else { lt.count.to_string() },
+                    pluralize!(lt.count),
+                ),
+            );
+        }
 
-        let elided_params: Vec<_> =
-            params.iter().cloned().filter(|info| info.lifetime_count > 0).collect();
+        let mut in_scope_lifetimes: Vec<_> = self
+            .lifetime_ribs
+            .iter()
+            .rev()
+            .take_while(|rib| !matches!(rib.kind, LifetimeRibKind::Item))
+            .flat_map(|rib| rib.bindings.iter())
+            .map(|(&ident, &res)| (ident, res))
+            .filter(|(ident, _)| ident.name != kw::UnderscoreLifetime)
+            .collect();
+        debug!(?in_scope_lifetimes);
 
-        let elided_len = elided_params.len();
+        debug!(?function_param_lifetimes);
+        if let Some((param_lifetimes, params)) = &function_param_lifetimes {
+            let elided_len = param_lifetimes.len();
+            let num_params = params.len();
 
-        for (i, info) in elided_params.into_iter().enumerate() {
-            let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
-                info;
+            let mut m = String::new();
 
-            diag.span_label(span, "");
-            let help_name = if let Some(ident) =
-                parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
-            {
-                format!("`{}`", ident)
-            } else {
-                format!("argument {}", index + 1)
-            };
+            for (i, info) in params.iter().enumerate() {
+                let ElisionFnParameter { ident, index, lifetime_count, span } = *info;
+                debug_assert_ne!(lifetime_count, 0);
 
-            m.push_str(
-                &(if n == 1 {
-                    help_name
+                err.span_label(span, "");
+
+                if i != 0 {
+                    if i + 1 < num_params {
+                        m.push_str(", ");
+                    } else if num_params == 2 {
+                        m.push_str(" or ");
+                    } else {
+                        m.push_str(", or ");
+                    }
+                }
+
+                let help_name = if let Some(ident) = ident {
+                    format!("`{}`", ident)
                 } else {
-                    format!(
-                        "one of {}'s {} {}lifetimes",
-                        help_name,
-                        n,
-                        if have_bound_regions { "free " } else { "" }
-                    )
-                })[..],
-            );
+                    format!("argument {}", index + 1)
+                };
 
-            if elided_len == 2 && i == 0 {
-                m.push_str(" or ");
-            } else if i + 2 == elided_len {
-                m.push_str(", or ");
-            } else if i != elided_len - 1 {
-                m.push_str(", ");
+                if lifetime_count == 1 {
+                    m.push_str(&help_name[..])
+                } else {
+                    m.push_str(&format!("one of {}'s {} lifetimes", help_name, lifetime_count)[..])
+                }
             }
-        }
 
-        if len == 0 {
-            diag.help(
-                "this function's return type contains a borrowed value, \
+            if num_params == 0 {
+                err.help(
+                    "this function's return type contains a borrowed value, \
                  but there is no value for it to be borrowed from",
-            );
-            true
-        } else if elided_len == 0 {
-            diag.help(
-                "this function's return type contains a borrowed value with \
+                );
+                if in_scope_lifetimes.is_empty() {
+                    in_scope_lifetimes = vec![(
+                        Ident::with_dummy_span(kw::StaticLifetime),
+                        (DUMMY_NODE_ID, LifetimeRes::Static),
+                    )];
+                }
+            } else if elided_len == 0 {
+                err.help(
+                    "this function's return type contains a borrowed value with \
                  an elided lifetime, but the lifetime cannot be derived from \
                  the arguments",
-            );
-            true
-        } else if elided_len == 1 {
-            diag.help(&format!(
-                "this function's return type contains a borrowed value, \
+                );
+                if in_scope_lifetimes.is_empty() {
+                    in_scope_lifetimes = vec![(
+                        Ident::with_dummy_span(kw::StaticLifetime),
+                        (DUMMY_NODE_ID, LifetimeRes::Static),
+                    )];
+                }
+            } else if num_params == 1 {
+                err.help(&format!(
+                    "this function's return type contains a borrowed value, \
                  but the signature does not say which {} it is borrowed from",
-                m
-            ));
-            false
-        } else {
-            diag.help(&format!(
-                "this function's return type contains a borrowed value, \
+                    m
+                ));
+            } else {
+                err.help(&format!(
+                    "this function's return type contains a borrowed value, \
                  but the signature does not say whether it is borrowed from {}",
-                m
-            ));
-            false
+                    m
+                ));
+            }
         }
-    }
 
-    pub(crate) fn is_trait_ref_fn_scope(
-        &mut self,
-        trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
-    ) -> bool {
-        if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
-            if [
-                self.tcx.lang_items().fn_once_trait(),
-                self.tcx.lang_items().fn_trait(),
-                self.tcx.lang_items().fn_mut_trait(),
-            ]
-            .contains(&Some(did))
-            {
-                let (span, span_type) = if let Some(bound) =
-                    trait_ref.bound_generic_params.iter().rfind(|param| {
-                        matches!(
-                            param.kind,
-                            hir::GenericParamKind::Lifetime {
-                                kind: hir::LifetimeParamKind::Explicit
-                            }
-                        )
-                    }) {
-                    (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail)
-                } else {
-                    (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty)
-                };
-                self.missing_named_lifetime_spots
-                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
-                return true;
-            }
+        let existing_name = match &in_scope_lifetimes[..] {
+            [] => Symbol::intern("'a"),
+            [(existing, _)] => existing.name,
+            _ => Symbol::intern("'lifetime"),
         };
-        false
-    }
-
-    pub(crate) fn add_missing_lifetime_specifiers_label(
-        &self,
-        err: &mut Diagnostic,
-        mut spans_with_counts: Vec<(Span, usize)>,
-        in_scope_lifetimes: FxIndexSet<LocalDefId>,
-        params: Option<&[ElisionFailureInfo]>,
-    ) {
-        let (mut lifetime_names, lifetime_spans): (FxHashSet<_>, Vec<_>) = in_scope_lifetimes
-            .iter()
-            .filter_map(|def_id| {
-                let name = self.tcx.item_name(def_id.to_def_id());
-                let span = self.tcx.def_ident_span(def_id.to_def_id())?;
-                Some((name, span))
-            })
-            .filter(|&(n, _)| n != kw::UnderscoreLifetime)
-            .unzip();
 
-        if let Some(params) = params {
-            // If there's no lifetime available, suggest `'static`.
-            if self.report_elision_failure(err, params) && lifetime_names.is_empty() {
-                lifetime_names.insert(kw::StaticLifetime);
+        let mut spans_suggs: Vec<_> = Vec::new();
+        let build_sugg = |lt: MissingLifetime| match lt.kind {
+            MissingLifetimeKind::Underscore => {
+                debug_assert_eq!(lt.count, 1);
+                (lt.span, existing_name.to_string())
             }
-        }
-        let params = params.unwrap_or(&[]);
-
-        let snippets: Vec<Option<String>> = spans_with_counts
-            .iter()
-            .map(|(span, _)| self.tcx.sess.source_map().span_to_snippet(*span).ok())
-            .collect();
-
-        // Empty generics are marked with a span of "<", but since from now on
-        // that information is in the snippets it can be removed from the spans.
-        for ((span, _), snippet) in spans_with_counts.iter_mut().zip(&snippets) {
-            if snippet.as_deref() == Some("<") {
-                *span = span.shrink_to_hi();
+            MissingLifetimeKind::Ampersand => {
+                debug_assert_eq!(lt.count, 1);
+                (lt.span.shrink_to_hi(), format!("{} ", existing_name))
             }
+            MissingLifetimeKind::Comma => {
+                let sugg: String = std::iter::repeat([existing_name.as_str(), ", "])
+                    .take(lt.count)
+                    .flatten()
+                    .collect();
+                (lt.span.shrink_to_hi(), sugg)
+            }
+            MissingLifetimeKind::Brackets => {
+                let sugg: String = std::iter::once("<")
+                    .chain(
+                        std::iter::repeat(existing_name.as_str()).take(lt.count).intersperse(", "),
+                    )
+                    .chain([">"])
+                    .collect();
+                (lt.span.shrink_to_hi(), sugg)
+            }
+        };
+        for &lt in &lifetime_refs {
+            spans_suggs.push(build_sugg(lt));
         }
-
-        for &(span, count) in &spans_with_counts {
-            err.span_label(
-                span,
-                format!(
-                    "expected {} lifetime parameter{}",
-                    if count == 1 { "named".to_string() } else { count.to_string() },
-                    pluralize!(count),
-                ),
-            );
-        }
-
-        let suggest_existing =
-            |err: &mut Diagnostic,
-             name: Symbol,
-             formatters: Vec<Option<Box<dyn Fn(Symbol) -> String>>>| {
-                if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
-                    self.missing_named_lifetime_spots.iter().rev().next()
-                {
-                    // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest
-                    // using `'a`, but also introduce the concept of HRLTs by suggesting
-                    // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404)
-                    let mut introduce_suggestion = vec![];
-
-                    let a_to_z_repeat_n = |n| {
-                        (b'a'..=b'z').map(move |c| {
-                            let mut s = '\''.to_string();
-                            s.extend(std::iter::repeat(char::from(c)).take(n));
-                            s
-                        })
-                    };
-
-                    // If all single char lifetime names are present, we wrap around and double the chars.
-                    let lt_name = (1..)
-                        .flat_map(a_to_z_repeat_n)
-                        .map(|lt| Symbol::intern(&lt))
-                        .find(|lt| !lifetime_names.contains(lt))
-                        .unwrap();
-                    let msg = format!(
-                        "consider making the {} lifetime-generic with a new `{}` lifetime",
-                        span_type.descr(),
-                        lt_name,
-                    );
-                    err.note(
-                        "for more information on higher-ranked polymorphism, visit \
-                    https://doc.rust-lang.org/nomicon/hrtb.html",
-                    );
-                    let for_sugg = span_type.suggestion(&lt_name);
-                    for param in params {
-                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
-                        {
-                            if snippet.starts_with('&') && !snippet.starts_with("&'") {
-                                introduce_suggestion
-                                    .push((param.span, format!("&{} {}", lt_name, &snippet[1..])));
-                            } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
-                                introduce_suggestion
-                                    .push((param.span, format!("&{} {}", lt_name, stripped)));
-                            }
-                        }
+        debug!(?spans_suggs);
+        match in_scope_lifetimes.len() {
+            0 => {
+                if let Some((param_lifetimes, _)) = function_param_lifetimes {
+                    for lt in param_lifetimes {
+                        spans_suggs.push(build_sugg(lt))
                     }
-                    introduce_suggestion.push((*for_span, for_sugg));
-                    for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) {
-                        if let Some(formatter) = formatter {
-                            introduce_suggestion.push((*span, formatter(lt_name)));
-                        }
-                    }
-                    err.multipart_suggestion_verbose(
-                        &msg,
-                        introduce_suggestion,
-                        Applicability::MaybeIncorrect,
-                    );
                 }
-
-                let spans_suggs: Vec<_> = formatters
-                    .into_iter()
-                    .zip(spans_with_counts.iter())
-                    .filter_map(|(formatter, (span, _))| {
-                        if let Some(formatter) = formatter {
-                            Some((*span, formatter(name)))
-                        } else {
-                            None
-                        }
-                    })
-                    .collect();
-                if spans_suggs.is_empty() {
-                    // If all the spans come from macros, we cannot extract snippets and then
-                    // `formatters` only contains None and `spans_suggs` is empty.
-                    return;
-                }
-                err.multipart_suggestion_verbose(
-                    &format!(
-                        "consider using the `{}` lifetime",
-                        lifetime_names.iter().next().unwrap()
-                    ),
-                    spans_suggs,
-                    Applicability::MaybeIncorrect,
-                );
-            };
-        let suggest_new = |err: &mut Diagnostic, suggs: Vec<Option<String>>| {
-            for missing in self.missing_named_lifetime_spots.iter().rev() {
-                let mut introduce_suggestion = vec![];
-                let msg;
-                let should_break;
-                introduce_suggestion.push(match missing {
-                    MissingLifetimeSpot::Generics(generics) => {
-                        if generics.span == DUMMY_SP {
-                            // Account for malformed generics in the HIR. This shouldn't happen,
-                            // but if we make a mistake elsewhere, mainly by keeping something in
-                            // `missing_named_lifetime_spots` that we shouldn't, like associated
-                            // `const`s or making a mistake in the AST lowering we would provide
-                            // nonsensical suggestions. Guard against that by skipping these.
-                            // (#74264)
-                            continue;
-                        }
-                        msg = "consider introducing a named lifetime parameter".to_string();
-                        should_break = true;
-                        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(), "'a, ".to_string())
-                        } else {
-                            (generics.span, "<'a>".to_string())
-                        }
-                    }
-                    MissingLifetimeSpot::HigherRanked { span, span_type } => {
-                        msg = format!(
-                            "consider making the {} lifetime-generic with a new `'a` lifetime",
-                            span_type.descr(),
-                        );
-                        should_break = false;
-                        err.note(
-                            "for more information on higher-ranked polymorphism, visit \
-                            https://doc.rust-lang.org/nomicon/hrtb.html",
-                        );
-                        (*span, span_type.suggestion("'a"))
-                    }
-                    MissingLifetimeSpot::Static => {
-                        let mut spans_suggs = Vec::new();
-                        for ((span, count), snippet) in
-                            spans_with_counts.iter().copied().zip(snippets.iter())
-                        {
-                            let (span, sugg) = match snippet.as_deref() {
-                                Some("&") => (span.shrink_to_hi(), "'static ".to_owned()),
-                                Some("'_") => (span, "'static".to_owned()),
-                                Some(snippet) if !snippet.ends_with('>') => {
-                                    if snippet == "" {
-                                        (
-                                            span,
-                                            std::iter::repeat("'static")
-                                                .take(count)
-                                                .collect::<Vec<_>>()
-                                                .join(", "),
-                                        )
-                                    } else if snippet == "<" || snippet == "(" {
-                                        (
-                                            span.shrink_to_hi(),
-                                            std::iter::repeat("'static")
-                                                .take(count)
-                                                .collect::<Vec<_>>()
-                                                .join(", "),
-                                        )
-                                    } else {
-                                        (
-                                            span.shrink_to_hi(),
-                                            format!(
-                                                "<{}>",
-                                                std::iter::repeat("'static")
-                                                    .take(count)
-                                                    .collect::<Vec<_>>()
-                                                    .join(", "),
-                                            ),
-                                        )
-                                    }
-                                }
-                                _ => continue,
-                            };
-                            spans_suggs.push((span, sugg.to_string()));
-                        }
+                self.suggest_introducing_lifetime(
+                    err,
+                    None,
+                    |err, higher_ranked, span, message, intro_sugg| {
                         err.multipart_suggestion_verbose(
-                            "consider using the `'static` lifetime",
-                            spans_suggs,
+                            message,
+                            std::iter::once((span, intro_sugg))
+                                .chain(spans_suggs.clone())
+                                .collect(),
                             Applicability::MaybeIncorrect,
                         );
-                        continue;
-                    }
-                });
-
-                struct Lifetime(Span, String);
-                impl Lifetime {
-                    fn is_unnamed(&self) -> bool {
-                        self.1.starts_with('&') && !self.1.starts_with("&'")
-                    }
-                    fn is_underscore(&self) -> bool {
-                        self.1.starts_with("&'_ ")
-                    }
-                    fn is_named(&self) -> bool {
-                        self.1.starts_with("&'")
-                    }
-                    fn suggestion(&self, sugg: String) -> Option<(Span, String)> {
-                        Some(
-                            match (
-                                self.is_unnamed(),
-                                self.is_underscore(),
-                                self.is_named(),
-                                sugg.starts_with('&'),
-                            ) {
-                                (true, _, _, false) => (self.span_unnamed_borrow(), sugg),
-                                (true, _, _, true) => {
-                                    (self.span_unnamed_borrow(), sugg[1..].to_string())
-                                }
-                                (_, true, _, false) => {
-                                    (self.span_underscore_borrow(), sugg.trim().to_string())
-                                }
-                                (_, true, _, true) => {
-                                    (self.span_underscore_borrow(), sugg[1..].trim().to_string())
-                                }
-                                (_, _, true, false) => {
-                                    (self.span_named_borrow(), sugg.trim().to_string())
-                                }
-                                (_, _, true, true) => {
-                                    (self.span_named_borrow(), sugg[1..].trim().to_string())
-                                }
-                                _ => return None,
-                            },
-                        )
-                    }
-                    fn span_unnamed_borrow(&self) -> Span {
-                        let lo = self.0.lo() + BytePos(1);
-                        self.0.with_lo(lo).with_hi(lo)
-                    }
-                    fn span_named_borrow(&self) -> Span {
-                        let lo = self.0.lo() + BytePos(1);
-                        self.0.with_lo(lo)
-                    }
-                    fn span_underscore_borrow(&self) -> Span {
-                        let lo = self.0.lo() + BytePos(1);
-                        let hi = lo + BytePos(2);
-                        self.0.with_lo(lo).with_hi(hi)
-                    }
-                }
-
-                for param in params {
-                    if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
-                        if let Some((span, sugg)) =
-                            Lifetime(param.span, snippet).suggestion("'a ".to_string())
-                        {
-                            introduce_suggestion.push((span, sugg));
-                        }
-                    }
-                }
-                for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map(
-                    |((span, _), sugg)| match &sugg {
-                        Some(sugg) => Some((span, sugg.to_string())),
-                        _ => None,
+                        higher_ranked
                     },
-                ) {
-                    let (span, sugg) = self
-                        .tcx
-                        .sess
-                        .source_map()
-                        .span_to_snippet(span)
-                        .ok()
-                        .and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone()))
-                        .unwrap_or((span, sugg));
-                    introduce_suggestion.push((span, sugg.to_string()));
-                }
+                );
+            }
+            1 => {
                 err.multipart_suggestion_verbose(
-                    &msg,
-                    introduce_suggestion,
+                    &format!("consider using the `{}` lifetime", existing_name),
+                    spans_suggs,
                     Applicability::MaybeIncorrect,
                 );
-                if should_break {
-                    break;
-                }
-            }
-        };
 
-        let lifetime_names: Vec<_> = lifetime_names.iter().collect();
-        match &lifetime_names[..] {
-            [name] => {
-                let mut suggs: Vec<Option<Box<dyn Fn(Symbol) -> String>>> = Vec::new();
-                for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied())
-                {
-                    suggs.push(match snippet.as_deref() {
-                        Some("&") => Some(Box::new(|name| format!("&{} ", name))),
-                        Some("'_") => Some(Box::new(|n| n.to_string())),
-                        Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))),
-                        Some("<") => Some(Box::new(move |n| {
-                            std::iter::repeat(n)
-                                .take(count)
-                                .map(|n| n.to_string())
-                                .collect::<Vec<_>>()
-                                .join(", ")
-                        })),
-                        Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| {
-                            format!(
-                                "{}<{}>",
-                                snippet,
-                                std::iter::repeat(name.to_string())
-                                    .take(count)
-                                    .collect::<Vec<_>>()
-                                    .join(", ")
-                            )
-                        })),
-                        _ => None,
-                    });
+                // Record as using the suggested resolution.
+                let (_, (_, res)) = in_scope_lifetimes[0];
+                for &lt in &lifetime_refs {
+                    self.r.lifetimes_res_map.insert(lt.id, res);
                 }
-                suggest_existing(err, **name, suggs);
             }
-            [] => {
-                let mut suggs = Vec::new();
-                for (snippet, (_, count)) in
-                    snippets.iter().cloned().zip(spans_with_counts.iter().copied())
-                {
-                    suggs.push(match snippet.as_deref() {
-                        Some("&") => Some("&'a ".to_string()),
-                        Some("'_") => Some("'a".to_string()),
-                        Some("") => {
-                            Some(std::iter::repeat("'a, ").take(count).collect::<Vec<_>>().join(""))
-                        }
-                        Some("<") => {
-                            Some(std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "))
-                        }
-                        Some(snippet) => Some(format!(
-                            "{}<{}>",
-                            snippet,
-                            std::iter::repeat("'a").take(count).collect::<Vec<_>>().join(", "),
-                        )),
-                        None => None,
-                    });
-                }
-                suggest_new(err, suggs);
-            }
-            lts if lts.len() > 1 => {
+            _ => {
+                let lifetime_spans: Vec<_> =
+                    in_scope_lifetimes.iter().map(|(ident, _)| ident.span).collect();
                 err.span_note(lifetime_spans, "these named lifetimes are available to use");
 
-                let mut spans_suggs: Vec<_> = Vec::new();
-                for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) {
-                    match snippet.as_deref() {
-                        Some("") => spans_suggs.push((span, "'lifetime, ".to_string())),
-                        Some("&") => spans_suggs
-                            .push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())),
-                        _ => {}
-                    }
-                }
-
                 if spans_suggs.len() > 0 {
                     // This happens when we have `Foo<T>` where we point at the space before `T`,
                     // but this can be confusing so we give a suggestion with placeholders.
@@ -2661,7 +2341,34 @@ fn span_underscore_borrow(&self) -> Span {
                     );
                 }
             }
-            _ => unreachable!(),
         }
     }
 }
+
+/// Report lifetime/lifetime shadowing as an error.
+pub fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
+    let mut err = struct_span_err!(
+        sess,
+        shadower.span,
+        E0496,
+        "lifetime name `{}` shadows a lifetime name that is already in scope",
+        orig.name,
+    );
+    err.span_label(orig.span, "first declared here");
+    err.span_label(shadower.span, format!("lifetime `{}` already in scope", orig.name));
+    err.emit();
+}
+
+/// Shadowing involving a label is only a warning for historical reasons.
+//FIXME: make this a proper lint.
+pub fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
+    let name = shadower.name;
+    let shadower = shadower.span;
+    let mut err = sess.struct_span_warn(
+        shadower,
+        &format!("label name `{}` shadows a label name that is already in scope", name),
+    );
+    err.span_label(orig, "first declared here");
+    err.span_label(shadower, format!("label `{}` already in scope", name));
+    err.emit();
+}
index 0eb11cd3e9fad9cafac6b21a4c54eb0bbe5e3436..a7fd7c427c759402444e127ccec7648c2a7bafc2 100644 (file)
@@ -1,12 +1,12 @@
 // ignore-tidy-filelength
-//! Name resolution for lifetimes.
+//! Resolution of early vs late bound lifetimes.
 //!
-//! Name resolution for lifetimes follows *much* simpler rules than the
-//! full resolve. For example, lifetime names are never exported or
-//! used between functions, and they operate in a purely top-down
-//! way. Therefore, we break lifetime name resolution into a separate pass.
+//! Name resolution for lifetimes is performed on the AST and embedded into HIR.  From this
+//! information, typechecking needs to transform the lifetime parameters into bound lifetimes.
+//! Lifetimes can be early-bound or late-bound.  Construction of typechecking terms needs to visit
+//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices.  This file
+//! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
 
-use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
 use rustc_ast::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::struct_span_err;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
-use rustc_hir::{GenericParamKind, HirIdMap, LifetimeParamKind};
+use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
+use rustc_middle::bug;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
 use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
-use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
@@ -152,10 +151,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> {
 
     /// Cache for cross-crate per-definition object lifetime defaults.
     xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
-
-    /// When encountering an undefined named lifetime, we will suggest introducing it in these
-    /// places.
-    pub(crate) missing_named_lifetime_spots: Vec<MissingLifetimeSpot<'tcx>>,
 }
 
 #[derive(Debug)]
@@ -323,23 +318,12 @@ enum Elide {
     /// Always use this one lifetime.
     Exact(Region),
     /// Less or more than one lifetime were found, error on unspecified.
-    Error(Vec<ElisionFailureInfo>),
+    Error,
     /// Forbid lifetime elision inside of a larger scope where it would be
     /// permitted. For example, in let position impl trait.
     Forbid,
 }
 
-#[derive(Clone, Debug)]
-pub(crate) struct ElisionFailureInfo {
-    /// Where we can find the argument pattern.
-    pub(crate) parent: Option<hir::BodyId>,
-    /// The index of the argument in the original definition.
-    pub(crate) index: usize,
-    pub(crate) lifetime_count: usize,
-    pub(crate) have_bound_regions: bool,
-    pub(crate) span: Span,
-}
-
 type ScopeRef<'a> = &'a Scope<'a>;
 
 const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
@@ -421,7 +405,6 @@ fn do_resolve(
         scope: ROOT_SCOPE,
         trait_definition_only,
         xcrate_object_lifetime_defaults: Default::default(),
-        missing_named_lifetime_spots: vec![],
     };
     visitor.visit_item(item);
 
@@ -644,40 +627,11 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
                 where_bound_origin: None,
             };
 
-            if let &hir::ClosureBinder::For { span, .. } = binder {
-                let last_lt = bound_generic_params
-                    .iter()
-                    .filter(|p| {
-                        matches!(
-                            p,
-                            GenericParam {
-                                kind: GenericParamKind::Lifetime {
-                                    kind: LifetimeParamKind::Explicit
-                                },
-                                ..
-                            }
-                        )
-                    })
-                    .last();
-                let (span, span_type) = match last_lt {
-                    Some(GenericParam { span: last_sp, .. }) => {
-                        (last_sp.shrink_to_hi(), ForLifetimeSpanType::ClosureTail)
-                    }
-                    None => (span, ForLifetimeSpanType::ClosureEmpty),
-                };
-                self.missing_named_lifetime_spots
-                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
-            }
-
             self.with(scope, |this| {
                 // a closure has no bounds, so everything
                 // contained within is scoped within its binder.
                 intravisit::walk_expr(this, e)
             });
-
-            if let hir::ClosureBinder::For { .. } = binder {
-                self.missing_named_lifetime_spots.pop();
-            }
         } else {
             intravisit::walk_expr(self, e)
         }
@@ -694,11 +648,9 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         }
         match item.kind {
             hir::ItemKind::Fn(_, ref generics, _) => {
-                self.missing_named_lifetime_spots.push(generics.into());
                 self.visit_early_late(None, item.hir_id(), generics, |this| {
                     intravisit::walk_item(this, item);
                 });
-                self.missing_named_lifetime_spots.pop();
             }
 
             hir::ItemKind::ExternCrate(_)
@@ -761,8 +713,6 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             | hir::ItemKind::Trait(_, _, ref generics, ..)
             | hir::ItemKind::TraitAlias(ref generics, ..)
             | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
-                self.missing_named_lifetime_spots.push(generics.into());
-
                 // These kinds of items have only early-bound lifetime parameters.
                 let mut index = if sub_items_have_self_param(&item.kind) {
                     1 // Self comes before lifetimes
@@ -800,7 +750,6 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                         intravisit::walk_item(this, item);
                     });
                 });
-                self.missing_named_lifetime_spots.pop();
             }
         }
     }
@@ -826,20 +775,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 lifetime_span: Option<Span> =
-                    c.generic_params.iter().rev().find_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
-                            Some(param.span)
-                        }
-                        _ => None,
-                    });
-                let (span, span_type) = if let Some(span) = lifetime_span {
-                    (span.shrink_to_hi(), ForLifetimeSpanType::TypeTail)
-                } else {
-                    (ty.span.shrink_to_lo(), ForLifetimeSpanType::TypeEmpty)
-                };
-                self.missing_named_lifetime_spots
-                    .push(MissingLifetimeSpot::HigherRanked { span, span_type });
                 let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
                     .generic_params
                     .iter()
@@ -867,7 +802,6 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     // contained within is scoped within its binder.
                     intravisit::walk_ty(this, ty);
                 });
-                self.missing_named_lifetime_spots.pop();
             }
             hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
                 debug!(?bounds, ?lifetime, "TraitObject");
@@ -878,11 +812,6 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     }
                 });
                 match lifetime.name {
-                    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",);
-                    }
                     LifetimeName::ImplicitObjectLifetimeDefault => {
                         // If the user does not write *anything*, we
                         // use the object lifetime defaulting
@@ -890,7 +819,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                         // `Box<dyn Debug + 'static>`.
                         self.resolve_object_lifetime_default(lifetime)
                     }
-                    LifetimeName::Underscore => {
+                    LifetimeName::Implicit | LifetimeName::Underscore => {
                         // If the user writes `'_`, we use the *ordinary* elision
                         // rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be
                         // resolved the same as the `'_` in `&'_ Foo`.
@@ -1010,10 +939,12 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                 let mut elision = None;
                 let mut lifetimes = FxIndexMap::default();
                 let mut non_lifetime_count = 0;
+                debug!(?generics.params);
                 for param in generics.params {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
                             let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, &param);
+                            lifetimes.insert(def_id, reg);
                             if let hir::ParamName::Plain(Ident {
                                 name: kw::UnderscoreLifetime,
                                 ..
@@ -1022,8 +953,6 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                                 // Pick the elided lifetime "definition" if one exists
                                 // and use it to make an elision scope.
                                 elision = Some(reg);
-                            } else {
-                                lifetimes.insert(def_id, reg);
                             }
                         }
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@@ -1088,7 +1017,6 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
             Fn(_, _) => {
-                self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(trait_item.hir_id())),
@@ -1096,10 +1024,8 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
                     &trait_item.generics,
                     |this| intravisit::walk_trait_item(this, trait_item),
                 );
-                self.missing_named_lifetime_spots.pop();
             }
             Type(bounds, ref ty) => {
-                self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let generics = &trait_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
@@ -1140,14 +1066,11 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
                         }
                     })
                 });
-                self.missing_named_lifetime_spots.pop();
             }
             Const(_, _) => {
                 // Only methods and types support generics.
                 assert!(trait_item.generics.params.is_empty());
-                self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
                 intravisit::walk_trait_item(self, trait_item);
-                self.missing_named_lifetime_spots.pop();
             }
         }
     }
@@ -1156,7 +1079,6 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
         match impl_item.kind {
             Fn(..) => {
-                self.missing_named_lifetime_spots.push((&impl_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
                     Some(tcx.hir().get_parent_item(impl_item.hir_id())),
@@ -1164,11 +1086,9 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
                     &impl_item.generics,
                     |this| intravisit::walk_impl_item(this, impl_item),
                 );
-                self.missing_named_lifetime_spots.pop();
             }
             TyAlias(ref ty) => {
                 let generics = &impl_item.generics;
-                self.missing_named_lifetime_spots.push(generics.into());
                 let mut index = self.next_early_index();
                 let mut non_lifetime_count = 0;
                 debug!("visit_ty: index = {}", index);
@@ -1203,14 +1123,11 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
                         this.visit_ty(ty);
                     })
                 });
-                self.missing_named_lifetime_spots.pop();
             }
             Const(_, _) => {
                 // Only methods and types support generics.
                 assert!(impl_item.generics.params.is_empty());
-                self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static);
                 intravisit::walk_impl_item(self, impl_item);
-                self.missing_named_lifetime_spots.pop();
             }
         }
     }
@@ -1393,8 +1310,6 @@ fn visit_poly_trait_ref(
     ) {
         debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
 
-        let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref);
-
         let next_early_index = self.next_early_index();
         let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
 
@@ -1435,10 +1350,6 @@ fn visit_poly_trait_ref(
             walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
             this.visit_trait_ref(&trait_ref.trait_ref);
         });
-
-        if should_pop_missing_lt {
-            self.missing_named_lifetime_spots.pop();
-        }
     }
 }
 
@@ -1584,14 +1495,12 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
     {
         let LifetimeContext { tcx, map, .. } = self;
         let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
-        let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
         let mut this = LifetimeContext {
             tcx: *tcx,
             map,
             scope: &wrap_scope,
             trait_definition_only: self.trait_definition_only,
             xcrate_object_lifetime_defaults,
-            missing_named_lifetime_spots,
         };
         let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
         {
@@ -1599,7 +1508,6 @@ fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
             f(&mut this);
         }
         self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
-        self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
     }
 
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
@@ -2202,24 +2110,20 @@ fn visit_fn_like_elision(
         let mut assoc_item_kind = None;
         let mut impl_self = None;
         let parent = self.tcx.hir().get_parent_node(output.hir_id);
-        let body = match self.tcx.hir().get(parent) {
+        match self.tcx.hir().get(parent) {
             // `fn` definitions and methods.
-            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(.., body), .. }) => Some(body),
+            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) => {}
 
-            Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => {
+            Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => {
                 if let hir::ItemKind::Trait(.., ref trait_items) =
                     self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
                 {
                     assoc_item_kind =
                         trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
                 }
-                match *m {
-                    hir::TraitFn::Required(_) => None,
-                    hir::TraitFn::Provided(body) => Some(body),
-                }
             }
 
-            Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
+            Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, _), .. }) => {
                 if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
                     self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
                 {
@@ -2227,13 +2131,12 @@ fn visit_fn_like_elision(
                     assoc_item_kind =
                         items.iter().find(|ii| ii.id.hir_id() == parent).map(|ii| ii.kind);
                 }
-                Some(body)
             }
 
             // Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
-            Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
+            Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => {},
 
-            Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None,
+            Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => {},
 
             // Everything else (only closures?) doesn't
             // actually enjoy elision in return types.
@@ -2320,42 +2223,29 @@ fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) {
         // have that lifetime.
         let mut possible_implied_output_region = None;
         let mut lifetime_count = 0;
-        let arg_lifetimes = inputs
-            .iter()
-            .enumerate()
-            .skip(has_self as usize)
-            .map(|(i, input)| {
-                let mut gather = GatherLifetimes {
-                    map: self.map,
-                    outer_index: ty::INNERMOST,
-                    have_bound_regions: false,
-                    lifetimes: Default::default(),
-                };
-                gather.visit_ty(input);
-
-                lifetime_count += gather.lifetimes.len();
+        for input in inputs.iter().skip(has_self as usize) {
+            let mut gather = GatherLifetimes {
+                map: self.map,
+                outer_index: ty::INNERMOST,
+                have_bound_regions: false,
+                lifetimes: Default::default(),
+            };
+            gather.visit_ty(input);
 
-                if lifetime_count == 1 && gather.lifetimes.len() == 1 {
-                    // there's a chance that the unique lifetime of this
-                    // iteration will be the appropriate lifetime for output
-                    // parameters, so lets store it.
-                    possible_implied_output_region = gather.lifetimes.iter().cloned().next();
-                }
+            lifetime_count += gather.lifetimes.len();
 
-                ElisionFailureInfo {
-                    parent: body,
-                    index: i,
-                    lifetime_count: gather.lifetimes.len(),
-                    have_bound_regions: gather.have_bound_regions,
-                    span: input.span,
-                }
-            })
-            .collect();
+            if lifetime_count == 1 && gather.lifetimes.len() == 1 {
+                // there's a chance that the unique lifetime of this
+                // iteration will be the appropriate lifetime for output
+                // parameters, so lets store it.
+                possible_implied_output_region = gather.lifetimes.iter().cloned().next();
+            }
+        }
 
         let elide = if lifetime_count == 1 {
             Elide::Exact(possible_implied_output_region.unwrap())
         } else {
-            Elide::Error(arg_lifetimes)
+            Elide::Error
         };
 
         debug!(?elide);
@@ -2487,17 +2377,14 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
 
         let mut late_depth = 0;
         let mut scope = self.scope;
-        let mut in_scope_lifetimes = FxIndexSet::default();
-        let error = loop {
+        loop {
             match *scope {
                 // Do not assign any resolution, it will be inferred.
                 Scope::Body { .. } => return,
 
-                Scope::Root => break None,
+                Scope::Root => break,
 
-                Scope::Binder { s, ref lifetimes, scope_type, .. } => {
-                    // collect named lifetimes for suggestions
-                    in_scope_lifetimes.extend(lifetimes.keys().copied());
+                Scope::Binder { s, scope_type, .. } => {
                     match scope_type {
                         BinderScopeType::Normal => late_depth += 1,
                         BinderScopeType::Concatenating => {}
@@ -2526,27 +2413,8 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
                     return;
                 }
 
-                Scope::Elision { elide: Elide::Error(ref e), ref s, .. } => {
-                    let mut scope = s;
-                    loop {
-                        match scope {
-                            Scope::Binder { ref lifetimes, s, .. } => {
-                                // Collect named lifetimes for suggestions.
-                                in_scope_lifetimes.extend(lifetimes.keys().copied());
-                                scope = s;
-                            }
-                            Scope::ObjectLifetimeDefault { ref s, .. }
-                            | Scope::Elision { ref s, .. }
-                            | Scope::TraitRefBoundary { ref s, .. } => {
-                                scope = s;
-                            }
-                            _ => break,
-                        }
-                    }
-                    break Some(&e[..]);
-                }
-
-                Scope::Elision { elide: Elide::Forbid, .. } => break None,
+                Scope::Elision { elide: Elide::Error, .. }
+                | Scope::Elision { elide: Elide::Forbid, .. } => break,
 
                 Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
@@ -2554,26 +2422,11 @@ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) {
                     scope = s;
                 }
             }
-        };
-
-        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();
-
-        let mut err = self.report_missing_lifetime_specifiers(spans.clone(), lifetime_refs.len());
+        }
 
-        self.add_missing_lifetime_specifiers_label(
-            &mut err,
-            spans_with_counts,
-            in_scope_lifetimes,
-            error,
-        );
-        err.emit();
+        for lt in lifetime_refs {
+            self.tcx.sess.delay_span_bug(lt.span, "Missing lifetime specifier");
+        }
     }
 
     fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
index 2fcbe1d4c14a565cc7a9a9e4db614c87165b1045..31d10008efbfbe8b9278f8c66c4cf356df41d73c 100644 (file)
@@ -11,6 +11,7 @@
 #![feature(drain_filter)]
 #![feature(if_let_guard)]
 #![cfg_attr(bootstrap, feature(let_chains))]
+#![feature(iter_intersperse)]
 #![feature(let_else)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
@@ -436,7 +437,7 @@ enum ModuleKind {
     ///     f(); // Resolves to (1)
     /// }
     /// ```
-    Block(NodeId),
+    Block,
     /// Any module with a name.
     ///
     /// This could be:
@@ -453,7 +454,7 @@ impl ModuleKind {
     /// Get name of the module.
     pub fn name(&self) -> Option<Symbol> {
         match self {
-            ModuleKind::Block(..) => None,
+            ModuleKind::Block => None,
             ModuleKind::Def(.., name) => Some(*name),
         }
     }
@@ -529,7 +530,7 @@ fn new(
     ) -> Self {
         let is_foreign = match kind {
             ModuleKind::Def(_, def_id, _) => !def_id.is_local(),
-            ModuleKind::Block(_) => false,
+            ModuleKind::Block => false,
         };
         ModuleData {
             parent,
index 2b5eb12a8a890e39a26b902b8fa790856cdeaa45..070fb9c721b401b1287fde73e37972e04e38ea97 100644 (file)
@@ -812,7 +812,7 @@ fn check_stability_and_deprecation(
                     stability::report_unstable(
                         self.session,
                         feature,
-                        reason,
+                        reason.to_opt_reason(),
                         issue,
                         None,
                         is_soft,
index 1b583417ca089697bd6ab85531e902e93c596a11..28e2e0db89a1fb7cffa737739963c0ed37764f67 100644 (file)
@@ -1282,6 +1282,8 @@ pub(crate) fn parse_branch_protection(
         "emit a section containing stack size metadata (default: no)"),
     emit_thin_lto: bool = (true, parse_bool, [TRACKED],
         "emit the bc module with thin LTO info (default: yes)"),
+    export_executable_symbols: bool = (false, parse_bool, [TRACKED],
+        "export symbols from executables, as if they were dynamic libraries"),
     fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
         (default: no)"),
index b4a4424e876cdeb6e5178df20f6bb19d3831be88..47159584afe3b3780f7113fa748e0a6a1ad7e36f 100644 (file)
@@ -586,17 +586,6 @@ fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSni
         }
     }
 
-    /// Returns whether or not this span points into a file
-    /// in the current crate. This may be `false` for spans
-    /// produced by a macro expansion, or for spans associated
-    /// with the definition of an item in a foreign crate
-    pub fn is_local_span(&self, sp: Span) -> bool {
-        let local_begin = self.lookup_byte_offset(sp.lo());
-        let local_end = self.lookup_byte_offset(sp.hi());
-        // This might be a weird span that covers multiple files
-        local_begin.sf.src.is_some() && local_end.sf.src.is_some()
-    }
-
     pub fn is_span_accessible(&self, sp: Span) -> bool {
         self.span_to_source(sp, |src, start_index, end_index| {
             Ok(src.get(start_index..end_index).is_some())
index cb15132bd4ba79d7540748a4b711815329c253c6..c75b6772487f9f6fb4e2dae1ee3b3ad737525308 100644 (file)
         rustc,
         rustc_allocator,
         rustc_allocator_nounwind,
+        rustc_allocator_zeroed,
         rustc_allow_const_fn_unstable,
         rustc_allow_incoherent_impl,
         rustc_allowed_through_unstable_modules,
         rustc_const_stable,
         rustc_const_unstable,
         rustc_conversion_suggestion,
+        rustc_deallocator,
         rustc_def_path,
         rustc_diagnostic_item,
         rustc_diagnostic_macros,
         rustc_private,
         rustc_proc_macro_decls,
         rustc_promotable,
+        rustc_reallocator,
         rustc_regions,
         rustc_reservation_impl,
         rustc_serialize,
         unsized_locals,
         unsized_tuple_coercion,
         unstable,
+        unstable_location_reason_default: "this crate is being loaded from the sysroot, an \
+                          unstable location; did you mean to load this crate \
+                          from crates.io via `Cargo.toml` instead?",
         untagged_unions,
         unused_imports,
         unused_qualifications,
index 9983438233e1ef129275b506f53ab82d1f57a2e6..fa94aa19abda594386bf61b758c515621a5a3ec6 100644 (file)
@@ -703,13 +703,42 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 }
             }
             ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
-            ty::Opaque(..) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+            ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
                 self.tcx.sess.delay_span_bug(
                     DUMMY_SP,
                     format!("ty_is_local invoked on closure or generator: {:?}", ty),
                 );
                 ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
             }
+            ty::Opaque(..) => {
+                // This merits some explanation.
+                // Normally, opaque types are not involved when performing
+                // coherence checking, since it is illegal to directly
+                // implement a trait on an opaque type. However, we might
+                // end up looking at an opaque type during coherence checking
+                // if an opaque type gets used within another type (e.g. as
+                // the type of a field) when checking for auto trait or `Sized`
+                // impls. This requires us to decide whether or not an opaque
+                // type should be considered 'local' or not.
+                //
+                // We choose to treat all opaque types as non-local, even
+                // those that appear within the same crate. This seems
+                // somewhat surprising at first, but makes sense when
+                // you consider that opaque types are supposed to hide
+                // the underlying type *within the same crate*. When an
+                // opaque type is used from outside the module
+                // where it is declared, it should be impossible to observe
+                // anything about it other than the traits that it implements.
+                //
+                // The alternative would be to look at the underlying type
+                // to determine whether or not the opaque type itself should
+                // be considered local. However, this could make it a breaking change
+                // to switch the underlying ('defining') type from a local type
+                // to a remote type. This would violate the rule that opaque
+                // types should be completely opaque apart from the traits
+                // that they implement, so we don't use this behavior.
+                self.found_non_local_ty(ty)
+            }
         };
         // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
         // the first type we visit is always the self type.
index decbf0133114f23ce21f3f72ab796f69bcddf176..254bc4ab66386bbf345a630e5ec306741b6701e5 100644 (file)
@@ -185,21 +185,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
         }
         let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
         match concrete {
-            Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
-                NotConstEvaluatable::MentionsInfer
-            } else if uv.has_param_types_or_consts() {
-                infcx
-                    .tcx
-                    .sess
-                    .delay_span_bug(span, &format!("unexpected `TooGeneric` for {:?}", uv));
-                NotConstEvaluatable::MentionsParam
-            } else {
-                let guar = infcx.tcx.sess.delay_span_bug(
+            Err(ErrorHandled::TooGeneric) => {
+                Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
                     span,
                     format!("Missing value for constant, but no error reported?"),
-                );
-                NotConstEvaluatable::Error(guar)
-            }),
+                )))
+            }
             Err(ErrorHandled::Linted) => {
                 let reported = infcx
                     .tcx
index 2f92a77a7957d886185adb768ea2c4f09ef8671b..25ba520ace2bae62ea633a7bd263cb35fdfc82b2 100644 (file)
@@ -301,13 +301,10 @@ fn report_selection_error(
                         span = obligation.cause.span;
                     }
                 }
-                if let ObligationCauseCode::CompareImplMethodObligation {
-                    impl_item_def_id,
-                    trait_item_def_id,
-                }
-                | ObligationCauseCode::CompareImplTypeObligation {
+                if let ObligationCauseCode::CompareImplItemObligation {
                     impl_item_def_id,
                     trait_item_def_id,
+                    kind: _,
                 } = *obligation.cause.code()
                 {
                     self.report_extra_impl_obligation(
@@ -634,9 +631,9 @@ fn report_selection_error(
                                         &format!(
                                             "expected a closure taking {} argument{}, but one taking {} argument{} was given",
                                             given.len(),
-                                            if given.len() == 1 { "" } else { "s" },
+                                            pluralize!(given.len()),
                                             expected.len(),
-                                            if expected.len() == 1 { "" } else { "s" },
+                                            pluralize!(expected.len()),
                                         )
                                     );
                                 } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
@@ -669,7 +666,7 @@ fn report_selection_error(
                             );
                         } else if !suggested {
                             // Can't show anything else useful, try to find similar impls.
-                            let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                            let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
                             if !self.report_similar_impl_candidates(
                                 impl_candidates,
                                 trait_ref,
@@ -704,7 +701,7 @@ fn report_selection_error(
                                 {
                                     let trait_ref = trait_pred.to_poly_trait_ref();
                                     let impl_candidates =
-                                        self.find_similar_impl_candidates(trait_ref);
+                                        self.find_similar_impl_candidates(trait_pred);
                                     self.report_similar_impl_candidates(
                                         impl_candidates,
                                         trait_ref,
@@ -1328,7 +1325,7 @@ fn fuzzy_match_tys(
 
     fn find_similar_impl_candidates(
         &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Vec<ImplCandidate<'tcx>>;
 
     fn report_similar_impl_candidates(
@@ -1697,18 +1694,22 @@ fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
 
     fn find_similar_impl_candidates(
         &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Vec<ImplCandidate<'tcx>> {
         self.tcx
-            .all_impls(trait_ref.def_id())
+            .all_impls(trait_pred.def_id())
             .filter_map(|def_id| {
-                if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
+                if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
+                    || !trait_pred
+                        .skip_binder()
+                        .is_constness_satisfied_by(self.tcx.constness(def_id))
+                {
                     return None;
                 }
 
                 let imp = self.tcx.impl_trait_ref(def_id).unwrap();
 
-                self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false)
+                self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
                     .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
             })
             .collect()
index 7ab85e7fa663e82eb845ba1e8104d0602f27af3b..89d7c050c408bc757fbf9ef9d277f41e0c39fe60 100644 (file)
@@ -2682,11 +2682,11 @@ fn note_obligation_cause_code<T>(
                     )
                 });
             }
-            ObligationCauseCode::CompareImplMethodObligation { trait_item_def_id, .. } => {
+            ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
                 let item_name = self.tcx.item_name(trait_item_def_id);
                 let msg = format!(
-                    "the requirement `{}` appears on the impl method `{}` but not on the \
-                     corresponding trait method",
+                    "the requirement `{}` appears on the `impl`'s {kind} `{}` but not on the \
+                     corresponding trait's {kind}",
                     predicate, item_name,
                 );
                 let sp = self
@@ -2697,7 +2697,7 @@ fn note_obligation_cause_code<T>(
                 let mut assoc_span: MultiSpan = sp.into();
                 assoc_span.push_span_label(
                     sp,
-                    format!("this trait method doesn't have the requirement `{}`", predicate),
+                    format!("this trait's {kind} doesn't have the requirement `{}`", predicate),
                 );
                 if let Some(ident) = self
                     .tcx
@@ -2708,38 +2708,6 @@ fn note_obligation_cause_code<T>(
                 }
                 err.span_note(assoc_span, &msg);
             }
-            ObligationCauseCode::CompareImplTypeObligation { trait_item_def_id, .. } => {
-                let item_name = self.tcx.item_name(trait_item_def_id);
-                let msg = format!(
-                    "the requirement `{}` appears on the associated impl type `{}` but not on the \
-                     corresponding associated trait type",
-                    predicate, item_name,
-                );
-                let sp = self.tcx.def_span(trait_item_def_id);
-                let mut assoc_span: MultiSpan = sp.into();
-                assoc_span.push_span_label(
-                    sp,
-                    format!(
-                        "this trait associated type doesn't have the requirement `{}`",
-                        predicate,
-                    ),
-                );
-                if let Some(ident) = self
-                    .tcx
-                    .opt_associated_item(trait_item_def_id)
-                    .and_then(|i| self.tcx.opt_item_ident(i.container.id()))
-                {
-                    assoc_span.push_span_label(ident.span, "in this trait");
-                }
-                err.span_note(assoc_span, &msg);
-            }
-            ObligationCauseCode::CompareImplConstObligation => {
-                err.note(&format!(
-                    "the requirement `{}` appears on the associated impl constant \
-                     but not on the corresponding associated trait constant",
-                    predicate
-                ));
-            }
             ObligationCauseCode::TrivialBound => {
                 err.help("see issue #48214");
                 if tcx.sess.opts.unstable_features.is_nightly_build() {
index fd6376ef6ee9dc04abfffdd00747a85c799d0670..791e9e0f5a3592bac49032854ac7462b41212878 100644 (file)
@@ -310,6 +310,7 @@ impl DebruijnIndex {
     ///    for<'a> fn(for<'b> fn(&'a x))
     ///
     /// you would need to shift the index for `'a` into a new binder.
+    #[inline]
     #[must_use]
     pub fn shifted_in(self, amount: u32) -> DebruijnIndex {
         DebruijnIndex::from_u32(self.as_u32() + amount)
@@ -317,18 +318,21 @@ pub fn shifted_in(self, amount: u32) -> DebruijnIndex {
 
     /// Update this index in place by shifting it "in" through
     /// `amount` number of binders.
+    #[inline]
     pub fn shift_in(&mut self, amount: u32) {
         *self = self.shifted_in(amount);
     }
 
     /// Returns the resulting index when this value is moved out from
     /// `amount` number of new binders.
+    #[inline]
     #[must_use]
     pub fn shifted_out(self, amount: u32) -> DebruijnIndex {
         DebruijnIndex::from_u32(self.as_u32() - amount)
     }
 
     /// Update in place by shifting out from `amount` binders.
+    #[inline]
     pub fn shift_out(&mut self, amount: u32) {
         *self = self.shifted_out(amount);
     }
@@ -353,6 +357,7 @@ pub fn shift_out(&mut self, amount: u32) {
     /// If we invoke `shift_out_to_binder` and the region is in fact
     /// bound by one of the binders we are shifting out of, that is an
     /// error (and should fail an assertion failure).
+    #[inline]
     pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self {
         self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32())
     }
index c873cf27e42c51cae416f53811b555344b85e679..99a8101dc96ba3b60239fc167345fed08b70ab67 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_session::parse::feature_err;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{sym, Ident};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{Span, Symbol, DUMMY_SP};
 
 use std::collections::BTreeSet;
 
@@ -17,7 +17,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// the type parameter's name as a placeholder.
     pub(crate) fn complain_about_missing_type_params(
         &self,
-        missing_type_params: Vec<String>,
+        missing_type_params: Vec<Symbol>,
         def_id: DefId,
         span: Span,
         empty_generic_args: bool,
index 7111812f0b090aadb68bcf303225ace290c6ec3d..58f4f02052f8bd64a7c9d964311fb73263a5e32a 100644 (file)
@@ -382,7 +382,7 @@ struct SubstsForAstPathCtxt<'a, 'tcx> {
             def_id: DefId,
             generic_args: &'a GenericArgs<'a>,
             span: Span,
-            missing_type_params: Vec<String>,
+            missing_type_params: Vec<Symbol>,
             inferred_params: Vec<Span>,
             infer_args: bool,
             is_object: bool,
@@ -514,7 +514,7 @@ fn inferred_kind(
                             // defaults. This will lead to an ICE if we are not
                             // careful!
                             if self.default_needs_object_self(param) {
-                                self.missing_type_params.push(param.name.to_string());
+                                self.missing_type_params.push(param.name);
                                 tcx.ty_error().into()
                             } else {
                                 // This is a default type parameter.
@@ -1150,17 +1150,12 @@ fn add_predicates_for_ast_type_binding(
             .expect("missing associated type");
 
         if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
-            let kind = match assoc_item.kind {
-                ty::AssocKind::Type => "type",
-                ty::AssocKind::Const => "const",
-                _ => unreachable!(),
-            };
             tcx.sess
                 .struct_span_err(
                     binding.span,
-                    &format!("associated {kind} `{}` is private", binding.item_name),
+                    &format!("{} `{}` is private", assoc_item.kind, binding.item_name),
                 )
-                .span_label(binding.span, &format!("private associated {kind}"))
+                .span_label(binding.span, &format!("private {}", assoc_item.kind))
                 .emit();
         }
         tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
index f629f6a0099d7a86d19cbd2f1c604b7b325c1024..147d87e7594c5be5e06d977087e65ba85dfea8ad 100644 (file)
@@ -488,7 +488,7 @@ pub(crate) fn opt_suggest_box_span(
                                 ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
                                     trait_ref: ty::TraitRef {
                                         def_id: t.def_id(),
-                                        substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
+                                        substs: self.tcx.mk_substs_trait(outer_ty, &[]),
                                     },
                                     constness: t.constness,
                                     polarity: t.polarity,
@@ -496,9 +496,9 @@ pub(crate) fn opt_suggest_box_span(
                             let obl = Obligation::new(
                                 o.cause.clone(),
                                 self.param_env,
-                                pred.to_predicate(self.infcx.tcx),
+                                pred.to_predicate(self.tcx),
                             );
-                            suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl);
+                            suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
                             if !suggest_box {
                                 // We've encountered some obligation that didn't hold, so the
                                 // return expression can't just be boxed. We don't need to
index 00c8aa3a1bbdae7df4c5817ddea93d464b1d5add..0836f15a1221bf27e2f2eb285bbd1c9dc13c4939 100644 (file)
@@ -376,7 +376,7 @@ fn confirm_builtin_call(
                             self.param_env,
                             *predicate,
                         );
-                        let result = self.infcx.evaluate_obligation(&obligation);
+                        let result = self.evaluate_obligation(&obligation);
                         self.tcx
                             .sess
                             .struct_span_err(
index 2005fc24ed09b1cbdd35dd315cf325849ef13358..fee872155f5b2d1fa86c3ca4958a8c5d0384ce3a 100644 (file)
@@ -96,7 +96,7 @@ fn check_closure(
             self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
         );
 
-        let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+        let tupled_upvars_ty = self.next_ty_var(TypeVariableOrigin {
             kind: TypeVariableOriginKind::ClosureSynthetic,
             span: self.tcx.hir().span(expr.hir_id),
         });
@@ -141,7 +141,7 @@ fn check_closure(
 
             // Create a type variable (for now) to represent the closure kind.
             // It will be unified during the upvar inference phase (`upvar.rs`)
-            None => self.infcx.next_ty_var(TypeVariableOrigin {
+            None => self.next_ty_var(TypeVariableOrigin {
                 // FIXME(eddyb) distinguish closure kind inference variables from the rest.
                 kind: TypeVariableOriginKind::ClosureSynthetic,
                 span: expr.span,
@@ -531,7 +531,7 @@ fn check_supplied_sig_against_expectation(
         //
         // [c1]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341089706
         // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796
-        self.infcx.commit_if_ok(|_| {
+        self.commit_if_ok(|_| {
             let mut all_obligations = vec![];
 
             // The liberated version of this signature should be a subtype
@@ -544,7 +544,7 @@ fn check_supplied_sig_against_expectation(
                 expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'.
             ) {
                 // Instantiate (this part of..) S to S', i.e., with fresh variables.
-                let supplied_ty = self.infcx.replace_bound_vars_with_fresh_vars(
+                let supplied_ty = self.replace_bound_vars_with_fresh_vars(
                     hir_ty.span,
                     LateBoundRegionConversionTime::FnCall,
                     supplied_sig.inputs().rebind(supplied_ty),
@@ -557,7 +557,7 @@ fn check_supplied_sig_against_expectation(
                 all_obligations.extend(obligations);
             }
 
-            let supplied_output_ty = self.infcx.replace_bound_vars_with_fresh_vars(
+            let supplied_output_ty = self.replace_bound_vars_with_fresh_vars(
                 decl.output.span(),
                 LateBoundRegionConversionTime::FnCall,
                 supplied_sig.output(),
index 9c9a2096ae9a481ecec8f697bf150495e4cf8bda..639cab98f1741f02175482d65b658417c12cb8e0 100644 (file)
@@ -241,13 +241,13 @@ fn coerce_from_inference_variable(
         make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
     ) -> CoerceResult<'tcx> {
         debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
-        assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a);
-        assert!(self.infcx.shallow_resolve(b) == b);
+        assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
+        assert!(self.shallow_resolve(b) == b);
 
         if b.is_ty_var() {
             // Two unresolved type variables: create a `Coerce` predicate.
             let target_ty = if self.use_lub {
-                self.infcx.next_ty_var(TypeVariableOrigin {
+                self.next_ty_var(TypeVariableOrigin {
                     kind: TypeVariableOriginKind::LatticeVariable,
                     span: self.cause.span,
                 })
@@ -991,7 +991,7 @@ pub fn deref_once_mutably_for_diagnostic(&self, expr_ty: Ty<'tcx>) -> Option<Ty<
         self.autoderef(rustc_span::DUMMY_SP, expr_ty).nth(1).and_then(|(deref_ty, _)| {
             self.infcx
                 .type_implements_trait(
-                    self.infcx.tcx.lang_items().deref_mut_trait()?,
+                    self.tcx.lang_items().deref_mut_trait()?,
                     expr_ty,
                     ty::List::empty(),
                     self.param_env,
index 1a9354f5d20c54c287c46d26fead0216daa752e7..af77efc3c2d57434692c14e091bf1605358c0d10 100644 (file)
@@ -90,9 +90,10 @@ fn compare_predicate_entailment<'tcx>(
     let mut cause = ObligationCause::new(
         impl_m_span,
         impl_m_hir_id,
-        ObligationCauseCode::CompareImplMethodObligation {
+        ObligationCauseCode::CompareImplItemObligation {
             impl_item_def_id: impl_m.def_id.expect_local(),
             trait_item_def_id: trait_m.def_id,
+            kind: impl_m.kind,
         },
     );
 
@@ -223,9 +224,10 @@ fn compare_predicate_entailment<'tcx>(
             let cause = ObligationCause::new(
                 span,
                 impl_m_hir_id,
-                ObligationCauseCode::CompareImplMethodObligation {
+                ObligationCauseCode::CompareImplItemObligation {
                     impl_item_def_id: impl_m.def_id.expect_local(),
                     trait_item_def_id: trait_m.def_id,
+                    kind: impl_m.kind,
                 },
             );
             ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
@@ -1079,7 +1081,11 @@ pub(crate) fn compare_const_impl<'tcx>(
         let mut cause = ObligationCause::new(
             impl_c_span,
             impl_c_hir_id,
-            ObligationCauseCode::CompareImplConstObligation,
+            ObligationCauseCode::CompareImplItemObligation {
+                impl_item_def_id: impl_c.def_id.expect_local(),
+                trait_item_def_id: trait_c.def_id,
+                kind: impl_c.kind,
+            },
         );
 
         // There is no "body" here, so just pass dummy id.
@@ -1212,15 +1218,6 @@ fn compare_type_predicate_entailment<'tcx>(
     // `ObligationCause` (and the `FnCtxt`). This is what
     // `regionck_item` expects.
     let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
-    let cause = ObligationCause::new(
-        impl_ty_span,
-        impl_ty_hir_id,
-        ObligationCauseCode::CompareImplTypeObligation {
-            impl_item_def_id: impl_ty.def_id.expect_local(),
-            trait_item_def_id: trait_ty.def_id,
-        },
-    );
-
     debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
 
     // The predicates declared by the impl definition, the trait and the
@@ -1239,7 +1236,7 @@ fn compare_type_predicate_entailment<'tcx>(
         Reveal::UserFacing,
         hir::Constness::NotConst,
     );
-    let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause.clone());
+    let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
     tcx.infer_ctxt().enter(|infcx| {
         let ocx = ObligationCtxt::new(&infcx);
 
@@ -1247,12 +1244,25 @@ fn compare_type_predicate_entailment<'tcx>(
 
         let mut selcx = traits::SelectionContext::new(&infcx);
 
-        for predicate in impl_ty_own_bounds.predicates {
+        assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
+        for (span, predicate) in
+            std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
+        {
+            let cause = ObligationCause::misc(span, impl_ty_hir_id);
             let traits::Normalized { value: predicate, obligations } =
-                traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
+                traits::normalize(&mut selcx, param_env, cause, predicate);
 
+            let cause = ObligationCause::new(
+                span,
+                impl_ty_hir_id,
+                ObligationCauseCode::CompareImplItemObligation {
+                    impl_item_def_id: impl_ty.def_id.expect_local(),
+                    trait_item_def_id: trait_ty.def_id,
+                    kind: impl_ty.kind,
+                },
+            );
             ocx.register_obligations(obligations);
-            ocx.register_obligation(traits::Obligation::new(cause.clone(), param_env, predicate));
+            ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
         }
 
         // Check that all obligations are satisfied by the implementation's
index a2d8765289c55498ae098f049d3ea424b386a5aa..58b0399c5c927cab49c64ef1ba9d3641434b7975 100644 (file)
@@ -287,6 +287,21 @@ fn suggest_compatible_variants(
         expr_ty: Ty<'tcx>,
     ) {
         if let ty::Adt(expected_adt, substs) = expected.kind() {
+            if let hir::ExprKind::Field(base, ident) = expr.kind {
+                let base_ty = self.typeck_results.borrow().expr_ty(base);
+                if self.can_eq(self.param_env, base_ty, expected).is_ok()
+                    && let Some(base_span) = base.span.find_ancestor_inside(expr.span)
+                {
+                    err.span_suggestion_verbose(
+                        expr.span.with_lo(base_span.hi()),
+                        format!("consider removing the tuple struct field `{ident}`"),
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
+                    return
+                }
+            }
+
             // If the expression is of type () and it's the return expression of a block,
             // we suggest adding a separate return expression instead.
             // (To avoid things like suggesting `Ok(while .. { .. })`.)
@@ -815,7 +830,7 @@ pub fn check_ref(
                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
                 _,
                 &ty::Ref(_, checked, _),
-            ) if self.infcx.can_sub(self.param_env, checked, expected).is_ok() => {
+            ) if self.can_sub(self.param_env, checked, expected).is_ok() => {
                 // We have `&T`, check if what was expected was `T`. If so,
                 // we may want to suggest removing a `&`.
                 if sm.is_imported(expr.span) {
@@ -959,7 +974,7 @@ pub fn check_ref(
 
                     // For this suggestion to make sense, the type would need to be `Copy`,
                     // or we have to be moving out of a `Box<T>`
-                    if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp)
+                    if self.type_is_copy_modulo_regions(self.param_env, expected, sp)
                         // FIXME(compiler-errors): We can actually do this if the checked_ty is
                         // `steps` layers of boxes, not just one, but this is easier and most likely.
                         || (checked_ty.is_box() && steps == 1)
index 8e4cd2392e03bf5edc9470e256c3960af4295db1..ba5ef5edc8630cd803cbe4379652e48f992ef578 100644 (file)
@@ -2235,7 +2235,7 @@ fn suggest_await_on_field_access(
         base: &'tcx hir::Expr<'tcx>,
         ty: Ty<'tcx>,
     ) {
-        let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
+        let output_ty = match self.get_impl_future_output_ty(ty) {
             Some(output_ty) => self.resolve_vars_if_possible(output_ty),
             _ => return,
         };
index 67a89a69f65528f004b6f2ff0e2a80dfb8b0cbe4..4059b3403b19fe4851db0658c6d1fe870b8a9a3d 100644 (file)
@@ -218,9 +218,9 @@ fn calculate_diverging_fallback(
             .diverging_type_vars
             .borrow()
             .iter()
-            .map(|&ty| self.infcx.shallow_resolve(ty))
+            .map(|&ty| self.shallow_resolve(ty))
             .filter_map(|ty| ty.ty_vid())
-            .map(|vid| self.infcx.root_var(vid))
+            .map(|vid| self.root_var(vid))
             .collect();
         debug!(
             "calculate_diverging_fallback: diverging_type_vars={:?}",
@@ -236,7 +236,7 @@ fn calculate_diverging_fallback(
         let mut diverging_vids = vec![];
         let mut non_diverging_vids = vec![];
         for unsolved_vid in unsolved_vids {
-            let root_vid = self.infcx.root_var(unsolved_vid);
+            let root_vid = self.root_var(unsolved_vid);
             debug!(
                 "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}",
                 unsolved_vid,
@@ -271,7 +271,7 @@ fn calculate_diverging_fallback(
         // variables. (Note that this set consists of "root variables".)
         let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph);
         for &non_diverging_vid in &non_diverging_vids {
-            let root_vid = self.infcx.root_var(non_diverging_vid);
+            let root_vid = self.root_var(non_diverging_vid);
             if roots_reachable_from_diverging.visited(root_vid) {
                 continue;
             }
@@ -294,7 +294,7 @@ fn calculate_diverging_fallback(
         diverging_fallback.reserve(diverging_vids.len());
         for &diverging_vid in &diverging_vids {
             let diverging_ty = self.tcx.mk_ty_var(diverging_vid);
-            let root_vid = self.infcx.root_var(diverging_vid);
+            let root_vid = self.root_var(diverging_vid);
             let can_reach_non_diverging = coercion_graph
                 .depth_first_search(root_vid)
                 .any(|n| roots_reachable_from_non_diverging.visited(n));
@@ -302,7 +302,7 @@ fn calculate_diverging_fallback(
             let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false };
 
             for (vid, rel) in relationships.iter() {
-                if self.infcx.root_var(*vid) == root_vid {
+                if self.root_var(*vid) == root_vid {
                     relationship.self_in_trait |= rel.self_in_trait;
                     relationship.output |= rel.output;
                 }
@@ -387,12 +387,12 @@ fn create_coercion_graph(&self) -> VecGraph<ty::TyVid> {
             })
             .collect();
         debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges);
-        let num_ty_vars = self.infcx.num_ty_vars();
+        let num_ty_vars = self.num_ty_vars();
         VecGraph::new(num_ty_vars, coercion_edges)
     }
 
     /// If `ty` is an unresolved type variable, returns its root vid.
     fn root_vid(&self, ty: Ty<'tcx>) -> Option<ty::TyVid> {
-        Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?))
+        Some(self.root_var(self.shallow_resolve(ty).ty_vid()?))
     }
 }
index 21b3c9063a78a85331e4caf8ed7a5c252efce94f..d1c10a3b63c65cdf15cb637757e5e9d185f831e7 100644 (file)
@@ -185,12 +185,12 @@ pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>)
         if !method.substs.is_empty() {
             let method_generics = self.tcx.generics_of(method.def_id);
             if !method_generics.params.is_empty() {
-                let user_type_annotation = self.infcx.probe(|_| {
+                let user_type_annotation = self.probe(|_| {
                     let user_substs = UserSubsts {
                         substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
                             let i = param.index as usize;
                             if i < method_generics.parent_count {
-                                self.infcx.var_for_def(DUMMY_SP, param)
+                                self.var_for_def(DUMMY_SP, param)
                             } else {
                                 method.substs[i]
                             }
@@ -198,7 +198,7 @@ pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>)
                         user_self_ty: None, // not relevant here
                     };
 
-                    self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
+                    self.canonicalize_user_type_annotation(UserType::TypeOf(
                         method.def_id,
                         user_substs,
                     ))
@@ -236,7 +236,7 @@ pub fn write_user_type_annotation_from_substs(
         debug!("fcx {}", self.tag());
 
         if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
-            let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
+            let canonicalized = self.canonicalize_user_type_annotation(UserType::TypeOf(
                 def_id,
                 UserSubsts { substs, user_self_ty },
             ));
@@ -480,7 +480,7 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
 
         if Self::can_contain_user_lifetime_bounds(ty) {
-            let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty));
+            let c_ty = self.canonicalize_response(UserType::Ty(ty));
             debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
             self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
         }
@@ -764,7 +764,7 @@ pub(in super::super) fn expected_inputs_for_expected_output(
                 if let ty::subst::GenericArgKind::Type(ty) = ty.unpack()
                     && let ty::Opaque(def_id, _) = *ty.kind()
                     && let Some(def_id) = def_id.as_local()
-                    && self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() {
+                    && self.opaque_type_origin(def_id, DUMMY_SP).is_some() {
                     return None;
                 }
             }
@@ -826,7 +826,7 @@ pub(in super::super) fn resolve_lang_item_path(
         } else {
             self.tcx.bound_type_of(def_id)
         };
-        let substs = self.infcx.fresh_substs_for_item(span, def_id);
+        let substs = self.fresh_substs_for_item(span, def_id);
         let ty = item_ty.subst(self.tcx, substs);
 
         self.write_resolution(hir_id, Ok((def_kind, def_id)));
index 84d2878308a1016ffb948359b2e11bcaccb0dddb..eb22938fb61c47299e48cbce2ae7577fc8903dd9 100644 (file)
@@ -15,7 +15,7 @@
 use crate::structured_errors::StructuredDiagnostic;
 
 use rustc_ast as ast;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticId, MultiSpan};
+use rustc_errors::{pluralize, Applicability, Diagnostic, DiagnosticId, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -645,7 +645,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                                     "argument"
                                 ),
                                 potentially_plural_count(provided_args.len(), "argument"),
-                                if provided_args.len() == 1 { "was" } else { "were" }
+                                pluralize!("was", provided_args.len())
                             ),
                             DiagnosticId::Error(err_code.to_owned()),
                         );
@@ -770,7 +770,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                     if c_variadic { "at least " } else { "" },
                     potentially_plural_count(formal_and_expected_inputs.len(), "argument"),
                     potentially_plural_count(provided_args.len(), "argument"),
-                    if provided_args.len() == 1 { "was" } else { "were" }
+                    pluralize!("was", provided_args.len())
                 ),
                 DiagnosticId::Error(err_code.to_owned()),
             )
@@ -1520,21 +1520,13 @@ fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'t
     /// ```
     fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
         let check_in_progress = |elem: &hir::Expr<'_>| {
-            self.in_progress_typeck_results
-                .and_then(|typeck_results| typeck_results.borrow().node_type_opt(elem.hir_id))
-                .and_then(|ty| {
-                    if ty.is_never() {
-                        None
-                    } else {
-                        Some(match elem.kind {
-                            // Point at the tail expression when possible.
-                            hir::ExprKind::Block(block, _) => {
-                                block.expr.map_or(block.span, |e| e.span)
-                            }
-                            _ => elem.span,
-                        })
-                    }
-                })
+            self.typeck_results.borrow().node_type_opt(elem.hir_id).filter(|ty| !ty.is_never()).map(
+                |_| match elem.kind {
+                    // Point at the tail expression when possible.
+                    hir::ExprKind::Block(block, _) => block.expr.map_or(block.span, |e| e.span),
+                    _ => elem.span,
+                },
+            )
         };
 
         if let hir::ExprKind::If(_, _, Some(el)) = expr.kind {
index 2f841fc277ded364f3d9b4203ea3f17099d65ae6..a499179b95f107c70be5c30e40743ee5fcb2fa29 100644 (file)
@@ -1,5 +1,4 @@
 use super::callee::DeferredCallResolution;
-use super::MaybeInProgressTables;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
@@ -29,7 +28,7 @@
 pub struct Inherited<'a, 'tcx> {
     pub(super) infcx: InferCtxt<'a, 'tcx>,
 
-    pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>,
+    pub(super) typeck_results: &'a RefCell<ty::TypeckResults<'tcx>>,
 
     pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
 
@@ -110,11 +109,11 @@ fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
         let tcx = infcx.tcx;
         let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
         let body_id = tcx.hir().maybe_body_owned_by(item_id);
+        let typeck_results =
+            infcx.in_progress_typeck_results.expect("building `FnCtxt` without typeck results");
 
         Inherited {
-            typeck_results: MaybeInProgressTables {
-                maybe_typeck_results: infcx.in_progress_typeck_results,
-            },
+            typeck_results,
             infcx,
             fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
             locals: RefCell::new(Default::default()),
index 416d33c7aa040501efc283bdb68677a35dd25adf..8f5f3657fc972eb628875867fc33a9deae88124d 100644 (file)
@@ -343,7 +343,7 @@ fn probe_op<OP, R>(
         OP: FnOnce(ProbeContext<'a, 'tcx>) -> Result<R, MethodError<'tcx>>,
     {
         let mut orig_values = OriginalQueryValues::default();
-        let param_env_and_self_ty = self.infcx.canonicalize_query(
+        let param_env_and_self_ty = self.canonicalize_query(
             ParamEnvAnd { param_env: self.param_env, value: self_ty },
             &mut orig_values,
         );
@@ -351,7 +351,7 @@ fn probe_op<OP, R>(
         let steps = if mode == Mode::MethodCall {
             self.tcx.method_autoderef_steps(param_env_and_self_ty)
         } else {
-            self.infcx.probe(|_| {
+            self.probe(|_| {
                 // Mode::Path - the deref steps is "trivial". This turns
                 // our CanonicalQuery into a "trivial" QueryResponse. This
                 // is a bit inefficient, but I don't think that writing
index 7f96e421a9ae366cbec4ebdbb0ec11c7c029a173..56fcd9e0a890743c93f6a118969957760ede4f31 100644 (file)
@@ -865,27 +865,26 @@ trait bound{s}",
                             .join("\n");
                         let actual_prefix = actual.prefix_string(self.tcx);
                         info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
-                        let (primary_message, label) = if unimplemented_traits.len() == 1
-                            && unimplemented_traits_only
-                        {
-                            unimplemented_traits
-                                .into_iter()
-                                .next()
-                                .map(|(_, (trait_ref, obligation))| {
-                                    if trait_ref.self_ty().references_error()
-                                        || actual.references_error()
-                                    {
-                                        // Avoid crashing.
-                                        return (None, None);
-                                    }
-                                    let OnUnimplementedNote { message, label, .. } =
-                                        self.infcx.on_unimplemented_note(trait_ref, &obligation);
-                                    (message, label)
-                                })
-                                .unwrap_or((None, None))
-                        } else {
-                            (None, None)
-                        };
+                        let (primary_message, label) =
+                            if unimplemented_traits.len() == 1 && unimplemented_traits_only {
+                                unimplemented_traits
+                                    .into_iter()
+                                    .next()
+                                    .map(|(_, (trait_ref, obligation))| {
+                                        if trait_ref.self_ty().references_error()
+                                            || actual.references_error()
+                                        {
+                                            // Avoid crashing.
+                                            return (None, None);
+                                        }
+                                        let OnUnimplementedNote { message, label, .. } =
+                                            self.on_unimplemented_note(trait_ref, &obligation);
+                                        (message, label)
+                                    })
+                                    .unwrap_or((None, None))
+                            } else {
+                                (None, None)
+                            };
                         let primary_message = primary_message.unwrap_or_else(|| format!(
                             "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
                         ));
@@ -1123,7 +1122,7 @@ trait bound{s}",
                          add a `use` for {one_of_them}:",
                         an = if candidates.len() == 1 { "an" } else { "" },
                         s = pluralize!(candidates.len()),
-                        were = if candidates.len() == 1 { "was" } else { "were" },
+                        were = pluralize!("was", candidates.len()),
                         one_of_them = if candidates.len() == 1 { "it" } else { "one_of_them" },
                     );
                     self.suggest_use_candidates(&mut err, help, candidates);
@@ -1648,7 +1647,7 @@ fn suggest_await_before_method(
         call: &hir::Expr<'_>,
         span: Span,
     ) {
-        let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
+        let output_ty = match self.get_impl_future_output_ty(ty) {
             Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(),
             _ => return,
         };
index b088fc9eddb85a14a3e84ef89fdc80824e2f1b0c..17c2e4868aac70e3e03eacd37fae0dc9d74b5a2d 100644 (file)
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
-
-use std::cell::{Ref, RefCell, RefMut};
+use std::cell::RefCell;
 
 use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
@@ -900,32 +899,6 @@ enum TupleArgumentsFlag {
     TupleArguments,
 }
 
-/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
-#[derive(Copy, Clone)]
-struct MaybeInProgressTables<'a, 'tcx> {
-    maybe_typeck_results: Option<&'a RefCell<ty::TypeckResults<'tcx>>>,
-}
-
-impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> {
-    fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> {
-        match self.maybe_typeck_results {
-            Some(typeck_results) => typeck_results.borrow(),
-            None => bug!(
-                "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results"
-            ),
-        }
-    }
-
-    fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> {
-        match self.maybe_typeck_results {
-            Some(typeck_results) => typeck_results.borrow_mut(),
-            None => bug!(
-                "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results"
-            ),
-        }
-    }
-}
-
 fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
     tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
 }
index 9858cd8fa1970c5a5128c0981799a74e884c5448..920b3e688089b1f1070c4737b695eaf47c7bf043 100644 (file)
@@ -475,7 +475,7 @@ fn check_overloaded_binop(
                         suggest_deref_binop(lhs_deref_ty);
                 } else if is_assign == IsAssign::No
                     && let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
-                    if self.infcx.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
+                    if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
                         suggest_deref_binop(*lhs_deref_ty);
                     }
                 }
@@ -523,7 +523,7 @@ fn check_overloaded_binop(
                                         _ => None,
                                     };
 
-                                    self.infcx.suggest_restricting_param_bound(
+                                    self.suggest_restricting_param_bound(
                                         &mut err,
                                         trait_pred,
                                         proj_pred,
@@ -740,7 +740,7 @@ pub fn check_user_unop(
                                 error.obligation.predicate.to_opt_poly_trait_pred()
                             });
                         for pred in predicates {
-                            self.infcx.suggest_restricting_param_bound(
+                            self.suggest_restricting_param_bound(
                                 &mut err,
                                 pred,
                                 None,
index d175d7e0695430733578ae30629142150783f84d..d72e215934a0d8626bbd9980fd6b315ce1df039c 100644 (file)
@@ -948,7 +948,7 @@ fn compute_2229_migrations_for_trait(
 
         let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?;
 
-        let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
+        let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id));
 
         let ty = match closure_clause {
             hir::CaptureBy::Value => ty, // For move closure the capture kind should be by value
@@ -1064,7 +1064,7 @@ fn compute_2229_migrations_for_drop(
         closure_clause: hir::CaptureBy,
         var_hir_id: hir::HirId,
     ) -> Option<FxHashSet<UpvarMigrationInfo>> {
-        let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
+        let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id));
 
         if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
             debug!("does not have significant drop");
index ca5defd16882a0aa1ccca568f5538bdb7ab126a0..bae986de9a23d64a48835a68b8c5b9c24fc7295b 100644 (file)
@@ -2,7 +2,7 @@
 use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
@@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
         unsatisfied_bounds.sort();
 
         if !unsatisfied_bounds.is_empty() {
-            let plural = if unsatisfied_bounds.len() > 1 { "s" } else { "" };
+            let plural = pluralize!(unsatisfied_bounds.len());
             let mut err = tcx.sess.struct_span_err(
                 gat_item_hir.span,
                 &format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
index d102fb45a8cbce446c3e77e239e66e85933a03c1..fa6053ac39585be8eddb6b49b5e5540251dcba6b 100644 (file)
@@ -748,7 +748,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
                 // (e.g. keep `for<'a>` named `for<'a>`).
                 // This allows NLL to generate error messages that
                 // refer to the higher-ranked lifetime names written by the user.
-                EraseEarlyRegions { tcx: self.infcx.tcx }.fold_ty(t)
+                EraseEarlyRegions { tcx: self.tcx }.fold_ty(t)
             }
             Err(_) => {
                 debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
@@ -766,7 +766,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         match self.infcx.fully_resolve(ct) {
-            Ok(ct) => self.infcx.tcx.erase_regions(ct),
+            Ok(ct) => self.tcx.erase_regions(ct),
             Err(_) => {
                 debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
                 self.report_const_error(ct);
index c562599e2cc53f748a0a0e658b34b413bba324eb..0e78c60ca5b6a5b6f3770754b80c74a6dffe6787 100644 (file)
@@ -2090,10 +2090,17 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
         // from the trait itself that *shouldn't* be shown as the source of
         // an obligation and instead be skipped. Otherwise we'd use
         // `tcx.def_span(def_id);`
+
+        let constness = if tcx.has_attr(def_id, sym::const_trait) {
+            ty::BoundConstness::ConstIfConst
+        } else {
+            ty::BoundConstness::NotConst
+        };
+
         let span = rustc_span::DUMMY_SP;
         result.predicates =
             tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(tcx),
+                ty::TraitRef::identity(tcx, def_id).with_constness(constness).to_predicate(tcx),
                 span,
             ))));
     }
@@ -2775,6 +2782,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
             }
         } else if attr.has_name(sym::rustc_allocator_nounwind) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+        } else if attr.has_name(sym::rustc_reallocator) {
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
+        } else if attr.has_name(sym::rustc_deallocator) {
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
+        } else if attr.has_name(sym::rustc_allocator_zeroed) {
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
         } else if attr.has_name(sym::naked) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
         } else if attr.has_name(sym::no_mangle) {
@@ -2843,7 +2856,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                     let is_like_elf = !(tcx.sess.target.is_like_osx
                         || tcx.sess.target.is_like_windows
                         || tcx.sess.target.is_like_wasm);
-                    codegen_fn_attrs.flags = if is_like_elf {
+                    codegen_fn_attrs.flags |= if is_like_elf {
                         CodegenFnAttrFlags::USED
                     } else {
                         CodegenFnAttrFlags::USED_LINKER
index faa4f3700bba8799b9346145659a9e91e04f30c7..64ac655e0c393f43cd5282bcc4dc3fe7b1dab3ee 100644 (file)
@@ -335,37 +335,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     tcx.mk_adt(def, substs)
                 }
                 ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
-                    find_opaque_ty_constraints(tcx, def_id)
+                    find_opaque_ty_constraints_for_tait(tcx, def_id)
                 }
                 // Opaque types desugared from `impl Trait`.
                 ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => {
-                    let concrete_ty = tcx
-                        .mir_borrowck(owner)
-                        .concrete_opaque_types
-                        .get(&def_id)
-                        .copied()
-                        .map(|concrete| concrete.ty)
-                        .unwrap_or_else(|| {
-                            let table = tcx.typeck(owner);
-                            if let Some(_) = table.tainted_by_errors {
-                                // Some error in the
-                                // owner fn prevented us from populating
-                                // the `concrete_opaque_types` table.
-                                tcx.ty_error()
-                            } else {
-                                table.concrete_opaque_types.get(&def_id).copied().unwrap_or_else(|| {
-                                    // We failed to resolve the opaque type or it
-                                    // resolves to itself. We interpret this as the
-                                    // no values of the hidden type ever being constructed,
-                                    // so we can just make the hidden type be `!`.
-                                    // For backwards compatibility reasons, we fall back to
-                                    // `()` until we the diverging default is changed.
-                                    Some(tcx.mk_diverging_default())
-                                }).expect("RPIT always have a hidden type from typeck")
-                            }
-                        });
-                    debug!("concrete_ty = {:?}", concrete_ty);
-                    concrete_ty
+                    find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
                 }
                 ItemKind::Trait(..)
                 | ItemKind::TraitAlias(..)
@@ -519,7 +493,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 /// fn b<T>() -> Foo<T, u32> { .. }
 /// ```
 ///
-fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
+fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
     use rustc_hir::{Expr, ImplItem, Item, TraitItem};
 
     struct ConstraintLocator<'tcx> {
@@ -538,9 +512,9 @@ struct ConstraintLocator<'tcx> {
 
     impl ConstraintLocator<'_> {
         #[instrument(skip(self), level = "debug")]
-        fn check(&mut self, def_id: LocalDefId) {
+        fn check(&mut self, item_def_id: LocalDefId) {
             // Don't try to check items that cannot possibly constrain the type.
-            if !self.tcx.has_typeck_results(def_id) {
+            if !self.tcx.has_typeck_results(item_def_id) {
                 debug!("no constraint: no typeck results");
                 return;
             }
@@ -555,26 +529,20 @@ fn check(&mut self, def_id: LocalDefId) {
             // // because we again need to reveal `Foo` so we can check whether the
             // // constant does not contain interior mutability.
             // ```
-            let tables = self.tcx.typeck(def_id);
+            let tables = self.tcx.typeck(item_def_id);
             if let Some(_) = tables.tainted_by_errors {
                 self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
                 return;
             }
-            if tables.concrete_opaque_types.get(&self.def_id).is_none() {
+            if !tables.concrete_opaque_types.contains_key(&self.def_id) {
                 debug!("no constraints in typeck results");
                 return;
             }
             // Use borrowck to get the type with unerased regions.
-            let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
+            let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
             debug!(?concrete_opaque_types);
-            for &(def_id, concrete_type) in concrete_opaque_types {
-                if def_id != self.def_id {
-                    // Ignore constraints for other opaque types.
-                    continue;
-                }
-
+            if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
                 debug!(?concrete_type, "found constraint");
-
                 if let Some(prev) = self.found {
                     if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
                         prev.report_mismatch(&concrete_type, self.tcx);
@@ -666,6 +634,122 @@ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
     }
 }
 
+fn find_opaque_ty_constraints_for_rpit(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+    owner_def_id: LocalDefId,
+) -> Ty<'_> {
+    use rustc_hir::{Expr, ImplItem, Item, TraitItem};
+
+    struct ConstraintChecker<'tcx> {
+        tcx: TyCtxt<'tcx>,
+
+        /// def_id of the opaque type whose defining uses are being checked
+        def_id: LocalDefId,
+
+        found: ty::OpaqueHiddenType<'tcx>,
+    }
+
+    impl ConstraintChecker<'_> {
+        #[instrument(skip(self), level = "debug")]
+        fn check(&self, def_id: LocalDefId) {
+            // Use borrowck to get the type with unerased regions.
+            let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
+            debug!(?concrete_opaque_types);
+            for &(def_id, concrete_type) in concrete_opaque_types {
+                if def_id != self.def_id {
+                    // Ignore constraints for other opaque types.
+                    continue;
+                }
+
+                debug!(?concrete_type, "found constraint");
+
+                if concrete_type.ty != self.found.ty
+                    && !(concrete_type, self.found).references_error()
+                {
+                    self.found.report_mismatch(&concrete_type, self.tcx);
+                }
+            }
+        }
+    }
+
+    impl<'tcx> intravisit::Visitor<'tcx> for ConstraintChecker<'tcx> {
+        type NestedFilter = nested_filter::OnlyBodies;
+
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.tcx.hir()
+        }
+        fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+            if let hir::ExprKind::Closure { .. } = ex.kind {
+                let def_id = self.tcx.hir().local_def_id(ex.hir_id);
+                self.check(def_id);
+            }
+            intravisit::walk_expr(self, ex);
+        }
+        fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
+            trace!(?it.def_id);
+            // The opaque type itself or its children are not within its reveal scope.
+            if it.def_id != self.def_id {
+                self.check(it.def_id);
+                intravisit::walk_item(self, it);
+            }
+        }
+        fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
+            trace!(?it.def_id);
+            // The opaque type itself or its children are not within its reveal scope.
+            if it.def_id != self.def_id {
+                self.check(it.def_id);
+                intravisit::walk_impl_item(self, it);
+            }
+        }
+        fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
+            trace!(?it.def_id);
+            self.check(it.def_id);
+            intravisit::walk_trait_item(self, it);
+        }
+    }
+
+    let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied();
+
+    if let Some(concrete) = concrete {
+        let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id);
+        debug!(?scope);
+        let mut locator = ConstraintChecker { def_id: def_id, tcx, found: concrete };
+
+        match tcx.hir().get(scope) {
+            Node::Item(it) => intravisit::walk_item(&mut locator, it),
+            Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it),
+            Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
+            other => bug!("{:?} is not a valid scope for an opaque type item", other),
+        }
+    }
+
+    concrete.map(|concrete| concrete.ty).unwrap_or_else(|| {
+        let table = tcx.typeck(owner_def_id);
+        if let Some(_) = table.tainted_by_errors {
+            // Some error in the
+            // owner fn prevented us from populating
+            // the `concrete_opaque_types` table.
+            tcx.ty_error()
+        } else {
+            table
+                .concrete_opaque_types
+                .get(&def_id)
+                .copied()
+                .unwrap_or_else(|| {
+                    // We failed to resolve the opaque type or it
+                    // resolves to itself. We interpret this as the
+                    // no values of the hidden type ever being constructed,
+                    // so we can just make the hidden type be `!`.
+                    // For backwards compatibility reasons, we fall back to
+                    // `()` until we the diverging default is changed.
+                    Some(tcx.mk_diverging_default())
+                })
+                .expect("RPIT always have a hidden type from typeck")
+        }
+    })
+}
+
 fn infer_placeholder_type<'a>(
     tcx: TyCtxt<'a>,
     def_id: LocalDefId,
index 4cdec615d8290352067207817dc8dd95ddff0823..0438ac02ea91a75fed88aa5e83d42b617667afa2 100644 (file)
@@ -244,7 +244,7 @@ pub struct UnconstrainedOpaqueType {
 pub struct MissingTypeParams {
     pub span: Span,
     pub def_span: Span,
-    pub missing_type_params: Vec<String>,
+    pub missing_type_params: Vec<Symbol>,
     pub empty_generic_args: bool,
 }
 
@@ -285,7 +285,15 @@ fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuar
                 err.span_suggestion(
                     self.span,
                     rustc_errors::fluent::typeck::suggestion,
-                    format!("{}<{}>", snippet, self.missing_type_params.join(", ")),
+                    format!(
+                        "{}<{}>",
+                        snippet,
+                        self.missing_type_params
+                            .iter()
+                            .map(|n| n.to_string())
+                            .collect::<Vec<_>>()
+                            .join(", ")
+                    ),
                     Applicability::HasPlaceholders,
                 );
                 suggested = true;
index 469f7d1172ae67ec7b0afd3bbe23a5d99ae49b00..99729391e02b0bc367510f9fb549857c556cb765 100644 (file)
@@ -420,12 +420,10 @@ fn create_error_message(&self) -> String {
         let provided_lt_args = self.num_provided_lifetime_args();
         let provided_type_or_const_args = self.num_provided_type_or_const_args();
 
-        let get_verb = |num_args| if num_args == 1 { "was" } else { "were" };
-
         let (provided_args_str, verb) = match self.gen_args_info {
             MissingLifetimes { .. } | ExcessLifetimes { .. } => (
                 format!("{} lifetime argument{}", provided_lt_args, pluralize!(provided_lt_args)),
-                get_verb(provided_lt_args),
+                pluralize!("was", provided_lt_args),
             ),
             MissingTypesOrConsts { .. } | ExcessTypesOrConsts { .. } => (
                 format!(
@@ -433,7 +431,7 @@ fn create_error_message(&self) -> String {
                     provided_type_or_const_args,
                     pluralize!(provided_type_or_const_args)
                 ),
-                get_verb(provided_type_or_const_args),
+                pluralize!("was", provided_type_or_const_args),
             ),
         };
 
index 7dc0f7cebd535e886446fc9898a573e2f666d229..72ac897d4f178d0236193de5f24c516cd1c6692f 100644 (file)
@@ -2,6 +2,7 @@
 // See https://github.com/rust-lang/rust/issues/73535#event-3477699747
 #![cfg(not(target_os = "android"))]
 #![feature(btree_drain_filter)]
+#![feature(iter_next_chunk)]
 #![feature(map_first_last)]
 #![feature(repr_simd)]
 #![feature(slice_partition_dedup)]
index efc47327e8a86d2fd89b8dec30bf076eb468750f..663f6b9dd1c9c038cbe3fbad3cbcb753329d27ec 100644 (file)
@@ -762,3 +762,23 @@ fn bench_retain_whole_100000(b: &mut Bencher) {
     let mut v = black_box(vec![826u32; 100000]);
     b.iter(|| v.retain(|x| *x == 826u32));
 }
+
+#[bench]
+fn bench_next_chunk(b: &mut Bencher) {
+    let v = vec![13u8; 2048];
+
+    b.iter(|| {
+        const CHUNK: usize = 8;
+
+        let mut sum = [0u32; CHUNK];
+        let mut iter = black_box(v.clone()).into_iter();
+
+        while let Ok(chunk) = iter.next_chunk::<CHUNK>() {
+            for i in 0..CHUNK {
+                sum[i] += chunk[i] as u32;
+            }
+        }
+
+        sum
+    })
+}
index efdc86bf57a8af6e1eb32f0092551da6fd0920e5..cc8da7bccff751b89aaacd76518ff88b88698ac8 100644 (file)
     // (the code expanding that attribute macro generates those functions), or to call
     // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
     // otherwise.
-    // The rustc fork of LLVM also special-cases these function names to be able to optimize them
+    // The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
     // like `malloc`, `realloc`, and `free`, respectively.
     #[rustc_allocator]
     #[rustc_allocator_nounwind]
     fn __rust_alloc(size: usize, align: usize) -> *mut u8;
+    #[cfg_attr(not(bootstrap), rustc_deallocator)]
     #[rustc_allocator_nounwind]
     fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
+    #[cfg_attr(not(bootstrap), rustc_reallocator)]
     #[rustc_allocator_nounwind]
     fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
+    #[cfg_attr(not(bootstrap), rustc_allocator_zeroed)]
     #[rustc_allocator_nounwind]
     fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
 }
index 315469387e5ae86a6499b90931382794df4f3d04..8b6f4054851dd454ae01fa96d2e4c7aa909c090b 100644 (file)
@@ -89,6 +89,7 @@
 #![feature(alloc_layout_extra)]
 #![feature(allocator_api)]
 #![feature(array_chunks)]
+#![feature(array_into_iter_constructors)]
 #![feature(array_methods)]
 #![feature(array_windows)]
 #![feature(assert_matches)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
+#![feature(iter_next_chunk)]
 #![feature(layout_for_ptr)]
+#![feature(maybe_uninit_array_assume_init)]
 #![feature(maybe_uninit_slice)]
+#![feature(maybe_uninit_uninit_array)]
 #![cfg_attr(test, feature(new_uninit))]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(pattern)]
index b1513e5e0f31c50db71835ad98ebc723e571a961..a5118e5333b825776e36a84ecb0b44f4f2523d3a 100644 (file)
 ///
 /// ```text
 /// 0
-/// 5
-/// 10
-/// 20
-/// 20
-/// 40
+/// 8
+/// 16
+/// 16
+/// 32
+/// 32
 /// ```
 ///
 /// At first, we have no memory allocated at all, but as we append to the
index 28979457b7fd389049ee21ef83308be1264949c5..1b483e3fc7793a499fcc236781eea1e5f96f8123 100644 (file)
@@ -2,13 +2,14 @@
 use super::AsVecIntoIter;
 use crate::alloc::{Allocator, Global};
 use crate::raw_vec::RawVec;
+use core::array;
 use core::fmt;
 use core::intrinsics::arith_offset;
 use core::iter::{
     FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
 };
 use core::marker::PhantomData;
-use core::mem::{self, ManuallyDrop};
+use core::mem::{self, ManuallyDrop, MaybeUninit};
 #[cfg(not(no_global_oom_handling))]
 use core::ops::Deref;
 use core::ptr::{self, NonNull};
@@ -124,7 +125,6 @@ pub(super) fn forget_allocation_drop_remaining(&mut self) {
     }
 
     /// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
-    #[cfg(not(no_global_oom_handling))]
     pub(crate) fn forget_remaining_elements(&mut self) {
         self.ptr = self.end;
     }
@@ -204,6 +204,43 @@ fn count(self) -> usize {
         self.len()
     }
 
+    #[inline]
+    fn next_chunk<const N: usize>(&mut self) -> Result<[T; N], core::array::IntoIter<T, N>> {
+        let mut raw_ary = MaybeUninit::uninit_array();
+
+        let len = self.len();
+
+        if mem::size_of::<T>() == 0 {
+            if len < N {
+                self.forget_remaining_elements();
+                // Safety: ZSTs can be conjured ex nihilo, only the amount has to be correct
+                return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) });
+            }
+
+            self.ptr = unsafe { arith_offset(self.ptr as *const i8, N as isize) as *mut T };
+            // Safety: ditto
+            return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) });
+        }
+
+        if len < N {
+            // Safety: `len` indicates that this many elements are available and we just checked that
+            // it fits into the array.
+            unsafe {
+                ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, len);
+                self.forget_remaining_elements();
+                return Err(array::IntoIter::new_unchecked(raw_ary, 0..len));
+            }
+        }
+
+        // Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize
+        // the array.
+        return unsafe {
+            ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, N);
+            self.ptr = self.ptr.add(N);
+            Ok(MaybeUninit::array_assume_init(raw_ary))
+        };
+    }
+
     unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
index c29e7b9c81efb0d985887809ccadaec3ff0d4092..d83cd29ddbad92e5d76b3694a7f87a7303265eed 100644 (file)
@@ -27,6 +27,7 @@
 #![feature(binary_heap_as_slice)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
+#![feature(iter_next_chunk)]
 #![feature(round_char_boundary)]
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
index 699567be5a004224252367d7c0daf4799b444d01..d94da8f5f5a0eac6731a298606f33715bd95f932 100644 (file)
@@ -1,4 +1,5 @@
 use core::alloc::{Allocator, Layout};
+use core::iter::IntoIterator;
 use core::ptr::NonNull;
 use std::alloc::System;
 use std::assert_matches::assert_matches;
@@ -930,6 +931,15 @@ fn test_into_iter_count() {
     assert_eq!([1, 2, 3].into_iter().count(), 3);
 }
 
+#[test]
+fn test_into_iter_next_chunk() {
+    let mut iter = b"lorem".to_vec().into_iter();
+
+    assert_eq!(iter.next_chunk().unwrap(), [b'l', b'o']); // N is inferred as 2
+    assert_eq!(iter.next_chunk().unwrap(), [b'r', b'e', b'm']); // N is inferred as 3
+    assert_eq!(iter.next_chunk::<4>().unwrap_err().as_slice(), &[]); // N is explicitly 4
+}
+
 #[test]
 fn test_into_iter_clone() {
     fn iter_equal<I: Iterator<Item = i32>>(it: I, slice: &[i32]) {
index 1d3466696ed0429a640dfd7b590b707b8f2abab3..20bb67687848fc1cb9c68dcdab594b2553743b39 100644 (file)
@@ -22,6 +22,8 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use crate::marker::Destruct;
+
 use self::Ordering::*;
 
 /// Trait for equality comparisons which are [partial equivalence
@@ -603,7 +605,8 @@ pub fn then_with<F: FnOnce() -> Ordering>(self, f: F) -> Ordering {
 pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T);
 
 #[stable(feature = "reverse_cmp_key", since = "1.19.0")]
-impl<T: PartialOrd> PartialOrd for Reverse<T> {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+impl<T: ~const PartialOrd> const PartialOrd for Reverse<T> {
     #[inline]
     fn partial_cmp(&self, other: &Reverse<T>) -> Option<Ordering> {
         other.0.partial_cmp(&self.0)
@@ -761,6 +764,7 @@ fn clone_from(&mut self, other: &Self) {
 #[doc(alias = ">=")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Ord"]
+#[const_trait]
 pub trait Ord: Eq + PartialOrd<Self> {
     /// This method returns an [`Ordering`] between `self` and `other`.
     ///
@@ -796,8 +800,15 @@ pub trait Ord: Eq + PartialOrd<Self> {
     fn max(self, other: Self) -> Self
     where
         Self: Sized,
+        Self: ~const Destruct,
     {
-        max_by(self, other, Ord::cmp)
+        // HACK(fee1-dead): go back to using `self.max_by(other, Ord::cmp)`
+        // when trait methods are allowed to be used when a const closure is
+        // expected.
+        match self.cmp(&other) {
+            Ordering::Less | Ordering::Equal => other,
+            Ordering::Greater => self,
+        }
     }
 
     /// Compares and returns the minimum of two values.
@@ -816,8 +827,15 @@ fn max(self, other: Self) -> Self
     fn min(self, other: Self) -> Self
     where
         Self: Sized,
+        Self: ~const Destruct,
     {
-        min_by(self, other, Ord::cmp)
+        // HACK(fee1-dead): go back to using `self.min_by(other, Ord::cmp)`
+        // when trait methods are allowed to be used when a const closure is
+        // expected.
+        match self.cmp(&other) {
+            Ordering::Less | Ordering::Equal => self,
+            Ordering::Greater => other,
+        }
     }
 
     /// Restrict a value to a certain interval.
@@ -841,6 +859,8 @@ fn min(self, other: Self) -> Self
     fn clamp(self, min: Self, max: Self) -> Self
     where
         Self: Sized,
+        Self: ~const Destruct,
+        Self: ~const PartialOrd,
     {
         assert!(min <= max);
         if self < min {
@@ -862,7 +882,8 @@ fn clamp(self, min: Self, max: Self) -> Self
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for Ordering {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+impl const Ord for Ordering {
     #[inline]
     fn cmp(&self, other: &Ordering) -> Ordering {
         (*self as i32).cmp(&(*other as i32))
@@ -870,7 +891,8 @@ fn cmp(&self, other: &Ordering) -> Ordering {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for Ordering {
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+impl const PartialOrd for Ordering {
     #[inline]
     fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
         (*self as i32).partial_cmp(&(*other as i32))
@@ -1187,8 +1209,9 @@ fn ge(&self, other: &Rhs) -> bool {
 #[inline]
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")]
-pub fn min<T: Ord>(v1: T, v2: T) -> T {
+pub const fn min<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
     v1.min(v2)
 }
 
@@ -1250,8 +1273,9 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")]
-pub fn max<T: Ord>(v1: T, v2: T) -> T {
+pub const fn max<T: ~const Ord + ~const Destruct>(v1: T, v2: T) -> T {
     v1.max(v2)
 }
 
@@ -1304,7 +1328,8 @@ mod impls {
     macro_rules! partial_eq_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl PartialEq for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+            impl const PartialEq for $t {
                 #[inline]
                 fn eq(&self, other: &$t) -> bool { (*self) == (*other) }
                 #[inline]
@@ -1314,7 +1339,8 @@ fn ne(&self, other: &$t) -> bool { (*self) != (*other) }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl PartialEq for () {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl const PartialEq for () {
         #[inline]
         fn eq(&self, _other: &()) -> bool {
             true
@@ -1341,7 +1367,8 @@ impl Eq for $t {}
     macro_rules! partial_ord_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl PartialOrd for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+            impl const PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
                     match (*self <= *other, *self >= *other) {
@@ -1364,7 +1391,8 @@ fn gt(&self, other: &$t) -> bool { (*self) > (*other) }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl PartialOrd for () {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl const PartialOrd for () {
         #[inline]
         fn partial_cmp(&self, _: &()) -> Option<Ordering> {
             Some(Equal)
@@ -1372,7 +1400,8 @@ fn partial_cmp(&self, _: &()) -> Option<Ordering> {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl PartialOrd for bool {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl const PartialOrd for bool {
         #[inline]
         fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
             Some(self.cmp(other))
@@ -1384,7 +1413,8 @@ fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
     macro_rules! ord_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl PartialOrd for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+            impl const PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
                     Some(self.cmp(other))
@@ -1400,7 +1430,8 @@ fn gt(&self, other: &$t) -> bool { (*self) > (*other) }
             }
 
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl Ord for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+            impl const Ord for $t {
                 #[inline]
                 fn cmp(&self, other: &$t) -> Ordering {
                     // The order here is important to generate more optimal assembly.
@@ -1414,7 +1445,8 @@ fn cmp(&self, other: &$t) -> Ordering {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl Ord for () {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl const Ord for () {
         #[inline]
         fn cmp(&self, _other: &()) -> Ordering {
             Equal
@@ -1422,7 +1454,8 @@ fn cmp(&self, _other: &()) -> Ordering {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl Ord for bool {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl const Ord for bool {
         #[inline]
         fn cmp(&self, other: &bool) -> Ordering {
             // Casting to i8's and converting the difference to an Ordering generates
@@ -1441,7 +1474,8 @@ fn cmp(&self, other: &bool) -> Ordering {
     ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl PartialEq for ! {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl const PartialEq for ! {
         fn eq(&self, _: &!) -> bool {
             *self
         }
@@ -1451,14 +1485,16 @@ fn eq(&self, _: &!) -> bool {
     impl Eq for ! {}
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl PartialOrd for ! {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl const PartialOrd for ! {
         fn partial_cmp(&self, _: &!) -> Option<Ordering> {
             *self
         }
     }
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl Ord for ! {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl const Ord for ! {
         fn cmp(&self, _: &!) -> Ordering {
             *self
         }
@@ -1467,9 +1503,10 @@ fn cmp(&self, _: &!) -> Ordering {
     // & pointers
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &A
+    #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
+    impl<A: ?Sized, B: ?Sized> const PartialEq<&B> for &A
     where
-        A: PartialEq<B>,
+        A: ~const PartialEq<B>,
     {
         #[inline]
         fn eq(&self, other: &&B) -> bool {
index 7ae1bfd4f351a1331d8fd14ddadaa2cefcd12ec9..81b6d5737ea753d9dd867e3a97f37fba3a22b5c9 100644 (file)
@@ -96,6 +96,7 @@
 #[inline]
 #[stable(feature = "unreachable", since = "1.27.0")]
 #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn unreachable_unchecked() -> ! {
     // SAFETY: the safety contract for `intrinsics::unreachable` must
     // be upheld by the caller.
index 9ae31a31aaad34c5cd697df3af9e374e449150dd..7e65f4ebdad8ae0c9ca4356559ce2469ec89b889 100644 (file)
@@ -2449,6 +2449,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
 #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
 #[inline]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
         #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
@@ -2535,6 +2536,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
 #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
 #[inline]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     extern "rust-intrinsic" {
         #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
@@ -2564,14 +2566,23 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 ///
 /// * `dst` must be properly aligned.
 ///
-/// Additionally, the caller must ensure that writing `count *
-/// size_of::<T>()` bytes to the given region of memory results in a valid
-/// value of `T`. Using a region of memory typed as a `T` that contains an
-/// invalid value of `T` is undefined behavior.
-///
 /// Note that even if the effectively copied size (`count * size_of::<T>()`) is
 /// `0`, the pointer must be non-null and properly aligned.
 ///
+/// Additionally, note that changing `*dst` in this way can easily lead to undefined behavior (UB)
+/// later if the written bytes are not a valid representation of some `T`. For instance, the
+/// following is an **incorrect** use of this function:
+///
+/// ```rust,no_run
+/// unsafe {
+///     let mut value: u8 = 0;
+///     let ptr: *mut bool = &mut value as *mut u8 as *mut bool;
+///     let _bool = ptr.read(); // This is fine, `ptr` points to a valid `bool`.
+///     ptr.write_bytes(42u8, 1); // This function itself does not cause UB...
+///     let _bool = ptr.read(); // ...but it makes this operation UB! ⚠️
+/// }
+/// ```
+///
 /// [valid]: crate::ptr#safety
 ///
 /// # Examples
@@ -2588,38 +2599,6 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 /// }
 /// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
 /// ```
-///
-/// Creating an invalid value:
-///
-/// ```
-/// use std::ptr;
-///
-/// let mut v = Box::new(0i32);
-///
-/// unsafe {
-///     // Leaks the previously held value by overwriting the `Box<T>` with
-///     // a null pointer.
-///     ptr::write_bytes(&mut v as *mut Box<i32>, 0, 1);
-/// }
-///
-/// // At this point, using or dropping `v` results in undefined behavior.
-/// // drop(v); // ERROR
-///
-/// // Even leaking `v` "uses" it, and hence is undefined behavior.
-/// // mem::forget(v); // ERROR
-///
-/// // In fact, `v` is invalid according to basic type layout invariants, so *any*
-/// // operation touching it is undefined behavior.
-/// // let v2 = v; // ERROR
-///
-/// unsafe {
-///     // Let us instead put in a valid value
-///     ptr::write(&mut v as *mut Box<i32>, Box::new(42i32));
-/// }
-///
-/// // Now the box is fine
-/// assert_eq!(*v, 42);
-/// ```
 #[doc(alias = "memset")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(bootstrap), rustc_allowed_through_unstable_modules)]
index f24a7ab61ae8903cd98dfdb3fcb1b992f8834220..30f2f0ee05c259db5508884732d1e14653f95990 100644 (file)
 #![feature(const_cell_into_inner)]
 #![feature(const_char_convert)]
 #![feature(const_clone)]
+#![feature(const_cmp)]
 #![feature(const_discriminant)]
 #![feature(const_eval_select)]
 #![feature(const_float_bits_conv)]
index 66af491607435f1d2d72c47fee787376c585237a..234fa213da89f4ee3101d15cd4d5a4752e7ab329 100644 (file)
@@ -1000,7 +1000,7 @@ pub fn copy<T: Copy>(x: &T) -> T {
 ///
 /// This function will unsafely assume the pointer `src` is valid for [`size_of::<U>`][size_of]
 /// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way
-/// that is correct even when `&U` makes stricter alignment requirements than `&T`). It will also
+/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also
 /// unsafely create a copy of the contained value instead of moving out of `src`.
 ///
 /// It is not a compile-time error if `T` and `U` have different sizes, but it
@@ -1124,6 +1124,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[stable(feature = "discriminant_value", since = "1.21.0")]
 #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")]
+#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
     Discriminant(intrinsics::discriminant_value(v))
 }
index eb458f3866e63181394b48b5444f3a794ce67180..a66de19bad0edb636f8f2f649cd607203c2a8c64 100644 (file)
@@ -449,6 +449,7 @@ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_add`.
@@ -517,6 +518,7 @@ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_sub`.
@@ -585,6 +587,7 @@ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_mul`.
@@ -757,6 +760,7 @@ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_shl`.
@@ -803,6 +807,7 @@ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_shr`.
index 715e78350a499d07566e00480d9ed75a2c8bbaa3..73365544233eb40815a87bea16d6abf8f8fe4360 100644 (file)
@@ -459,6 +459,7 @@ pub const fn checked_add(self, rhs: Self) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_add(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_add`.
@@ -528,6 +529,7 @@ pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_sub(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_sub`.
@@ -574,6 +576,7 @@ pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_mul(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_mul`.
@@ -933,6 +936,7 @@ pub const fn checked_shl(self, rhs: u32) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_shl`.
@@ -979,6 +983,7 @@ pub const fn checked_shr(self, rhs: u32) -> Option<Self> {
                       without modifying the original"]
         #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
         #[inline(always)]
+        #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
         pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
             // SAFETY: the caller must uphold the safety contract for
             // `unchecked_shr`.
index 6cdbab3058941c3938adb71106e1518b4f60be20..e0655d68d2cfa7922d2504cc830c4194d42fa5c3 100644 (file)
@@ -449,6 +449,7 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn offset(self, count: isize) -> *const T
     where
         T: Sized,
@@ -471,6 +472,7 @@ pub const fn to_raw_parts(self) -> (*const (), <T as super::Pointee>::Metadata)
     #[inline(always)]
     #[unstable(feature = "pointer_byte_offsets", issue = "96283")]
     #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset(self, count: isize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `offset`.
         let this = unsafe { self.cast::<u8>().offset(count).cast::<()>() };
@@ -641,6 +643,7 @@ pub const fn wrapping_byte_offset(self, count: isize) -> Self {
     #[stable(feature = "ptr_offset_from", since = "1.47.0")]
     #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
         T: Sized,
@@ -663,6 +666,7 @@ pub const fn wrapping_byte_offset(self, count: isize) -> Self {
     #[inline(always)]
     #[unstable(feature = "pointer_byte_offsets", issue = "96283")]
     #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize {
         // SAFETY: the caller must uphold the safety contract for `offset_from`.
         unsafe { self.cast::<u8>().offset_from(origin.cast::<u8>()) }
@@ -726,11 +730,12 @@ pub const fn wrapping_byte_offset(self, count: isize) -> Self {
     /// }
     ///
     /// // This would be incorrect, as the pointers are not correctly ordered:
-    /// // ptr1.offset_from(ptr2)
+    /// // ptr1.sub_ptr(ptr2)
     /// ```
     #[unstable(feature = "ptr_sub_ptr", issue = "95892")]
     #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub_ptr(self, origin: *const T) -> usize
     where
         T: Sized,
@@ -862,6 +867,7 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn add(self, count: usize) -> Self
     where
         T: Sized,
@@ -884,6 +890,7 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool
     #[inline(always)]
     #[unstable(feature = "pointer_byte_offsets", issue = "96283")]
     #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_add(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `add`.
         let this = unsafe { self.cast::<u8>().add(count).cast::<()>() };
@@ -946,6 +953,7 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub(self, count: usize) -> Self
     where
         T: Sized,
@@ -969,6 +977,7 @@ pub const fn guaranteed_ne(self, other: *const T) -> bool
     #[inline(always)]
     #[unstable(feature = "pointer_byte_offsets", issue = "96283")]
     #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_sub(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `sub`.
         let this = unsafe { self.cast::<u8>().sub(count).cast::<()>() };
@@ -1205,6 +1214,7 @@ pub unsafe fn read_volatile(self) -> T
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn copy_to(self, dest: *mut T, count: usize)
     where
         T: Sized,
@@ -1224,6 +1234,7 @@ pub unsafe fn read_volatile(self) -> T
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
     where
         T: Sized,
index e323f63115b85a7415bc12eebeca1c1719dda13d..fc3dd2a9b25a9efd646ec0143265b028e702321c 100644 (file)
@@ -461,6 +461,7 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn offset(self, count: isize) -> *mut T
     where
         T: Sized,
@@ -485,6 +486,7 @@ pub const fn to_raw_parts(self) -> (*mut (), <T as super::Pointee>::Metadata) {
     #[inline(always)]
     #[unstable(feature = "pointer_byte_offsets", issue = "96283")]
     #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset(self, count: isize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `offset`.
         let this = unsafe { self.cast::<u8>().offset(count).cast::<()>() };
@@ -824,6 +826,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[stable(feature = "ptr_offset_from", since = "1.47.0")]
     #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
         T: Sized,
@@ -844,6 +847,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[inline(always)]
     #[unstable(feature = "pointer_byte_offsets", issue = "96283")]
     #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_offset_from(self, origin: *const T) -> isize {
         // SAFETY: the caller must uphold the safety contract for `offset_from`.
         unsafe { self.cast::<u8>().offset_from(origin.cast::<u8>()) }
@@ -913,6 +917,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[unstable(feature = "ptr_sub_ptr", issue = "95892")]
     #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub_ptr(self, origin: *const T) -> usize
     where
         T: Sized,
@@ -976,6 +981,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn add(self, count: usize) -> Self
     where
         T: Sized,
@@ -998,6 +1004,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[inline(always)]
     #[unstable(feature = "pointer_byte_offsets", issue = "96283")]
     #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_add(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `add`.
         let this = unsafe { self.cast::<u8>().add(count).cast::<()>() };
@@ -1060,6 +1067,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[must_use = "returns a new pointer rather than modifying its argument"]
     #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
     #[inline]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn sub(self, count: usize) -> Self
     where
         T: Sized,
@@ -1083,6 +1091,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     #[inline(always)]
     #[unstable(feature = "pointer_byte_offsets", issue = "96283")]
     #[rustc_const_unstable(feature = "const_pointer_byte_offsets", issue = "96283")]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn byte_sub(self, count: usize) -> Self {
         // SAFETY: the caller must uphold the safety contract for `sub`.
         let this = unsafe { self.cast::<u8>().sub(count).cast::<()>() };
@@ -1319,6 +1328,7 @@ pub unsafe fn read_volatile(self) -> T
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn copy_to(self, dest: *mut T, count: usize)
     where
         T: Sized,
@@ -1338,6 +1348,7 @@ pub unsafe fn read_volatile(self) -> T
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
     where
         T: Sized,
@@ -1357,6 +1368,7 @@ pub unsafe fn read_volatile(self) -> T
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn copy_from(self, src: *const T, count: usize)
     where
         T: Sized,
@@ -1376,6 +1388,7 @@ pub unsafe fn read_volatile(self) -> T
     #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
     #[stable(feature = "pointer_methods", since = "1.26.0")]
     #[inline(always)]
+    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
     pub const unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
     where
         T: Sized,
index a1889e3d21cb88481f3a6231149a8d52bf6296eb..76b4a534e5db5b7989904ac479c42624e60e4a30 100644 (file)
@@ -1628,14 +1628,21 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for Chunks<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct ChunksMut<'a, T: 'a> {
-    v: &'a mut [T],
+    /// # Safety
+    /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
+    /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
+    /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
+    /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
+    /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
+    v: *mut [T],
     chunk_size: usize,
+    _marker: PhantomData<&'a mut T>,
 }
 
 impl<'a, T: 'a> ChunksMut<'a, T> {
     #[inline]
     pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
-        Self { v: slice, chunk_size: size }
+        Self { v: slice, chunk_size: size, _marker: PhantomData }
     }
 }
 
@@ -1649,10 +1656,11 @@ fn next(&mut self) -> Option<&'a mut [T]> {
             None
         } else {
             let sz = cmp::min(self.v.len(), self.chunk_size);
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(sz);
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (head, tail) = unsafe { self.v.split_at_mut(sz) };
             self.v = tail;
-            Some(head)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *head })
         }
     }
 
@@ -1684,11 +1692,13 @@ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
                 Some(sum) => cmp::min(self.v.len(), sum),
                 None => self.v.len(),
             };
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(end);
-            let (_, nth) = head.split_at_mut(start);
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (head, tail) = unsafe { self.v.split_at_mut(end) };
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (_, nth) = unsafe { head.split_at_mut(start) };
             self.v = tail;
-            Some(nth)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *nth })
         }
     }
 
@@ -1698,13 +1708,14 @@ fn last(self) -> Option<Self::Item> {
             None
         } else {
             let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
-            Some(&mut self.v[start..])
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *self.v.get_unchecked_mut(start..) })
         }
     }
 
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let start = idx * self.chunk_size;
-        // SAFETY: see comments for `Chunks::__iterator_get_unchecked`.
+        // SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`.
         //
         // Also note that the caller also guarantees that we're never called
         // with the same index again, and that no other methods that will
@@ -1726,12 +1737,12 @@ fn next_back(&mut self) -> Option<&'a mut [T]> {
         } else {
             let remainder = self.v.len() % self.chunk_size;
             let sz = if remainder != 0 { remainder } else { self.chunk_size };
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
+            let len = self.v.len();
             // SAFETY: Similar to `Chunks::next_back`
-            let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
+            let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) };
             self.v = head;
-            Some(tail)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *tail })
         }
     }
 
@@ -1747,10 +1758,13 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
                 Some(res) => cmp::min(self.v.len(), res),
                 None => self.v.len(),
             };
-            let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
-            let (head, nth_back) = temp.split_at_mut(start);
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (temp, _tail) = unsafe { self.v.split_at_mut(end) };
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (head, nth_back) = unsafe { temp.split_at_mut(start) };
             self.v = head;
-            Some(nth_back)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *nth_back })
         }
     }
 }
@@ -1956,9 +1970,16 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExact<'a, T> {
 #[stable(feature = "chunks_exact", since = "1.31.0")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct ChunksExactMut<'a, T: 'a> {
-    v: &'a mut [T],
-    rem: &'a mut [T],
+    /// # Safety
+    /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
+    /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
+    /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
+    /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
+    /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
+    v: *mut [T],
+    rem: &'a mut [T], // The iterator never yields from here, so this can be unique
     chunk_size: usize,
+    _marker: PhantomData<&'a mut T>,
 }
 
 impl<'a, T> ChunksExactMut<'a, T> {
@@ -1968,7 +1989,7 @@ pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self {
         let fst_len = slice.len() - rem;
         // SAFETY: 0 <= fst_len <= slice.len() by construction above
         let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) };
-        Self { v: fst, rem: snd, chunk_size }
+        Self { v: fst, rem: snd, chunk_size, _marker: PhantomData }
     }
 
     /// Returns the remainder of the original slice that is not going to be
@@ -1990,10 +2011,11 @@ fn next(&mut self) -> Option<&'a mut [T]> {
         if self.v.len() < self.chunk_size {
             None
         } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(self.chunk_size);
+            // SAFETY: self.chunk_size is inbounds because we compared above against self.v.len()
+            let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
             self.v = tail;
-            Some(head)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *head })
         }
     }
 
@@ -2015,8 +2037,8 @@ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
             self.v = &mut [];
             None
         } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (_, snd) = tmp.split_at_mut(start);
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (_, snd) = unsafe { self.v.split_at_mut(start) };
             self.v = snd;
             self.next()
         }
@@ -2029,7 +2051,7 @@ fn last(mut self) -> Option<Self::Item> {
 
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let start = idx * self.chunk_size;
-        // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`.
+        // SAFETY: see comments for `Chunks::__iterator_get_unchecked` and `self.v`.
         unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
     }
 }
@@ -2041,11 +2063,11 @@ fn next_back(&mut self) -> Option<&'a mut [T]> {
         if self.v.len() < self.chunk_size {
             None
         } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
+            // SAFETY: This subtraction is inbounds because of the check above
+            let (head, tail) = unsafe { self.v.split_at_mut(self.v.len() - self.chunk_size) };
             self.v = head;
-            Some(tail)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *tail })
         }
     }
 
@@ -2058,10 +2080,13 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
         } else {
             let start = (len - 1 - n) * self.chunk_size;
             let end = start + self.chunk_size;
-            let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
-            let (head, nth_back) = temp.split_at_mut(start);
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (temp, _tail) = unsafe { mem::replace(&mut self.v, &mut []).split_at_mut(end) };
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (head, nth_back) = unsafe { temp.split_at_mut(start) };
             self.v = head;
-            Some(nth_back)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *nth_back })
         }
     }
 }
@@ -2645,14 +2670,21 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunks<'a, T> {
 #[stable(feature = "rchunks", since = "1.31.0")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct RChunksMut<'a, T: 'a> {
-    v: &'a mut [T],
+    /// # Safety
+    /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
+    /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
+    /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
+    /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
+    /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
+    v: *mut [T],
     chunk_size: usize,
+    _marker: PhantomData<&'a mut T>,
 }
 
 impl<'a, T: 'a> RChunksMut<'a, T> {
     #[inline]
     pub(super) fn new(slice: &'a mut [T], size: usize) -> Self {
-        Self { v: slice, chunk_size: size }
+        Self { v: slice, chunk_size: size, _marker: PhantomData }
     }
 }
 
@@ -2666,16 +2698,16 @@ fn next(&mut self) -> Option<&'a mut [T]> {
             None
         } else {
             let sz = cmp::min(self.v.len(), self.chunk_size);
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
+            let len = self.v.len();
             // SAFETY: split_at_mut_unchecked just requires the argument be less
             // than the length. This could only happen if the expression
-            // `tmp_len - sz` overflows. This could only happen if `sz >
-            // tmp_len`, which is impossible as we initialize it as the `min` of
-            // `self.v.len()` (e.g. `tmp_len`) and `self.chunk_size`.
-            let (head, tail) = unsafe { tmp.split_at_mut_unchecked(tmp_len - sz) };
+            // `len - sz` overflows. This could only happen if `sz >
+            // len`, which is impossible as we initialize it as the `min` of
+            // `self.v.len()` (e.g. `len`) and `self.chunk_size`.
+            let (head, tail) = unsafe { self.v.split_at_mut_unchecked(len - sz) };
             self.v = head;
-            Some(tail)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *tail })
         }
     }
 
@@ -2709,11 +2741,15 @@ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
                 Some(sum) => sum,
                 None => 0,
             };
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(start);
-            let (nth, _) = tail.split_at_mut(end - start);
+            // SAFETY: This type ensures that self.v is a valid pointer with a correct len.
+            // Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
+            let (head, tail) = unsafe { self.v.split_at_mut(start) };
+            // SAFETY: This type ensures that self.v is a valid pointer with a correct len.
+            // Therefore the bounds check in split_at_mut guarantess the split point is inbounds.
+            let (nth, _) = unsafe { tail.split_at_mut(end - start) };
             self.v = head;
-            Some(nth)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *nth })
         }
     }
 
@@ -2724,7 +2760,8 @@ fn last(self) -> Option<Self::Item> {
         } else {
             let rem = self.v.len() % self.chunk_size;
             let end = if rem == 0 { self.chunk_size } else { rem };
-            Some(&mut self.v[0..end])
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *self.v.get_unchecked_mut(0..end) })
         }
     }
 
@@ -2735,7 +2772,7 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
             Some(start) => start,
         };
         // SAFETY: see comments for `RChunks::__iterator_get_unchecked` and
-        // `ChunksMut::__iterator_get_unchecked`
+        // `ChunksMut::__iterator_get_unchecked`, `self.v`.
         unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
     }
 }
@@ -2749,11 +2786,11 @@ fn next_back(&mut self) -> Option<&'a mut [T]> {
         } else {
             let remainder = self.v.len() % self.chunk_size;
             let sz = if remainder != 0 { remainder } else { self.chunk_size };
-            let tmp = mem::replace(&mut self.v, &mut []);
             // SAFETY: Similar to `Chunks::next_back`
-            let (head, tail) = unsafe { tmp.split_at_mut_unchecked(sz) };
+            let (head, tail) = unsafe { self.v.split_at_mut_unchecked(sz) };
             self.v = tail;
-            Some(head)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *head })
         }
     }
 
@@ -2768,10 +2805,13 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
             let offset_from_end = (len - 1 - n) * self.chunk_size;
             let end = self.v.len() - offset_from_end;
             let start = end.saturating_sub(self.chunk_size);
-            let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
-            let (_, nth_back) = tmp.split_at_mut(start);
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (tmp, tail) = unsafe { self.v.split_at_mut(end) };
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (_, nth_back) = unsafe { tmp.split_at_mut(start) };
             self.v = tail;
-            Some(nth_back)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *nth_back })
         }
     }
 }
@@ -2897,8 +2937,7 @@ fn last(mut self) -> Option<Self::Item> {
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let end = self.v.len() - idx * self.chunk_size;
         let start = end - self.chunk_size;
-        // SAFETY:
-        // SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`.
+        // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`.
         unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
     }
 }
@@ -2981,7 +3020,13 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExact<'a, T> {
 #[stable(feature = "rchunks", since = "1.31.0")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct RChunksExactMut<'a, T: 'a> {
-    v: &'a mut [T],
+    /// # Safety
+    /// This slice pointer must point at a valid region of `T` with at least length `v.len()`. Normally,
+    /// those requirements would mean that we could instead use a `&mut [T]` here, but we cannot
+    /// because `__iterator_get_unchecked` needs to return `&mut [T]`, which guarantees certain aliasing
+    /// properties that we cannot uphold if we hold on to the full original `&mut [T]`. Wrapping a raw
+    /// slice instead lets us hand out non-overlapping `&mut [T]` subslices of the slice we wrap.
+    v: *mut [T],
     rem: &'a mut [T],
     chunk_size: usize,
 }
@@ -3014,11 +3059,12 @@ fn next(&mut self) -> Option<&'a mut [T]> {
         if self.v.len() < self.chunk_size {
             None
         } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
+            let len = self.v.len();
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (head, tail) = unsafe { self.v.split_at_mut(len - self.chunk_size) };
             self.v = head;
-            Some(tail)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *tail })
         }
     }
 
@@ -3040,9 +3086,9 @@ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
             self.v = &mut [];
             None
         } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let tmp_len = tmp.len();
-            let (fst, _) = tmp.split_at_mut(tmp_len - end);
+            let len = self.v.len();
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (fst, _) = unsafe { self.v.split_at_mut(len - end) };
             self.v = fst;
             self.next()
         }
@@ -3056,7 +3102,7 @@ fn last(mut self) -> Option<Self::Item> {
     unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
         let end = self.v.len() - idx * self.chunk_size;
         let start = end - self.chunk_size;
-        // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`.
+        // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked` and `self.v`.
         unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
     }
 }
@@ -3068,10 +3114,11 @@ fn next_back(&mut self) -> Option<&'a mut [T]> {
         if self.v.len() < self.chunk_size {
             None
         } else {
-            let tmp = mem::replace(&mut self.v, &mut []);
-            let (head, tail) = tmp.split_at_mut(self.chunk_size);
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
             self.v = tail;
-            Some(head)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *head })
         }
     }
 
@@ -3087,10 +3134,13 @@ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
             let offset = (len - n) * self.chunk_size;
             let start = self.v.len() - offset;
             let end = start + self.chunk_size;
-            let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
-            let (_, nth_back) = tmp.split_at_mut(start);
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (tmp, tail) = unsafe { self.v.split_at_mut(end) };
+            // SAFETY: The self.v contract ensures that any split_at_mut is valid.
+            let (_, nth_back) = unsafe { tmp.split_at_mut(start) };
             self.v = tail;
-            Some(nth_back)
+            // SAFETY: Nothing else points to or will point to the contents of this slice.
+            Some(unsafe { &mut *nth_back })
         }
     }
 }
index 5751a91721d1fcee6c24caec5b13b5af5865fb56..6d1516958f39bd49b38217d196bcb1d11fb16c8c 100644 (file)
@@ -409,6 +409,50 @@ fn test_chunks_mut_zip() {
     assert_eq!(v1, [13, 14, 19, 20, 14]);
 }
 
+#[test]
+fn test_chunks_mut_zip_aliasing() {
+    let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+    let mut it = v1.chunks_mut(2).zip(v2.chunks(2));
+    let first = it.next().unwrap();
+    let _ = it.next().unwrap();
+    assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_chunks_exact_mut_zip_aliasing() {
+    let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+    let mut it = v1.chunks_exact_mut(2).zip(v2.chunks(2));
+    let first = it.next().unwrap();
+    let _ = it.next().unwrap();
+    assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_rchunks_mut_zip_aliasing() {
+    let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+    let mut it = v1.rchunks_mut(2).zip(v2.chunks(2));
+    let first = it.next().unwrap();
+    let _ = it.next().unwrap();
+    assert_eq!(first, (&mut [3, 4][..], &[6, 7][..]));
+}
+
+#[test]
+fn test_rchunks_exact_mut_zip_aliasing() {
+    let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let v2: &[i32] = &[6, 7, 8, 9, 10];
+
+    let mut it = v1.rchunks_exact_mut(2).zip(v2.chunks(2));
+    let first = it.next().unwrap();
+    let _ = it.next().unwrap();
+    assert_eq!(first, (&mut [3, 4][..], &[6, 7][..]));
+}
+
 #[test]
 fn test_chunks_exact_count() {
     let v: &[i32] = &[0, 1, 2, 3, 4, 5];
index 6a01b4a2e284178f3745b611eba69e265ac30c33..8801c670bc9795cf4179fa67d9178b26cafe315a 100644 (file)
@@ -37,12 +37,11 @@ pub unsafe fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
     abort();
 
     cfg_if::cfg_if! {
-        if #[cfg(unix)] {
+        if #[cfg(any(unix, target_os = "solid_asp3"))] {
             unsafe fn abort() -> ! {
                 libc::abort();
             }
         } else if #[cfg(any(target_os = "hermit",
-                            target_os = "solid_asp3",
                             all(target_vendor = "fortanix", target_env = "sgx")
         ))] {
             unsafe fn abort() -> ! {
index 08b45ac11a14c2b06f427874f96210f755bcbccf..8e478cd7bc8a2f9ade1430d59e247a4edbc295ce 100644 (file)
@@ -382,6 +382,14 @@ fn next(&mut self) -> Option<TokenTree> {
                 bridge::TokenTree::Literal(tt) => TokenTree::Literal(Literal(tt)),
             })
         }
+
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            self.0.size_hint()
+        }
+
+        fn count(self) -> usize {
+            self.0.count()
+        }
     }
 
     #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
index 989cec976b72fb58343247b9d51be3c0c5f27f7d..f7fbaa9c27649dfc9230079c7e5be6c095510246 100644 (file)
@@ -1,9 +1,10 @@
-use crate::cmp;
+mod buffer;
+
 use crate::fmt;
 use crate::io::{
     self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
 };
-use crate::mem::MaybeUninit;
+use buffer::Buffer;
 
 /// The `BufReader<R>` struct adds buffering to any reader.
 ///
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufReader<R> {
     inner: R,
-    buf: Box<[MaybeUninit<u8>]>,
-    pos: usize,
-    cap: usize,
-    init: usize,
+    buf: Buffer,
 }
 
 impl<R: Read> BufReader<R> {
@@ -93,8 +91,7 @@ pub fn new(inner: R) -> BufReader<R> {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
-        let buf = Box::new_uninit_slice(capacity);
-        BufReader { inner, buf, pos: 0, cap: 0, init: 0 }
+        BufReader { inner, buf: Buffer::with_capacity(capacity) }
     }
 }
 
@@ -170,8 +167,7 @@ pub fn get_mut(&mut self) -> &mut R {
     /// ```
     #[stable(feature = "bufreader_buffer", since = "1.37.0")]
     pub fn buffer(&self) -> &[u8] {
-        // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init
-        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) }
+        self.buf.buffer()
     }
 
     /// Returns the number of bytes the internal buffer can hold at once.
@@ -194,7 +190,7 @@ pub fn buffer(&self) -> &[u8] {
     /// ```
     #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
     pub fn capacity(&self) -> usize {
-        self.buf.len()
+        self.buf.capacity()
     }
 
     /// Unwraps this `BufReader<R>`, returning the underlying reader.
@@ -224,8 +220,7 @@ pub fn into_inner(self) -> R {
     /// Invalidates all data in the internal buffer.
     #[inline]
     fn discard_buffer(&mut self) {
-        self.pos = 0;
-        self.cap = 0;
+        self.buf.discard_buffer()
     }
 }
 
@@ -236,15 +231,15 @@ impl<R: Seek> BufReader<R> {
     /// must track this information themselves if it is required.
     #[stable(feature = "bufreader_seek_relative", since = "1.53.0")]
     pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
-        let pos = self.pos as u64;
+        let pos = self.buf.pos() as u64;
         if offset < 0 {
-            if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
-                self.pos = new_pos as usize;
+            if let Some(_) = pos.checked_sub((-offset) as u64) {
+                self.buf.unconsume((-offset) as usize);
                 return Ok(());
             }
         } else if let Some(new_pos) = pos.checked_add(offset as u64) {
-            if new_pos <= self.cap as u64 {
-                self.pos = new_pos as usize;
+            if new_pos <= self.buf.filled() as u64 {
+                self.buf.consume(offset as usize);
                 return Ok(());
             }
         }
@@ -259,7 +254,7 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         // If we don't have any buffered data and we're doing a massive read
         // (larger than our internal buffer), bypass our internal buffer
         // entirely.
-        if self.pos == self.cap && buf.len() >= self.buf.len() {
+        if self.buf.pos() == self.buf.filled() && buf.len() >= self.capacity() {
             self.discard_buffer();
             return self.inner.read(buf);
         }
@@ -275,7 +270,7 @@ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
         // If we don't have any buffered data and we're doing a massive read
         // (larger than our internal buffer), bypass our internal buffer
         // entirely.
-        if self.pos == self.cap && buf.remaining() >= self.buf.len() {
+        if self.buf.pos() == self.buf.filled() && buf.remaining() >= self.capacity() {
             self.discard_buffer();
             return self.inner.read_buf(buf);
         }
@@ -295,9 +290,7 @@ fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
     // generation for the common path where the buffer has enough bytes to fill the passed-in
     // buffer.
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
-        if self.buffer().len() >= buf.len() {
-            buf.copy_from_slice(&self.buffer()[..buf.len()]);
-            self.consume(buf.len());
+        if self.buf.consume_with(buf.len(), |claimed| buf.copy_from_slice(claimed)) {
             return Ok(());
         }
 
@@ -306,7 +299,7 @@ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
 
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
-        if self.pos == self.cap && total_len >= self.buf.len() {
+        if self.buf.pos() == self.buf.filled() && total_len >= self.capacity() {
             self.discard_buffer();
             return self.inner.read_vectored(bufs);
         }
@@ -325,8 +318,9 @@ fn is_read_vectored(&self) -> bool {
     // The inner reader might have an optimized `read_to_end`. Drain our buffer and then
     // delegate to the inner implementation.
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
-        let nread = self.cap - self.pos;
-        buf.extend_from_slice(&self.buffer());
+        let inner_buf = self.buffer();
+        buf.extend_from_slice(inner_buf);
+        let nread = inner_buf.len();
         self.discard_buffer();
         Ok(nread + self.inner.read_to_end(buf)?)
     }
@@ -371,33 +365,11 @@ fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<R: Read> BufRead for BufReader<R> {
     fn fill_buf(&mut self) -> io::Result<&[u8]> {
-        // If we've reached the end of our internal buffer then we need to fetch
-        // some more data from the underlying reader.
-        // Branch using `>=` instead of the more correct `==`
-        // to tell the compiler that the pos..cap slice is always valid.
-        if self.pos >= self.cap {
-            debug_assert!(self.pos == self.cap);
-
-            let mut readbuf = ReadBuf::uninit(&mut self.buf);
-
-            // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()`
-            // from the last time this function was called
-            unsafe {
-                readbuf.assume_init(self.init);
-            }
-
-            self.inner.read_buf(&mut readbuf)?;
-
-            self.cap = readbuf.filled_len();
-            self.init = readbuf.initialized_len();
-
-            self.pos = 0;
-        }
-        Ok(self.buffer())
+        self.buf.fill_buf(&mut self.inner)
     }
 
     fn consume(&mut self, amt: usize) {
-        self.pos = cmp::min(self.pos + amt, self.cap);
+        self.buf.consume(amt)
     }
 }
 
@@ -409,7 +381,10 @@ impl<R> fmt::Debug for BufReader<R>
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct("BufReader")
             .field("reader", &self.inner)
-            .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
+            .field(
+                "buffer",
+                &format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()),
+            )
             .finish()
     }
 }
@@ -441,7 +416,7 @@ impl<R: Seek> Seek for BufReader<R> {
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         let result: u64;
         if let SeekFrom::Current(n) = pos {
-            let remainder = (self.cap - self.pos) as i64;
+            let remainder = (self.buf.filled() - self.buf.pos()) as i64;
             // it should be safe to assume that remainder fits within an i64 as the alternative
             // means we managed to allocate 8 exbibytes and that's absurd.
             // But it's not out of the realm of possibility for some weird underlying reader to
@@ -499,7 +474,7 @@ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
     /// }
     /// ```
     fn stream_position(&mut self) -> io::Result<u64> {
-        let remainder = (self.cap - self.pos) as u64;
+        let remainder = (self.buf.filled() - self.buf.pos()) as u64;
         self.inner.stream_position().map(|pos| {
             pos.checked_sub(remainder).expect(
                 "overflow when subtracting remaining buffer size from inner stream position",
diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs
new file mode 100644 (file)
index 0000000..8ae01f3
--- /dev/null
@@ -0,0 +1,105 @@
+///! An encapsulation of `BufReader`'s buffer management logic.
+///
+/// This module factors out the basic functionality of `BufReader` in order to protect two core
+/// invariants:
+/// * `filled` bytes of `buf` are always initialized
+/// * `pos` is always <= `filled`
+/// Since this module encapsulates the buffer management logic, we can ensure that the range
+/// `pos..filled` is always a valid index into the initialized region of the buffer. This means
+/// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so
+/// without encountering any runtime bounds checks.
+use crate::cmp;
+use crate::io::{self, Read, ReadBuf};
+use crate::mem::MaybeUninit;
+
+pub struct Buffer {
+    // The buffer.
+    buf: Box<[MaybeUninit<u8>]>,
+    // The current seek offset into `buf`, must always be <= `filled`.
+    pos: usize,
+    // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
+    // initialized with bytes from a read.
+    filled: usize,
+}
+
+impl Buffer {
+    #[inline]
+    pub fn with_capacity(capacity: usize) -> Self {
+        let buf = Box::new_uninit_slice(capacity);
+        Self { buf, pos: 0, filled: 0 }
+    }
+
+    #[inline]
+    pub fn buffer(&self) -> &[u8] {
+        // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and
+        // that region is initialized because those are all invariants of this type.
+        unsafe { MaybeUninit::slice_assume_init_ref(self.buf.get_unchecked(self.pos..self.filled)) }
+    }
+
+    #[inline]
+    pub fn capacity(&self) -> usize {
+        self.buf.len()
+    }
+
+    #[inline]
+    pub fn filled(&self) -> usize {
+        self.filled
+    }
+
+    #[inline]
+    pub fn pos(&self) -> usize {
+        self.pos
+    }
+
+    #[inline]
+    pub fn discard_buffer(&mut self) {
+        self.pos = 0;
+        self.filled = 0;
+    }
+
+    #[inline]
+    pub fn consume(&mut self, amt: usize) {
+        self.pos = cmp::min(self.pos + amt, self.filled);
+    }
+
+    /// If there are `amt` bytes available in the buffer, pass a slice containing those bytes to
+    /// `visitor` and return true. If there are not enough bytes available, return false.
+    #[inline]
+    pub fn consume_with<V>(&mut self, amt: usize, mut visitor: V) -> bool
+    where
+        V: FnMut(&[u8]),
+    {
+        if let Some(claimed) = self.buffer().get(..amt) {
+            visitor(claimed);
+            // If the indexing into self.buffer() succeeds, amt must be a valid increment.
+            self.pos += amt;
+            true
+        } else {
+            false
+        }
+    }
+
+    #[inline]
+    pub fn unconsume(&mut self, amt: usize) {
+        self.pos = self.pos.saturating_sub(amt);
+    }
+
+    #[inline]
+    pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> {
+        // If we've reached the end of our internal buffer then we need to fetch
+        // some more data from the reader.
+        // Branch using `>=` instead of the more correct `==`
+        // to tell the compiler that the pos..cap slice is always valid.
+        if self.pos >= self.filled {
+            debug_assert!(self.pos == self.filled);
+
+            let mut readbuf = ReadBuf::uninit(&mut self.buf);
+
+            reader.read_buf(&mut readbuf)?;
+
+            self.filled = readbuf.filled_len();
+            self.pos = 0;
+        }
+        Ok(self.buffer())
+    }
+}
index 9d429e7090e83cb25cecd289af329e53be31ac40..fe45b1326384416239fd6c04ef767967698556fe 100644 (file)
@@ -523,6 +523,7 @@ fn bench_buffered_reader_small_reads(b: &mut test::Bencher) {
         let mut buf = [0u8; 4];
         for _ in 0..1024 {
             reader.read_exact(&mut buf).unwrap();
+            core::hint::black_box(&buf);
         }
     });
 }
index f4f2e3f2434574f1fc1faeb461e87d5a9c66f7df..96addbd1a0558c5273c2a3a2bf55a27c62d8411f 100644 (file)
@@ -898,7 +898,7 @@ fn by_ref(&mut self) -> &mut Self
     /// use std::fs::File;
     ///
     /// fn main() -> io::Result<()> {
-    ///     let mut f = File::open("foo.txt")?;
+    ///     let f = File::open("foo.txt")?;
     ///
     ///     for byte in f.bytes() {
     ///         println!("{}", byte.unwrap());
@@ -932,8 +932,8 @@ fn bytes(self) -> Bytes<Self>
     /// use std::fs::File;
     ///
     /// fn main() -> io::Result<()> {
-    ///     let mut f1 = File::open("foo.txt")?;
-    ///     let mut f2 = File::open("bar.txt")?;
+    ///     let f1 = File::open("foo.txt")?;
+    ///     let f2 = File::open("bar.txt")?;
     ///
     ///     let mut handle = f1.chain(f2);
     ///     let mut buffer = String::new();
@@ -973,7 +973,7 @@ fn chain<R: Read>(self, next: R) -> Chain<Self, R>
     /// use std::fs::File;
     ///
     /// fn main() -> io::Result<()> {
-    ///     let mut f = File::open("foo.txt")?;
+    ///     let f = File::open("foo.txt")?;
     ///     let mut buffer = [0; 5];
     ///
     ///     // read at most five bytes
@@ -2577,6 +2577,7 @@ fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
 
         let max = cmp::min(buf.len() as u64, self.limit) as usize;
         let n = self.inner.read(&mut buf[..max])?;
+        assert!(n as u64 <= self.limit, "number of read bytes exceeds limit");
         self.limit -= n as u64;
         Ok(n)
     }
index d5a8c93b0ce9f35cbc48a2b9300813be558e8582..f357f33ec52c54b771d2e89ec45df7633a3c353c 100644 (file)
@@ -583,6 +583,25 @@ fn test_write_all_vectored() {
     }
 }
 
+// Issue 94981
+#[test]
+#[should_panic = "number of read bytes exceeds limit"]
+fn test_take_wrong_length() {
+    struct LieAboutSize(bool);
+
+    impl Read for LieAboutSize {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            // Lie about the read size at first time of read.
+            if core::mem::take(&mut self.0) { Ok(buf.len() + 1) } else { Ok(buf.len()) }
+        }
+    }
+
+    let mut buffer = vec![0; 4];
+    let mut reader = LieAboutSize(true).take(4);
+    // Primed the `Limit` by lying about the read size.
+    let _ = reader.read(&mut buffer[..]);
+}
+
 #[bench]
 fn bench_take_read(b: &mut test::Bencher) {
     b.iter(|| {
index f15baff59dbfb589b0dec2f68fd235b14822da03..a091f06dd532cc14aaa5f4f75cae8c43264f8256 100644 (file)
@@ -7,6 +7,7 @@
 use crate::fs::{self, Metadata, OpenOptions};
 use crate::io;
 use crate::path::Path;
+use crate::sealed::Sealed;
 use crate::sys;
 use crate::sys_common::{AsInner, AsInnerMut};
 
@@ -502,17 +503,20 @@ fn file_index(&self) -> Option<u64> {
 /// Windows-specific extensions to [`fs::FileType`].
 ///
 /// On Windows, a symbolic link knows whether it is a file or directory.
-#[unstable(feature = "windows_file_type_ext", issue = "none")]
-pub trait FileTypeExt {
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+pub trait FileTypeExt: Sealed {
     /// Returns `true` if this file type is a symbolic link that is also a directory.
-    #[unstable(feature = "windows_file_type_ext", issue = "none")]
+    #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
     fn is_symlink_dir(&self) -> bool;
     /// Returns `true` if this file type is a symbolic link that is also a file.
-    #[unstable(feature = "windows_file_type_ext", issue = "none")]
+    #[stable(feature = "windows_file_type_ext", since = "1.64.0")]
     fn is_symlink_file(&self) -> bool;
 }
 
-#[unstable(feature = "windows_file_type_ext", issue = "none")]
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
+impl Sealed for fs::FileType {}
+
+#[stable(feature = "windows_file_type_ext", since = "1.64.0")]
 impl FileTypeExt for fs::FileType {
     fn is_symlink_dir(&self) -> bool {
         self.as_inner().is_symlink_dir()
index 1afc83f766df3e6bed0ad5d972509dd70005156e..8440d572cfbd3fe5d0e3eb3fd9325aa1d872c7c4 100644 (file)
@@ -4,32 +4,6 @@
 pub mod sockets;
 pub use self::fs::*;
 
-#[inline(always)]
-pub fn breakpoint_program_exited(tid: usize) {
-    unsafe {
-        match () {
-            // SOLID_BP_PROGRAM_EXITED = 15
-            #[cfg(target_arch = "arm")]
-            () => core::arch::asm!("bkpt #15", in("r0") tid),
-            #[cfg(target_arch = "aarch64")]
-            () => core::arch::asm!("hlt #15", in("x0") tid),
-        }
-    }
-}
-
-#[inline(always)]
-pub fn breakpoint_abort() {
-    unsafe {
-        match () {
-            // SOLID_BP_CSABORT = 16
-            #[cfg(target_arch = "arm")]
-            () => core::arch::asm!("bkpt #16"),
-            #[cfg(target_arch = "aarch64")]
-            () => core::arch::asm!("hlt #16"),
-        }
-    }
-}
-
 // `solid_types.h`
 pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID};
 
index 2d21e4764fc210a21ecb23341ab64c5ed4160811..778a589d1b724434f38d6f90eb51c370039f6027 100644 (file)
@@ -76,20 +76,9 @@ pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
     error::decode_error_kind(code)
 }
 
-#[inline(always)]
+#[inline]
 pub fn abort_internal() -> ! {
-    loop {
-        abi::breakpoint_abort();
-    }
-}
-
-// This function is needed by the panic runtime. The symbol is named in
-// pre-link args for the target specification, so keep that in sync.
-#[cfg(not(test))]
-#[no_mangle]
-// NB. used by both libunwind and libpanic_abort
-pub extern "C" fn __rust_abort() {
-    abort_internal();
+    unsafe { libc::abort() }
 }
 
 pub fn hashmap_random_keys() -> (u64, u64) {
index 719d95bbe50a81f49ce1b1ad12ed8da032044399..b5649d6e0ffb0cb24c1606a78dd752374d4d47a3 100644 (file)
@@ -11,7 +11,7 @@
 use crate::sys_common::rwlock::StaticRwLock;
 use crate::vec;
 
-use super::{abi, error, itron, memchr};
+use super::{error, itron, memchr};
 
 // `solid` directly maps `errno`s to μITRON error codes.
 impl itron::error::ItronError {
@@ -184,11 +184,8 @@ pub fn home_dir() -> Option<PathBuf> {
     None
 }
 
-pub fn exit(_code: i32) -> ! {
-    let tid = itron::task::try_current_task_id().unwrap_or(0);
-    loop {
-        abi::breakpoint_program_exited(tid as usize);
-    }
+pub fn exit(code: i32) -> ! {
+    rtabort!("exit({}) called", code);
 }
 
 pub fn getpid() -> u32 {
index 7c8824694408c65d3fcc78970833d2b984876a55..71522865b7dcfda18c64d19ba91ec7b036150f2f 100644 (file)
@@ -1126,6 +1126,19 @@ fn get_path(fd: c_int) -> Option<PathBuf> {
             Some(PathBuf::from(OsString::from_vec(buf)))
         }
 
+        #[cfg(all(target_os = "freebsd", target_arch = "x86_64"))]
+        fn get_path(fd: c_int) -> Option<PathBuf> {
+            let info = Box::<libc::kinfo_file>::new_zeroed();
+            let mut info = unsafe { info.assume_init() };
+            info.kf_structsize = mem::size_of::<libc::kinfo_file>() as libc::c_int;
+            let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) };
+            if n == -1 {
+                return None;
+            }
+            let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() };
+            Some(PathBuf::from(OsString::from_vec(buf)))
+        }
+
         #[cfg(target_os = "vxworks")]
         fn get_path(fd: c_int) -> Option<PathBuf> {
             let mut buf = vec![0; libc::PATH_MAX as usize];
@@ -1142,6 +1155,7 @@ fn get_path(fd: c_int) -> Option<PathBuf> {
             target_os = "linux",
             target_os = "macos",
             target_os = "vxworks",
+            all(target_os = "freebsd", target_arch = "x86_64"),
             target_os = "netbsd"
         )))]
         fn get_path(_fd: c_int) -> Option<PathBuf> {
index 3d678b2290d1c7dd3f8983394e0dbb524bb195c7..aa7cda46bda69460406d134031c535bef05acc15 100644 (file)
@@ -651,6 +651,12 @@ fn run(self, builder: &Builder<'_>) {
             panic!("Cannot use and generate PGO profiles at the same time");
         }
 
+        // With LLD, we can use ICF (identical code folding) to reduce the executable size
+        // of librustc_driver/rustc and to improve i-cache utilization.
+        if builder.config.use_lld {
+            cargo.rustflag("-Clink-args=-Wl,--icf=all");
+        }
+
         let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
             if compiler.stage == 1 {
                 cargo.rustflag(&format!("-Cprofile-generate={}", path));
index ea0f78e2a6be9da2c9461497e2bafb53ca18b6ec..c7212ad2c21665160df2edf44b1aa5509b110d5a 100644 (file)
@@ -411,7 +411,11 @@ pub struct Target {
 impl Target {
     pub fn from_triple(triple: &str) -> Self {
         let mut target: Self = Default::default();
-        if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") {
+        if triple.contains("-none")
+            || triple.contains("nvptx")
+            || triple.contains("switch")
+            || triple.contains("-uefi")
+        {
             target.no_std = true;
         }
         target
index ab6c888030e1bf783f863aadcc2cbf695fce5876..f262bc3c7d8d2112f04555861a5cccfec888a663 100644 (file)
@@ -122,7 +122,8 @@ ENV RUST_CONFIGURE_ARGS \
       --set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \
       --set llvm.thin-lto=true \
       --set llvm.ninja=false \
-      --set rust.jemalloc
+      --set rust.jemalloc \
+      --set rust.use-lld=true
 ENV SCRIPT ../src/ci/pgo.sh python3 ../x.py dist \
     --host $HOSTS --target $HOSTS \
     --include-default-paths \
index 28bed1fa0353b3cc1778bee81dcaee1d44fbd0a6..4773dc09960a00a599604b4f6dd987c3343dbdfd 100755 (executable)
@@ -195,3 +195,7 @@ rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld
 $@ \
     --rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \
     --llvm-profile-use=${LLVM_PROFILE_MERGED_FILE}
+
+echo "Rustc binary size"
+ls -la ./build/$PGO_HOST/stage2/bin
+ls -la ./build/$PGO_HOST/stage2/lib
index 2bc6e8fc8ae4df6606001b710e7793f585fcc4ba..9438948af544a86a22fac07b7d79b87b2777ce97 100644 (file)
@@ -10,4 +10,4 @@ change in any release.
 
 In the past the most common use case for customizing passes was to omit the `strip-private` pass.
 You can do this more easily, and without risk of the pass being changed, by passing
-[`--document-private-items`](./unstable-features.md#--document-private-items).
+[`--document-private-items`](command-line-arguments.md#--document-private-items-show-items-that-are-not-public).
index 30b3d6defb4b86e0636957e41159eacb38d9acef..32b350074903e14e24e62212020e052c18be7183 100644 (file)
@@ -466,7 +466,7 @@ Note that the third item is the crate root, which in this case is undocumented.
 and is also accepted on stable toolchains.
 
 It can also be used with `--show-coverage`. Take a look at its
-[documentation](#--show-coverage-get-statistics-about-code-documentation-coverage) for more
+[documentation](#--show-coverage-calculate-the-percentage-of-items-with-documentation) for more
 information.
 
 ### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
index 0bd72625f150989e21579681e2e6b98ad3277518..ddaa7438e1778e5b32d743faa1b05f62fe8c1e05 100644 (file)
@@ -10,7 +10,7 @@ path = "lib.rs"
 arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.11", default-features = false, features = ["config"] }
 atty = "0.2"
-pulldown-cmark = { version = "0.9", default-features = false }
+pulldown-cmark = { version = "0.9.2", default-features = false }
 minifier = "0.2.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
index c9ef4748a48451619cadda1289bbd09d54d5d97e..2f3ca41723d8558ff9c3570576103d4dee5571f2 100644 (file)
@@ -327,10 +327,12 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
         let bound_predicate = self.kind();
         match bound_predicate.skip_binder() {
-            ty::PredicateKind::Trait(pred) => bound_predicate.rebind(pred).clean(cx),
-            ty::PredicateKind::RegionOutlives(pred) => pred.clean(cx),
-            ty::PredicateKind::TypeOutlives(pred) => pred.clean(cx),
-            ty::PredicateKind::Projection(pred) => Some(pred.clean(cx)),
+            ty::PredicateKind::Trait(pred) => {
+                clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
+            }
+            ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred, cx),
+            ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
+            ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
             ty::PredicateKind::ConstEvaluatable(..) => None,
             ty::PredicateKind::WellFormed(..) => None,
 
@@ -344,57 +346,56 @@ fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
     }
 }
 
-impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::PolyTraitPredicate<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
-        // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
-        if self.skip_binder().constness == ty::BoundConstness::ConstIfConst
-            && Some(self.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
-        {
-            return None;
-        }
-
-        let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
-        Some(WherePredicate::BoundPredicate {
-            ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
-            bounds: vec![poly_trait_ref.clean(cx)],
-            bound_params: Vec::new(),
-        })
+fn clean_poly_trait_predicate<'tcx>(
+    pred: ty::PolyTraitPredicate<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+    // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
+    if pred.skip_binder().constness == ty::BoundConstness::ConstIfConst
+        && Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
+    {
+        return None;
     }
-}
 
-impl<'tcx> Clean<'tcx, Option<WherePredicate>>
-    for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
-{
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
-        let ty::OutlivesPredicate(a, b) = self;
+    let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
+    Some(WherePredicate::BoundPredicate {
+        ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
+        bounds: vec![poly_trait_ref.clean(cx)],
+        bound_params: Vec::new(),
+    })
+}
 
-        if a.is_empty() && b.is_empty() {
-            return None;
-        }
+fn clean_region_outlives_predicate<'tcx>(
+    pred: ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+    let ty::OutlivesPredicate(a, b) = pred;
 
-        Some(WherePredicate::RegionPredicate {
-            lifetime: a.clean(cx).expect("failed to clean lifetime"),
-            bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))],
-        })
+    if a.is_empty() && b.is_empty() {
+        return None;
     }
-}
 
-impl<'tcx> Clean<'tcx, Option<WherePredicate>>
-    for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>
-{
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
-        let ty::OutlivesPredicate(ty, lt) = self;
+    Some(WherePredicate::RegionPredicate {
+        lifetime: a.clean(cx).expect("failed to clean lifetime"),
+        bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))],
+    })
+}
 
-        if lt.is_empty() {
-            return None;
-        }
+fn clean_type_outlives_predicate<'tcx>(
+    pred: ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+    let ty::OutlivesPredicate(ty, lt) = pred;
 
-        Some(WherePredicate::BoundPredicate {
-            ty: clean_middle_ty(*ty, cx, None),
-            bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
-            bound_params: Vec::new(),
-        })
+    if lt.is_empty() {
+        return None;
     }
+
+    Some(WherePredicate::BoundPredicate {
+        ty: clean_middle_ty(ty, cx, None),
+        bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
+        bound_params: Vec::new(),
+    })
 }
 
 impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> {
@@ -418,10 +419,14 @@ fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
     }
 }
 
-impl<'tcx> Clean<'tcx, WherePredicate> for ty::ProjectionPredicate<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> WherePredicate {
-        let ty::ProjectionPredicate { projection_ty, term } = self;
-        WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
+fn clean_projection_predicate<'tcx>(
+    pred: ty::ProjectionPredicate<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> WherePredicate {
+    let ty::ProjectionPredicate { projection_ty, term } = pred;
+    WherePredicate::EqPredicate {
+        lhs: clean_projection(projection_ty, cx, None),
+        rhs: term.clean(cx),
     }
 }
 
@@ -447,12 +452,6 @@ fn clean_projection<'tcx>(
     }
 }
 
-impl<'tcx> Clean<'tcx, Type> for ty::ProjectionTy<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Type {
-        clean_projection(*self, cx, None)
-    }
-}
-
 fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
     !trait_.segments.is_empty()
         && self_def_id
@@ -734,8 +733,12 @@ fn clean_ty_generics<'tcx>(
                             .filter(|b| !b.is_sized_bound(cx)),
                     );
 
-                    let proj = projection
-                        .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
+                    let proj = projection.map(|p| {
+                        (
+                            clean_projection(p.skip_binder().projection_ty, cx, None),
+                            p.skip_binder().term,
+                        )
+                    });
                     if let Some(((_, trait_did, name), rhs)) = proj
                         .as_ref()
                         .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs)))
@@ -1993,6 +1996,7 @@ fn clean_maybe_renamed_item<'tcx>(
             ItemKind::Trait(_, _, generics, bounds, item_ids) => {
                 let items =
                     item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+
                 TraitItem(Trait {
                     def_id,
                     items,
index 2d364f3402e9630f3958987abc9fbabd2217ad08..83d8ed3fc87fb6a0d8cf112f6c9def6b5ee0db24 100644 (file)
@@ -2175,8 +2175,8 @@ pub(crate) fn last(&self) -> Symbol {
     pub(crate) fn whole_name(&self) -> String {
         self.segments
             .iter()
-            .map(|s| if s.name == kw::PathRoot { String::new() } else { s.name.to_string() })
-            .intersperse("::".into())
+            .map(|s| if s.name == kw::PathRoot { "" } else { s.name.as_str() })
+            .intersperse("::")
             .collect()
     }
 
index 4170c73b246252314dd4aa6ea24daf03a9159ee8..52a2effca0ff7957db687d69d1a8eae9df941269 100644 (file)
@@ -1485,6 +1485,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("synthetic-implementations-list".into(), 1);
     map.insert("blanket-implementations-list".into(), 1);
     map.insert("deref-methods".into(), 1);
+    map.insert("layout".into(), 1);
     map
 }
 
index 81cc12c9d55961dc23407e07c9488d00ee6ec7d2..69d66693f752e92b9528917f15f82aad73c22696 100644 (file)
@@ -1,9 +1,5 @@
 use clean::AttributesExt;
 
-use std::cmp::Ordering;
-use std::fmt;
-use std::rc::Rc;
-
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
@@ -15,6 +11,9 @@
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants};
+use std::cmp::Ordering;
+use std::fmt;
+use std::rc::Rc;
 
 use super::{
     collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section,
@@ -37,6 +36,7 @@
 use crate::html::url_parts_builder::UrlPartsBuilder;
 
 use askama::Template;
+use itertools::Itertools;
 
 const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
 const ITEM_TABLE_CLOSE: &str = "</div>";
@@ -539,6 +539,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
     let count_types = required_types.len() + provided_types.len();
     let count_consts = required_consts.len() + provided_consts.len();
     let count_methods = required_methods.len() + provided_methods.len();
+    let must_implement_one_of_functions =
+        cx.tcx().trait_def(t.def_id).must_implement_one_of.clone();
 
     // Output the trait definition
     wrap_into_docblock(w, |w| {
@@ -784,13 +786,22 @@ fn trait_item(w: &mut Buffer, cx: &mut Context<'_>, m: &clean::Item, t: &clean::
     }
 
     // Output the documentation for each function individually
-    if !required_methods.is_empty() {
+    if !required_methods.is_empty() || must_implement_one_of_functions.is_some() {
         write_small_section_header(
             w,
             "required-methods",
             "Required Methods",
             "<div class=\"methods\">",
         );
+
+        if let Some(list) = must_implement_one_of_functions.as_deref() {
+            write!(
+                w,
+                "<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>",
+                list.iter().join("`, `")
+            );
+        }
+
         for m in required_methods {
             trait_item(w, cx, m, it);
         }
@@ -1869,7 +1880,11 @@ fn write_size_of_layout(w: &mut Buffer, layout: Layout<'_>, tag_size: u64) {
         return;
     }
 
-    writeln!(w, "<h2 class=\"small-section-header\">Layout</h2>");
+    writeln!(
+        w,
+        "<h2 id=\"layout\" class=\"small-section-header\"> \
+        Layout<a href=\"#layout\" class=\"anchor\"></a></h2>"
+    );
     writeln!(w, "<div class=\"docblock\">");
 
     let tcx = cx.tcx();
index 70b7a47bcd58bf65aca0bfba557d6b5db0931552..025157713498e07c4d2afe68689d4546a95e85bd 100644 (file)
@@ -1855,7 +1855,6 @@ in storage.js plus the media query with (min-width: 701px)
                   the sidebar stays visible for screen readers, which is useful for navigation. */
                left: -1000px;
                margin-left: 0;
-               background-color: rgba(0,0,0,0);
                margin: 0;
                padding: 0;
                z-index: 11;
index 7ff8063904acef718711d7c9c8913fc0c798c232..c42cac59bd6fa36f43bf262b9ae74b15478d91da 100644 (file)
@@ -205,11 +205,13 @@ details.rustdoc-toggle > summary::before {
 
 /* Created this empty rule to satisfy the theme checks. */
 .stab.empty-impl {}
+.stab.must_implement {}
 
 .stab.unstable,
 .stab.deprecated,
 .stab.portability,
-.stab.empty-impl {
+.stab.empty-impl,
+.stab.must_implement {
        color: #c5c5c5;
        background: #314559 !important;
        border-style: none !important;
index 8e753f57682063d8598013ddeb4e46c244840d7a..62d9eaa02e6a7e645b8969972c1d199e087b6f81 100644 (file)
@@ -180,6 +180,7 @@ details.rustdoc-toggle > summary::before {
 .stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
 .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; }
+.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
 .stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
 .stab.portability > code { background: none; }
 
index 40d965c39c390a0fb48bb895667592b4cd3adcf2..b751acff152cb4b2863fcd600999bc4c57728033 100644 (file)
@@ -163,6 +163,7 @@ details.rustdoc-toggle > summary::before {
 .stab.empty-impl { background: #FFF5D6; border-color: #FFC600; }
 .stab.unstable { background: #FFF5D6; border-color: #FFC600; }
 .stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
+.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; }
 .stab.portability { background: #F3DFFF; border-color: #b07bdb; }
 .stab.portability > code { background: none; }
 
diff --git a/src/test/codegen/box-maybe-uninit-llvm14.rs b/src/test/codegen/box-maybe-uninit-llvm14.rs
new file mode 100644 (file)
index 0000000..bd1a659
--- /dev/null
@@ -0,0 +1,26 @@
+// compile-flags: -O
+
+// Once we're done with llvm 14 and earlier, this test can be deleted.
+
+#![crate_type="lib"]
+
+use std::mem::MaybeUninit;
+
+// Boxing a `MaybeUninit` value should not copy junk from the stack
+#[no_mangle]
+pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
+    // CHECK-LABEL: @box_uninitialized
+    // CHECK-NOT: store
+    // CHECK-NOT: alloca
+    // CHECK-NOT: memcpy
+    // CHECK-NOT: memset
+    Box::new(MaybeUninit::uninit())
+}
+
+// FIXME: add a test for a bigger box. Currently broken, see
+// https://github.com/rust-lang/rust/issues/58201.
+
+// Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
+// from the CHECK-NOT above. We don't check the attributes here because we can't rely
+// on all of them being set until LLVM 15.
+// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+.*}})
index 5004f787cde190725b2b5d3b69a117a319fcb0a6..e105e26f16a23c6db15cc840c45a946b8794e4ed 100644 (file)
@@ -1,4 +1,5 @@
 // compile-flags: -O
+// min-llvm-version: 15.0
 #![crate_type="lib"]
 
 use std::mem::MaybeUninit;
@@ -16,3 +17,9 @@ pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
 
 // FIXME: add a test for a bigger box. Currently broken, see
 // https://github.com/rust-lang/rust/issues/58201.
+
+// Hide the `allocalign` attribute in the declaration of __rust_alloc
+// from the CHECK-NOT above, and also verify the attributes got set reasonably.
+// CHECK: declare noalias ptr @__rust_alloc(i{{[0-9]+}}, i{{[0-9]+}} allocalign) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
+
+// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
diff --git a/src/test/codegen/vec-calloc-llvm14.rs b/src/test/codegen/vec-calloc-llvm14.rs
new file mode 100644 (file)
index 0000000..0830279
--- /dev/null
@@ -0,0 +1,144 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @vec_zero_bytes
+#[no_mangle]
+pub fn vec_zero_bytes(n: usize) -> Vec<u8> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+    // CHECK-NOT: call {{.*}}llvm.memset
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+    // CHECK-NOT: call {{.*}}llvm.memset
+
+    // CHECK: ret void
+    vec![0; n]
+}
+
+// CHECK-LABEL: @vec_one_bytes
+#[no_mangle]
+pub fn vec_one_bytes(n: usize) -> Vec<u8> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: call {{.*}}__rust_alloc(
+    // CHECK: call {{.*}}llvm.memset
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: ret void
+    vec![1; n]
+}
+
+// CHECK-LABEL: @vec_zero_scalar
+#[no_mangle]
+pub fn vec_zero_scalar(n: usize) -> Vec<i32> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![0; n]
+}
+
+// CHECK-LABEL: @vec_one_scalar
+#[no_mangle]
+pub fn vec_one_scalar(n: usize) -> Vec<i32> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: call {{.*}}__rust_alloc(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: ret void
+    vec![1; n]
+}
+
+// CHECK-LABEL: @vec_zero_rgb48
+#[no_mangle]
+pub fn vec_zero_rgb48(n: usize) -> Vec<[u16; 3]> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![[0, 0, 0]; n]
+}
+
+// CHECK-LABEL: @vec_zero_array_16
+#[no_mangle]
+pub fn vec_zero_array_16(n: usize) -> Vec<[i64; 16]> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![[0_i64; 16]; n]
+}
+
+// CHECK-LABEL: @vec_zero_tuple
+#[no_mangle]
+pub fn vec_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc(
+
+    // CHECK: ret void
+    vec![(0, 0, '\0'); n]
+}
+
+// CHECK-LABEL: @vec_non_zero_tuple
+#[no_mangle]
+pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: call {{.*}}__rust_alloc(
+
+    // CHECK-NOT: call {{.*}}alloc::vec::from_elem
+    // CHECK-NOT: call {{.*}}reserve
+    // CHECK-NOT: call {{.*}}__rust_alloc_zeroed(
+
+    // CHECK: ret void
+    vec![(0, 0, 'A'); n]
+}
index 08302796c41a1e14a8cbdb124d6078442e857eb5..435a4ab5187f6ed5c468c4e26d4051ae22f04ea0 100644 (file)
@@ -1,6 +1,7 @@
 // compile-flags: -O
 // only-x86_64
 // ignore-debug
+// min-llvm-version: 15.0
 
 #![crate_type = "lib"]
 
@@ -142,3 +143,8 @@ pub fn vec_non_zero_tuple(n: usize) -> Vec<(i16, u8, char)> {
     // CHECK: ret void
     vec![(0, 0, 'A'); n]
 }
+
+// Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away.
+// CHECK: declare noalias ptr @__rust_alloc_zeroed(i64, i64 allocalign) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]]
+
+// CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
diff --git a/src/test/mir-opt/issue-99325.rs b/src/test/mir-opt/issue-99325.rs
new file mode 100644 (file)
index 0000000..b79946e
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+
+pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
+    BYTES
+}
+
+// EMIT_MIR issue_99325.main.mir_map.0.mir
+pub fn main() {
+    assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]);
+    assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA");
+}
diff --git a/src/test/mir-opt/issue_99325.main.mir_map.0.mir b/src/test/mir-opt/issue_99325.main.mir_map.0.mir
new file mode 100644 (file)
index 0000000..175f244
--- /dev/null
@@ -0,0 +1,295 @@
+// MIR for `main` 0 mir_map
+
+| User Type Annotations
+| 0: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Value(Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)])) }], user_self_ty: None }) }, span: $DIR/issue-99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:8 ~ issue_99325[8f58]::main::{constant#1}), const_param_did: Some(DefId(0:4 ~ issue_99325[8f58]::function_with_bytes::BYTES)) }, substs: [], promoted: None }) }], user_self_ty: None }) }, span: $DIR/issue-99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+|
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/issue-99325.rs:9:15: 9:15
+    let _1: ();                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _2: (&&[u8], &&[u8; 4]);     // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _3: &&[u8];                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _4: &[u8];                       // in scope 0 at $DIR/issue-99325.rs:10:16: 10:48
+    let mut _5: &&[u8; 4];               // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _6: &[u8; 4];                    // in scope 0 at $DIR/issue-99325.rs:10:50: 10:75
+    let _7: [u8; 4];                     // in scope 0 at $DIR/issue-99325.rs:10:51: 10:75
+    let _8: &&[u8];                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _9: &&[u8; 4];                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _10: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _11: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _12: &&[u8];                 // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _13: &&[u8; 4];              // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _14: !;                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _16: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _18: &&[u8];                 // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _19: &&[u8];                     // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _20: &&[u8; 4];              // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _21: &&[u8; 4];                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _22: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _23: ();                         // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _24: (&&[u8], &&[u8; 4]);    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _25: &&[u8];                 // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _26: &[u8];                      // in scope 0 at $DIR/issue-99325.rs:11:16: 11:70
+    let mut _27: &&[u8; 4];              // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _28: &[u8; 4];                   // in scope 0 at $DIR/issue-99325.rs:11:72: 11:79
+    let _29: &&[u8];                     // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _30: &&[u8; 4];                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _31: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _32: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _33: &&[u8];                 // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _34: &&[u8; 4];              // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _35: !;                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _37: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _38: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _39: &&[u8];                 // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _40: &&[u8];                     // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _41: &&[u8; 4];              // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let _42: &&[u8; 4];                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    let mut _43: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    scope 1 {
+        debug left_val => _8;            // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        debug right_val => _9;           // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        let _15: core::panicking::AssertKind; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        scope 2 {
+            debug kind => _15;           // in scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        }
+    }
+    scope 3 {
+        debug left_val => _29;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        debug right_val => _30;          // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        let _36: core::panicking::AssertKind; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        scope 4 {
+            debug kind => _36;           // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        }
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_3);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_4);                 // scope 0 at $DIR/issue-99325.rs:10:16: 10:48
+        _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb19]; // scope 0 at $DIR/issue-99325.rs:10:16: 10:48
+                                         // mir::Constant
+                                         // + span: $DIR/issue-99325.rs:10:16: 10:46
+                                         // + user_ty: UserType(0)
+                                         // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        _3 = &_4;                        // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_5);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_6);                 // scope 0 at $DIR/issue-99325.rs:10:50: 10:75
+        StorageLive(_7);                 // scope 0 at $DIR/issue-99325.rs:10:51: 10:75
+        _7 = [const 65_u8, const 65_u8, const 65_u8, const 65_u8]; // scope 0 at $DIR/issue-99325.rs:10:51: 10:75
+        _6 = &_7;                        // scope 0 at $DIR/issue-99325.rs:10:50: 10:75
+        _5 = &_6;                        // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _2 = (move _3, move _5);         // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_5);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_3);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        FakeRead(ForMatchedPlace(None), _2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_8);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _8 = (_2.0: &&[u8]);             // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_9);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _9 = (_2.1: &&[u8; 4]);          // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_10);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_11);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_12);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _12 = &(*_8);                    // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_13);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _13 = &(*_9);                    // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _11 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _12, move _13) -> [return: bb2, unwind: bb19]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                         // + literal: Const { ty: for<'r, 's> fn(&'r &[u8], &'s &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
+    }
+
+    bb2: {
+        StorageDead(_13);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_12);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _10 = Not(move _11);             // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_11);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        switchInt(move _10) -> [false: bb4, otherwise: bb3]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb3: {
+        StorageLive(_15);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _15 = core::panicking::AssertKind::Eq; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        FakeRead(ForLet(None), _15);     // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_16);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_17);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _17 = move _15;                  // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_18);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_19);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _19 = &(*_8);                    // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _18 = &(*_19);                   // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_20);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_21);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _21 = &(*_9);                    // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _20 = &(*_21);                   // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_22);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _22 = Option::<Arguments>::None; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _16 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _17, move _18, move _20, move _22) -> bb19; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                         // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r &[u8], &'s &[u8; 4], Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
+    }
+
+    bb4: {
+        goto -> bb7;                     // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb5: {
+        StorageDead(_22);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_20);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_18);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_17);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_21);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_19);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_16);                // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_15);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        unreachable;                     // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb6: {
+        goto -> bb8;                     // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb7: {
+        _1 = const ();                   // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        goto -> bb8;                     // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb8: {
+        StorageDead(_10);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_9);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_8);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        goto -> bb9;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb9: {
+        StorageDead(_7);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_6);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_1);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_23);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_24);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_25);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_26);                // scope 0 at $DIR/issue-99325.rs:11:16: 11:70
+        _26 = function_with_bytes::<&*b"AAAA">() -> [return: bb10, unwind: bb19]; // scope 0 at $DIR/issue-99325.rs:11:16: 11:70
+                                         // mir::Constant
+                                         // + span: $DIR/issue-99325.rs:11:16: 11:68
+                                         // + user_ty: UserType(1)
+                                         // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value(<ZST>) }
+    }
+
+    bb10: {
+        _25 = &_26;                      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_27);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_28);                // scope 0 at $DIR/issue-99325.rs:11:72: 11:79
+        _28 = const b"AAAA";             // scope 0 at $DIR/issue-99325.rs:11:72: 11:79
+                                         // mir::Constant
+                                         // + span: $DIR/issue-99325.rs:11:72: 11:79
+                                         // + literal: Const { ty: &[u8; 4], val: Value(Scalar(alloc4)) }
+        _27 = &_28;                      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _24 = (move _25, move _27);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_27);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_25);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        FakeRead(ForMatchedPlace(None), _24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_29);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _29 = (_24.0: &&[u8]);           // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_30);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _30 = (_24.1: &&[u8; 4]);        // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_31);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_32);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_33);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _33 = &(*_29);                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_34);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _34 = &(*_30);                   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _32 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _33, move _34) -> [return: bb11, unwind: bb19]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                         // + literal: Const { ty: for<'r, 's> fn(&'r &[u8], &'s &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
+    }
+
+    bb11: {
+        StorageDead(_34);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_33);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _31 = Not(move _32);             // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_32);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        switchInt(move _31) -> [false: bb13, otherwise: bb12]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb12: {
+        StorageLive(_36);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _36 = core::panicking::AssertKind::Eq; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        FakeRead(ForLet(None), _36);     // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_37);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_38);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _38 = move _36;                  // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_39);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_40);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _40 = &(*_29);                   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _39 = &(*_40);                   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_41);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_42);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _42 = &(*_30);                   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _41 = &(*_42);                   // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageLive(_43);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _43 = Option::<Arguments>::None; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _37 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _38, move _39, move _41, move _43) -> bb19; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                         // mir::Constant
+                                         // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                         // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r &[u8], &'s &[u8; 4], Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
+    }
+
+    bb13: {
+        goto -> bb16;                    // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb14: {
+        StorageDead(_43);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_41);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_39);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_38);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_42);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_40);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_37);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_36);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        unreachable;                     // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb15: {
+        goto -> bb17;                    // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb16: {
+        _23 = const ();                  // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        goto -> bb17;                    // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb17: {
+        StorageDead(_31);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_30);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_29);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        goto -> bb18;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+    }
+
+    bb18: {
+        StorageDead(_28);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_26);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_24);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        StorageDead(_23);                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        _0 = const ();                   // scope 0 at $DIR/issue-99325.rs:9:15: 12:2
+        return;                          // scope 0 at $DIR/issue-99325.rs:12:2: 12:2
+    }
+
+    bb19 (cleanup): {
+        resume;                          // scope 0 at $DIR/issue-99325.rs:9:1: 12:2
+    }
+}
+
+alloc4 (size: 4, align: 1) {
+    41 41 41 41                                     │ AAAA
+}
index d102d9ecf7d14f53b4cc970cc03903dfa4c830e1..effdef80e8eb65628a784f09a9865d4c86d4f77c 100644 (file)
@@ -1,21 +1,28 @@
     1|       |// Regression test for issue #98833.
-    2|       |// compile-flags: -Zinline-mir
+    2|       |// compile-flags: -Zinline-mir -Cdebug-assertions=off
     3|       |
     4|      1|fn main() {
     5|      1|    println!("{}", live::<false>());
-    6|      1|}
-    7|       |
-    8|       |#[inline]
-    9|      1|fn live<const B: bool>() -> u32 {
-   10|      1|    if B {
-   11|      0|        dead()
-   12|       |    } else {
-   13|      1|        0
-   14|       |    }
-   15|      1|}
-   16|       |
-   17|       |#[inline]
-   18|      0|fn dead() -> u32 {
-   19|      0|    42
-   20|      0|}
+    6|      1|
+    7|      1|    let f = |x: bool| {
+    8|       |        debug_assert!(
+    9|       |            x
+   10|       |        );
+   11|      1|    };
+   12|      1|    f(false);
+   13|      1|}
+   14|       |
+   15|       |#[inline]
+   16|      1|fn live<const B: bool>() -> u32 {
+   17|      1|    if B {
+   18|      0|        dead()
+   19|       |    } else {
+   20|      1|        0
+   21|       |    }
+   22|      1|}
+   23|       |
+   24|       |#[inline]
+   25|      0|fn dead() -> u32 {
+   26|      0|    42
+   27|      0|}
 
index cd1ae911a5f7e44dc8037a818862907dfb4e2277..854fa062967526a5b530b4f68ca7883c1907f73a 100644 (file)
@@ -1,8 +1,15 @@
 // Regression test for issue #98833.
-// compile-flags: -Zinline-mir
+// compile-flags: -Zinline-mir -Cdebug-assertions=off
 
 fn main() {
     println!("{}", live::<false>());
+
+    let f = |x: bool| {
+        debug_assert!(
+            x
+        );
+    };
+    f(false);
 }
 
 #[inline]
index a14f6e3ab95a5b7fcdac3662f6b5ca8532d425ed..33bf95ac1657ed171e2c64175e6230694a284d3b 100644 (file)
@@ -90,7 +90,7 @@ NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
 OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
        -Fo:`cygpath -w $(TMPDIR)/$(1).obj`
 else
-COMPILE_OBJ = $(CC) -c -o $(1) $(2)
+COMPILE_OBJ = $(CC) -v -c -o $(1) $(2)
 COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
 NATIVE_STATICLIB_FILE = lib$(1).a
 NATIVE_STATICLIB = $(call STATICLIB,$(1))
diff --git a/src/test/run-make/export-executable-symbols/Makefile b/src/test/run-make/export-executable-symbols/Makefile
new file mode 100644 (file)
index 0000000..5006f9c
--- /dev/null
@@ -0,0 +1,11 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# ignore-wasm32
+# ignore-wasm64
+# ignore-none no-std is not supported
+# only-linux
+
+all:
+       $(RUSTC) -Zexport-executable-symbols  main.rs --target $(TARGET) --crate-type=bin
+       nm $(TMPDIR)/main | $(CGREP) exported_symbol
+
diff --git a/src/test/run-make/export-executable-symbols/main.rs b/src/test/run-make/export-executable-symbols/main.rs
new file mode 100644 (file)
index 0000000..c498381
--- /dev/null
@@ -0,0 +1,8 @@
+// edition:2018
+
+fn main() {}
+
+#[no_mangle]
+pub fn exported_symbol() -> i8 {
+    42
+}
index 4af8b43ea848d15290a7100ceb39cfa9bb2b8ca6..1badde541128df48928fc69b19f217999fca9939 100644 (file)
@@ -6,14 +6,14 @@
 -include ../../run-make-fulldeps/tools.mk
 
 all:
+       $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
+       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
 ifdef IS_MSVC
-       $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll
+       $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
 else
        $(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
 endif
-       $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
-       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
 
 ifdef RUSTC_BLESS_TEST
index 166305672e6f229790c35292ad5f39d221aa9f5f..713f665078e579bc84a00c9d7bb6e83be28a20e0 100644 (file)
@@ -5,21 +5,24 @@
 -include ../../run-make-fulldeps/tools.mk
 
 all:
+       $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+       $(RUSTC) --crate-type bin --crate-name raw_dylib_test_bin lib.rs
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
 ifdef IS_MSVC
-       $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
-       $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+       $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
+       $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
 else
        $(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
        $(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
 endif
-       $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
-       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+       "$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt
 
 ifdef RUSTC_BLESS_TEST
        cp "$(TMPDIR)"/output.txt output.txt
 else
        $(DIFF) output.txt "$(TMPDIR)"/output.txt
+       $(DIFF) output.txt "$(TMPDIR)"/output_bin.txt
 endif
index e185c4aec12b0603acd1035f05b9989ae99bd63a..58f7ccb38ce4a35ebf57f72557721cf1efc3769e 100644 (file)
@@ -20,3 +20,7 @@ pub fn library_function() {
         extern_fn_3();
     }
 }
+
+fn main() {
+    library_function();
+}
index 0e84a749b05782151ae4008333b319947ba56421..c9baa3c1ec9ac111d56974417c7fe0aed4848bae 100644 (file)
@@ -5,14 +5,14 @@
 -include ../../run-make-fulldeps/tools.mk
 
 all:
+       $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        $(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
 ifdef IS_MSVC
-       $(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+       $(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib
 else
        $(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll
 endif
-       $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
-       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
 
 ifdef RUSTC_BLESS_TEST
index 69f62669d6291da4d8cc3e3122699d921e869c3c..3360a97b5ff0e5e58d08df473671b75a6896a35e 100644 (file)
@@ -6,14 +6,14 @@
 -include ../../run-make-fulldeps/tools.mk
 
 all:
+       $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        $(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
 ifdef IS_MSVC
-       $(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+       $(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll -noimplib
 else
        $(CC) "$(TMPDIR)"/exporter.obj exporter-gnu.def -shared -o "$(TMPDIR)"/exporter.dll
 endif
-       $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
-       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        "$(TMPDIR)"/driver > "$(TMPDIR)"/actual_output.txt
 
 ifdef RUSTC_BLESS_TEST
index 79f18db8fc7cde424abeb23607bedd19a005a963..033c65783498fb89143fde3e4ee638a2e19baa5b 100644 (file)
@@ -40,3 +40,25 @@ assert-position: ("#method\.must_use", {"y": 45})
 click: ".sidebar-menu-toggle"
 scroll-to: ".block.keyword li:nth-child(1)"
 compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543})
+
+// Now checking the background color of the sidebar.
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)"})
+
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "ayu"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)"})
+
+local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "light"}
+reload:
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)"})
index bcf323e1cab89d76df086c205652f24b3fe8f3e8..86e42440bd0bceb276aa6f6b38b86caf0342f8e0 100644 (file)
@@ -37,6 +37,7 @@
     -Z                           dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
     -Z                           emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
+    -Z               export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
     -Z                             fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
     -Z              force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
     -Z                                    fuel=val -- set the optimization fuel quota for a crate
diff --git a/src/test/rustdoc/must_implement_one_of.rs b/src/test/rustdoc/must_implement_one_of.rs
new file mode 100644 (file)
index 0000000..1f1dd5d
--- /dev/null
@@ -0,0 +1,10 @@
+#![crate_name = "c"]
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(a, b)]
+// @matches c/trait.Trait.html '//*[@class="stab must_implement"]' \
+//      'At least one of the `a`, `b` methods is required.$'
+pub trait Trait {
+    fn a() {}
+    fn b() {}
+}
index 4eea9809ac58f66e19e5bab3f29307c6a6c19d6d..e5c6e9dc3f9ed30f29c95cf134d565ed1ef7e386 100644 (file)
@@ -2,6 +2,7 @@
 
 // @has type_layout/struct.Foo.html 'Size: '
 // @has - ' bytes'
+// @has - '//*[@id="layout"]/a[@href="#layout"]' ''
 pub struct Foo {
     pub a: usize,
     b: Vec<String>,
index 46c206f3bf9fb0772ba9fc3ba4d9b19ea4ca6c8d..e849ca2829e434c5532471666df115c9612498e4 100644 (file)
@@ -4,14 +4,14 @@ error: malformed `rustc_lint_diagnostics` attribute input
 LL |     #[rustc_lint_diagnostics(a)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_lint_diagnostics]`
 
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
   --> $DIR/diagnostics_incorrect.rs:5:1
    |
 LL | #[rustc_lint_diagnostics]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL | struct Foo;
-   | ----------- not a function
+   | ----------- not a function definition
 
 error: aborting due to 2 previous errors
 
index b5156f2ac5905551077f73b3265e75c7d5d14410..3f78b39edd96a3adcddf933de7e810ca03798eac 100644 (file)
@@ -4,14 +4,14 @@ error: malformed `rustc_lint_query_instability` attribute input
 LL |     #[rustc_lint_query_instability(a)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_lint_query_instability]`
 
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
   --> $DIR/query_stability_incorrect.rs:5:1
    |
 LL | #[rustc_lint_query_instability]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL | struct Foo;
-   | ----------- not a function
+   | ----------- not a function definition
 
 error: aborting due to 2 previous errors
 
index 08260ec8f4d6318a5b92403be35ecaa5c4f0f8e9..63bac96135b42f4c9763d253924ab3bf40e44f67 100644 (file)
@@ -5,7 +5,7 @@ trait Foo {
 
 impl<'a> Foo for &'a () {
     const NAME: &'a str = "unit";
-    //~^ ERROR mismatched types [E0308]
+    //~^ ERROR const not compatible with trait
 }
 
 fn main() {}
index f71fb2ee18aa1beb8c80e6012e7fc3be56bb8991..de1d9589e99615bcdc0c271f143d670c3c27f046 100644 (file)
@@ -1,4 +1,4 @@
-error[E0308]: mismatched types
+error[E0308]: const not compatible with trait
   --> $DIR/associated-const-impl-wrong-lifetime.rs:7:5
    |
 LL |     const NAME: &'a str = "unit";
diff --git a/src/test/ui/associated-type-bounds/elision.rs b/src/test/ui/associated-type-bounds/elision.rs
new file mode 100644 (file)
index 0000000..4a53393
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(associated_type_bounds)]
+#![feature(anonymous_lifetime_in_impl_trait)]
+
+// The same thing should happen for constaints in dyn trait.
+fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+//~^ ERROR missing lifetime specifier
+//~| ERROR mismatched types
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/elision.stderr b/src/test/ui/associated-type-bounds/elision.stderr
new file mode 100644 (file)
index 0000000..ea30246
--- /dev/null
@@ -0,0 +1,28 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/elision.rs:5:70
+   |
+LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+   |         ------------------------------------------------             ^^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `x`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL | fn f<'a>(x: &'a mut dyn Iterator<Item: Iterator<Item = &'a ()>>) -> Option<&'a ()> { x.next() }
+   |     ++++     ++                                         ~~                  ~~
+
+error[E0308]: mismatched types
+  --> $DIR/elision.rs:5:79
+   |
+LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
+   |                           -----------------------------      --------------   ^^^^^^^^ expected `&()`, found type parameter `impl Iterator<Item = &'_ ()>`
+   |                           |                                  |
+   |                           |                                  expected `Option<&'static ()>` because of return type
+   |                           this type parameter
+   |
+   = note: expected enum `Option<&'static ()>`
+              found enum `Option<impl Iterator<Item = &'_ ()>>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0106, E0308.
+For more information about an error, try `rustc --explain E0106`.
index e8e07997c721df94b12bd3199e885217767f7795..4de4afb6e92461699d2c208ef0aad2ead233b3e4 100644 (file)
@@ -5,15 +5,10 @@ LL | fn elision<T: Fn() -> &i32>() {
    |                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = 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 elision<T: for<'a> Fn() -> &'a i32>() {
-   |               +++++++         ~~~
 help: consider using the `'static` lifetime
    |
 LL | fn elision<T: Fn() -> &'static i32>() {
-   |                       ~~~~~~~~
+   |                        +++++++
 
 error: aborting due to previous error
 
index c75e732b7ca4c82c56a301d71e0a2c408e14cea7..7753d186504f815ef1aa954704394bff70907bfe 100644 (file)
@@ -5,15 +5,10 @@ LL | fn elision(_: fn() -> &i32) {
    |                       ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-   = 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 | fn elision(_: for<'a> fn() -> &'a i32) {
-   |               +++++++         ~~~
 help: consider using the `'static` lifetime
    |
 LL | fn elision(_: fn() -> &'static i32) {
-   |                       ~~~~~~~~
+   |                        +++++++
 
 error: aborting due to previous error
 
index 458bc9faeaf272bfb2d879edd699b31bcf054718..90b59f96e5f553b46cabce767d07bb0aae4026bf 100644 (file)
@@ -11,6 +11,7 @@ async fn do_sth<'a>(
         foo: &dyn Foo, bar: &'a dyn Foo
     ) -> &dyn Foo //~ ERROR missing lifetime specifier
     {
+        //~^ ERROR explicit lifetime required in the type of `foo` [E0621]
         foo
     }
 }
index 24fd3845b4e04500ca6a4206c617f1d3c44fa9b2..e515f227c7ef6641036104aaa2bb089734c1f798 100644 (file)
@@ -10,8 +10,21 @@ LL |     ) -> &dyn Foo
 help: consider using the `'a` lifetime
    |
 LL |     ) -> &'a dyn Foo
-   |          ~~~
+   |           ++
 
-error: aborting due to previous error
+error[E0621]: explicit lifetime required in the type of `foo`
+  --> $DIR/issue-63388-2.rs:13:5
+   |
+LL |           foo: &dyn Foo, bar: &'a dyn Foo
+   |                -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
+LL |       ) -> &dyn Foo
+LL | /     {
+LL | |
+LL | |         foo
+LL | |     }
+   | |_____^ lifetime `'a` required
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0621.
+For more information about an error, try `rustc --explain E0106`.
index cdb141c0e3ea2802c7efd1d6a3a368d832b5e64e..3128b4df4e2d1248874d54199e1ab66f109d9095 100644 (file)
@@ -13,7 +13,7 @@ LL | | }
    |
    = help: consider adding the following bound: `'a: 'b`
 
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Trait<'a>` captures lifetime that does not appear in bounds
   --> $DIR/ret-impl-trait-one.rs:16:80
    |
 LL |   async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
index bb15cc000a46bf73d7c29030dbb037604d3cbcf8..4c7792d9650190e48b79c7dee7dd5fa8e735da1a 100644 (file)
@@ -4,11 +4,11 @@ error[E0106]: missing lifetime specifier
 LL | ) -> &usize {
    |      ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | ) -> &'static usize {
-   |      ~~~~~~~~
+   |       +++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/coherence/issue-99663-2.rs b/src/test/ui/coherence/issue-99663-2.rs
new file mode 100644 (file)
index 0000000..10a0a56
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+struct Outer<T: ?Sized> {
+    i: InnerSend<T>,
+}
+
+type InnerSend<T: ?Sized> = impl Send;
+
+fn constrain<T: ?Sized>() -> InnerSend<T> {
+    ()
+}
+
+trait SendMustNotImplDrop {}
+
+#[allow(drop_bounds)]
+impl<T: ?Sized + Send + Drop> SendMustNotImplDrop for T {}
+
+impl<T: ?Sized> SendMustNotImplDrop for Outer<T> {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/issue-99663.rs b/src/test/ui/coherence/issue-99663.rs
new file mode 100644 (file)
index 0000000..a2d4d39
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+
+struct Send<T> {
+    i: InnerSend<T>,
+}
+
+type InnerSend<T> = impl Sized;
+
+fn constrain<T>() -> InnerSend<T> {
+    ()
+}
+
+trait SendMustNotImplDrop {}
+
+#[allow(drop_bounds)]
+impl<T: Drop> SendMustNotImplDrop for T {}
+
+impl<T> SendMustNotImplDrop for Send<T> {}
+
+fn main() {}
index 18f33acaabbba19fbcc73a699924d4c26b0cad2b..5874625adff61e1ca35d95416fae6af120f30b81 100644 (file)
@@ -1,3 +1,5 @@
+// check-pass
+
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 
@@ -21,11 +23,6 @@ fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
 }
 
 fn main() {
-    // FIXME(generic_const_exprs): We can't correctly infer `T` which requires
-    // evaluating `{ N + 1 }` which has substs containing an inference var
     let mut _q = Default::default();
-    //~^ ERROR type annotations needed
-
     _q = foo::<_, 2>(_q);
-    //~^ ERROR type annotations needed
 }
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.stderr
deleted file mode 100644 (file)
index 9e8328d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-error[E0282]: type annotations needed
-  --> $DIR/const_eval_resolve_canonical.rs:26:9
-   |
-LL |     let mut _q = Default::default();
-   |         ^^^^^^
-   |
-help: consider giving `_q` an explicit type
-   |
-LL |     let mut _q: _ = Default::default();
-   |               +++
-
-error[E0283]: type annotations needed
-  --> $DIR/const_eval_resolve_canonical.rs:29:10
-   |
-LL |     _q = foo::<_, 2>(_q);
-   |          ^^^^^^^^^^^ cannot infer the value of the constant `{ N + 1 }`
-   |
-note: multiple `impl`s satisfying `(): Foo<{ N + 1 }>` found
-  --> $DIR/const_eval_resolve_canonical.rs:8:1
-   |
-LL | impl Foo<0> for () {
-   | ^^^^^^^^^^^^^^^^^^
-...
-LL | impl Foo<3> for () {
-   | ^^^^^^^^^^^^^^^^^^
-note: required by a bound in `foo`
-  --> $DIR/const_eval_resolve_canonical.rs:18:9
-   |
-LL | fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
-   |    --- required by a bound in this
-LL | where
-LL |     (): Foo<{ N + 1 }>,
-   |         ^^^^^^^^^^^^^^ required by this bound in `foo`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0282, E0283.
-For more information about an error, try `rustc --explain E0282`.
index bebd0c6ac1202d656c67299d2dac1f19a105a02c..d6c48e63bb3ce70f98fbdbebddae06b2019356a7 100644 (file)
@@ -12,16 +12,14 @@ impl True for If<true> {}
 fn consume<T: 'static>(_val: T)
 where
     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-    //~^ ERROR: overly complex generic constant
-    //~| ERROR: cannot call non-const operator in constants
+    //~^ ERROR: can't compare
 {
 }
 
 fn test<T: 'static>()
 where
     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-    //~^ ERROR: overly complex generic constant
-    //~| ERROR: cannot call non-const operator in constants
+    //~^ ERROR: can't compare
 {
 }
 
index c8690ecd0da7e84434306962292eb922f7abe4b8..aba4b5c1a8d8d8794f8cae24f8bf22d3ad610f33 100644 (file)
@@ -1,53 +1,29 @@
-error: overly complex generic constant
-  --> $DIR/issue-90318.rs:14:8
+error[E0277]: can't compare `TypeId` with `_` in const contexts
+  --> $DIR/issue-90318.rs:14:28
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-   |        ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
-   |          |
-   |          borrowing is not supported in generic constants
+   |                            ^^ no implementation for `TypeId == _`
    |
-   = help: consider moving this anonymous constant into a `const` function
-   = note: this operation may be supported in the future
-
-error[E0015]: cannot call non-const operator in constants
-  --> $DIR/issue-90318.rs:14:10
+   = help: the trait `~const PartialEq<_>` is not implemented for `TypeId`
+note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const`
+  --> $DIR/issue-90318.rs:14:28
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: impl defined here, but it is not `const`
-  --> $SRC_DIR/core/src/any.rs:LL:COL
-   |
-LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-   |                       ^^^^^^^^^
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+   |                            ^^
 
-error: overly complex generic constant
-  --> $DIR/issue-90318.rs:22:8
+error[E0277]: can't compare `TypeId` with `_` in const contexts
+  --> $DIR/issue-90318.rs:21:28
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-   |        ^^-----------------^^^^^^^^^^^^^^^^^^^^^^^^
-   |          |
-   |          borrowing is not supported in generic constants
+   |                            ^^ no implementation for `TypeId == _`
    |
-   = help: consider moving this anonymous constant into a `const` function
-   = note: this operation may be supported in the future
-
-error[E0015]: cannot call non-const operator in constants
-  --> $DIR/issue-90318.rs:22:10
+   = help: the trait `~const PartialEq<_>` is not implemented for `TypeId`
+note: the trait `PartialEq<_>` is implemented for `TypeId`, but that implementation is not `const`
+  --> $DIR/issue-90318.rs:21:28
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: impl defined here, but it is not `const`
-  --> $SRC_DIR/core/src/any.rs:LL:COL
-   |
-LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-   |                       ^^^^^^^^^
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+   |                            ^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
index c2d22ca4917db34f18de00811c76afccb8cef468..f3bf9c496da7b2aa12aca64b2d53dd8ec7aa7349 100644 (file)
@@ -222,7 +222,7 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  ptr_offset_from_unsigned called on pointers into different allocations
+   |                  `ptr_offset_from_unsigned` called on pointers into different allocations
    |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -241,7 +241,7 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  ptr_offset_from_unsigned called on pointers into different allocations
+   |                  `ptr_offset_from_unsigned` called on pointers into different allocations
    |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
index da9df1c63a4cbda9f6b40f2f78f9e6344103d7f7..5f2821a91937baa712e7ed4d81449b244cce8b5e 100644 (file)
@@ -222,7 +222,7 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  ptr_offset_from_unsigned called on pointers into different allocations
+   |                  `ptr_offset_from_unsigned` called on pointers into different allocations
    |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -241,7 +241,7 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  ptr_offset_from_unsigned called on pointers into different allocations
+   |                  `ptr_offset_from_unsigned` called on pointers into different allocations
    |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
index e238e13b8e2da46fff8542ce21a634f011144655..cd7c980077533bea1f5d4366ad82dba067bafb25 100644 (file)
@@ -1,6 +1,6 @@
 fn main() {}
 
 // unconst and bad, will thus error in miri
-const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR cannot be reliably
+const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR can't compare
 // unconst and bad, will thus error in miri
-const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR cannot be reliably
+const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; //~ ERROR can't compare
index 1f5bca273d3b040012c8b4dd13c8e613d1b9fcdb..168fa0ad0f0ed0ad2c567800ebaa26b9cc80c8a7 100644 (file)
@@ -1,18 +1,49 @@
-error: pointers cannot be reliably compared during const eval
-  --> $DIR/const_raw_ptr_ops.rs:4:26
+error[E0277]: can't compare `*const i32` with `_` in const contexts
+  --> $DIR/const_raw_ptr_ops.rs:4:43
    |
 LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                           ^^ no implementation for `*const i32 == _`
    |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+   = help: the trait `~const PartialEq<_>` is not implemented for `*const i32`
+note: the trait `PartialEq<_>` is implemented for `*const i32`, but that implementation is not `const`
+  --> $DIR/const_raw_ptr_ops.rs:4:43
+   |
+LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 };
+   |                                           ^^
+   = help: the following other types implement trait `PartialEq<Rhs>`:
+             f32
+             f64
+             i128
+             i16
+             i32
+             i64
+             i8
+             isize
+           and 6 others
 
-error: pointers cannot be reliably compared during const eval
-  --> $DIR/const_raw_ptr_ops.rs:6:27
+error[E0277]: can't compare `*const i32` with `_` in const contexts
+  --> $DIR/const_raw_ptr_ops.rs:6:44
    |
 LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                            ^^ no implementation for `*const i32 == _`
    |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+   = help: the trait `~const PartialEq<_>` is not implemented for `*const i32`
+note: the trait `PartialEq<_>` is implemented for `*const i32`, but that implementation is not `const`
+  --> $DIR/const_raw_ptr_ops.rs:6:44
+   |
+LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
+   |                                            ^^
+   = help: the following other types implement trait `PartialEq<Rhs>`:
+             f32
+             f64
+             i128
+             i16
+             i32
+             i64
+             i8
+             isize
+           and 6 others
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
index d1093c205798a0b8875111e57d65d23625d0e74b..c340c30a113b5108a4e719b8d67f20afb9cb6533 100644 (file)
@@ -1,6 +1,6 @@
 fn id<T>(t: T) -> T { t }
 fn main() {
     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
-    //~^ ERROR pointers cannot be reliably compared during const eval
+    //~^ ERROR can't compare
     println!("{}", A);
 }
index 780edd2149fe102ce3ed1fd78264ecf77f247b4c..b80befa26f6e007392731a55ee323596a621adf3 100644 (file)
@@ -1,10 +1,20 @@
-error: pointers cannot be reliably compared during const eval
-  --> $DIR/issue-25826.rs:3:30
+error[E0277]: can't compare `*const ()` with `*const ()` in const contexts
+  --> $DIR/issue-25826.rs:3:52
    |
 LL |     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
-   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                                    ^ no implementation for `*const () < *const ()` and `*const () > *const ()`
    |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+   = help: the trait `~const PartialOrd` is not implemented for `*const ()`
+note: the trait `PartialOrd` is implemented for `*const ()`, but that implementation is not `const`
+  --> $DIR/issue-25826.rs:3:52
+   |
+LL |     const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
+   |                                                    ^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() where *const (): ~const PartialOrd {
+   |           ++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
index e07b269c386eabee6dfc0c5e59c673e973e82bd2..9a2775688c6fa43c1f1a2b1c515b7350de3de96d 100644 (file)
@@ -1,6 +1,6 @@
 const fn cmp(x: fn(), y: fn()) -> bool {
     unsafe { x == y }
-    //~^ ERROR pointers cannot be reliably compared
+    //~^ ERROR can't compare
 }
 
 fn main() {}
index 3845068d8411c652cfca567167c846d75d0d4a4d..8a1b20a334567a9e041da3aa42a2716df4b438c6 100644 (file)
@@ -1,10 +1,16 @@
-error: pointers cannot be reliably compared during const eval
-  --> $DIR/cmp_fn_pointers.rs:2:14
+error[E0277]: can't compare `fn()` with `_` in const contexts
+  --> $DIR/cmp_fn_pointers.rs:2:16
    |
 LL |     unsafe { x == y }
-   |              ^^^^^^
+   |                ^^ no implementation for `fn() == _`
    |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+   = help: the trait `~const PartialEq<_>` is not implemented for `fn()`
+note: the trait `PartialEq<_>` is implemented for `fn()`, but that implementation is not `const`
+  --> $DIR/cmp_fn_pointers.rs:2:16
+   |
+LL |     unsafe { x == y }
+   |                ^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
index 2beb531cc6890c5b4600f0391d187de7bec617aa..13e6af36e0200225f5277c4937d5e10c196e636e 100644 (file)
@@ -2,14 +2,8 @@
 #![feature(core_intrinsics)]
 #![allow(const_err)]
 
-// During CTFE, we prevent pointer comparison and pointer-to-int casts.
-
-static CMP: () = {
-    let x = &0 as *const _;
-    let _v = x == x;
-    //~^ ERROR could not evaluate static initializer
-    //~| "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
-};
+// During CTFE, we prevent pointer-to-int casts.
+// Pointer comparisons are prevented in the trait system.
 
 static PTR_INT_CAST: () = {
     let x = &0 as *const _ as usize;
index 47142752f0ee09d42f8291a13a41c3ef6e4213e6..00cff23fb3fbe4471c490bdd82afa3a4424fc7b8 100644 (file)
@@ -1,17 +1,11 @@
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ptr_arith.rs:9:14
-   |
-LL |     let _v = x == x;
-   |              ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
-
-error[E0080]: could not evaluate static initializer
-  --> $DIR/ptr_arith.rs:15:13
+  --> $DIR/ptr_arith.rs:9:13
    |
 LL |     let x = &0 as *const _ as usize;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ "exposing pointers" needs an rfc before being allowed inside constants
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/ptr_arith.rs:23:14
+  --> $DIR/ptr_arith.rs:17:14
    |
 LL |     let _v = x + 0;
    |              ^ unable to turn pointer into raw bytes
@@ -19,16 +13,11 @@ LL |     let _v = x + 0;
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/ptr_arith.rs:9:14
-   |
-LL |     let _v = x == x;
-   |              ^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/ptr_arith.rs:15:13
+  --> $DIR/ptr_arith.rs:9:13
    |
 LL |     let x = &0 as *const _ as usize;
    |             ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
index db2d421427c3ebc26a9bc5376b675938da1e268d..1f29a690550bc2368f7125daf94caddc868d02dd 100644 (file)
@@ -2,6 +2,7 @@
 #![feature(core_intrinsics)]
 
 use std::intrinsics::{ptr_offset_from, ptr_offset_from_unsigned};
+use std::ptr;
 
 #[repr(C)]
 struct Struct {
@@ -75,9 +76,21 @@ struct Struct {
     let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
     let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
     let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
-    let offset = unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed
+    unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed
     //~| pointers into different allocations
-    offset as usize
+};
+
+pub const TOO_FAR_APART1: isize = {
+    let ptr1 = ptr::null::<u8>();
+    let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
+    unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
+    //~| too far ahead
+};
+pub const TOO_FAR_APART2: isize = {
+    let ptr1 = ptr::null::<u8>();
+    let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
+    unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
+    //~| too far before
 };
 
 const WRONG_ORDER_UNSIGNED: usize = {
@@ -86,5 +99,27 @@ struct Struct {
     unsafe { ptr_offset_from_unsigned(p, p.add(2) ) } //~ERROR evaluation of constant value failed
     //~| first pointer has smaller offset than second: 0 < 8
 };
+pub const TOO_FAR_APART_UNSIGNED: usize = {
+    let ptr1 = ptr::null::<u8>();
+    let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
+    // This would fit into a `usize` but we still don't allow it.
+    unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed
+    //~| too far ahead
+};
+
+// These do NOT complain that pointers are too far apart; they pass that check (to then fail the
+// next one).
+pub const OFFSET_VERY_FAR1: isize = {
+    let ptr1 = ptr::null::<u8>();
+    let ptr2 = ptr1.wrapping_offset(isize::MAX);
+    unsafe { ptr2.offset_from(ptr1) }
+    //~^ inside
+};
+pub const OFFSET_VERY_FAR2: isize = {
+    let ptr1 = ptr::null::<u8>();
+    let ptr2 = ptr1.wrapping_offset(isize::MAX);
+    unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
+    //~^ inside
+};
 
 fn main() {}
index 94d778bc8a150578400e8e90d45f1c6f5b8c9d81..62a087d94d3565894d4043cff00b66526097b54b 100644 (file)
@@ -1,8 +1,8 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:17:27
+  --> $DIR/offset_from_ub.rs:18:27
    |
 LL |     let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from called on pointers into different allocations
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations
 
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -10,62 +10,108 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  ptr_offset_from called on pointers into different allocations
+   |                  `ptr_offset_from` called on pointers into different allocations
    |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/offset_from_ub.rs:23:14
+  ::: $DIR/offset_from_ub.rs:24:14
    |
 LL |     unsafe { (42 as *const u8).offset_from(&5u8) as usize }
-   |              ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:23:14
+   |              ----------------------------------- inside `NOT_PTR` at $DIR/offset_from_ub.rs:24:14
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:30:14
+  --> $DIR/offset_from_ub.rs:31:14
    |
 LL |     unsafe { ptr_offset_from(field_ptr, base_ptr as *const u16) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:36:14
+  --> $DIR/offset_from_ub.rs:37:14
    |
 LL |     unsafe { ptr_offset_from(ptr, ptr) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:43:14
+  --> $DIR/offset_from_ub.rs:44:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x8[noalloc] is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:52:14
+  --> $DIR/offset_from_ub.rs:53:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, start_ptr) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:61:14
+  --> $DIR/offset_from_ub.rs:62:14
    |
 LL |     unsafe { ptr_offset_from(start_ptr, end_ptr) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:69:14
+  --> $DIR/offset_from_ub.rs:70:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, end_ptr) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:78:27
+  --> $DIR/offset_from_ub.rs:79:14
    |
-LL |     let offset = unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) };
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called on pointers into different allocations
+LL |     unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:86:14
    |
+LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far ahead of second
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:92:14
+   |
+LL |     unsafe { ptr_offset_from(ptr1, ptr2) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called when first pointer is too far before second
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:99:14
+   |
 LL |     unsafe { ptr_offset_from_unsigned(p, p.add(2) ) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 8
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 8
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/offset_from_ub.rs:106:14
+   |
+LL |     unsafe { ptr_offset_from_unsigned(ptr2, ptr1) }
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer is too far ahead of second
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+   |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/offset_from_ub.rs:115:14
+   |
+LL |     unsafe { ptr2.offset_from(ptr1) }
+   |              ---------------------- inside `OFFSET_VERY_FAR1` at $DIR/offset_from_ub.rs:115:14
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { intrinsics::ptr_offset_from(self, origin) }
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                  |
+   |                  out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
+   |                  inside `ptr::const_ptr::<impl *const u8>::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/offset_from_ub.rs:121:14
+   |
+LL |     unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
+   |              ----------------------------------------- inside `OFFSET_VERY_FAR2` at $DIR/offset_from_ub.rs:121:14
 
-error: aborting due to 10 previous errors
+error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index b78eeaa90551b067b35d85500e61c68ff2b0effe..3884e397764e75e504bd1f87c9ddc77746cd0f78 100644 (file)
@@ -1,29 +1,43 @@
 #![deny(unaligned_references)]
 
-// check that derive on a packed struct with non-Copy fields
-// correctly. This can't be made to work perfectly because
-// we can't just use the field from the struct as it might
-// not be aligned.
+// Check that deriving certain builtin traits on certain packed structs cause
+// errors. This happens when the derived trait would need to use a potentially
+// misaligned reference. But there are two cases that are allowed:
+// - If all the fields within the struct meet the required alignment: 1 for
+//   `repr(packed)`, or `N` for `repr(packed(N))`.
+// - If `Default` is the only trait derived, because it doesn't involve any
+//   references.
 
-#[derive(Copy, Clone, PartialEq, Eq)]
-//~^ ERROR `#[derive]` can't be used
+#[derive(Copy, Clone, Default, PartialEq, Eq)]
+//~^ ERROR `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
 //~| hard error
-//~^^^ ERROR `#[derive]` can't be used
+//~^^^ ERROR `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
 //~| hard error
 #[repr(packed)]
 pub struct Foo<T>(T, T, T);
 
-#[derive(PartialEq, Eq)]
-//~^ ERROR `#[derive]` can't be used
+#[derive(Default, Hash)]
+//~^ ERROR `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
 //~| hard error
 #[repr(packed)]
 pub struct Bar(u32, u32, u32);
 
-#[derive(PartialEq)]
+// This one is fine because the field alignment is 1.
+#[derive(Default, Hash)]
+#[repr(packed)]
+pub struct Bar2(u8, i8, bool);
+
+// This one is fine because the field alignment is 2, matching `packed(2)`.
+#[derive(Default, Hash)]
+#[repr(packed(2))]
+pub struct Bar3(u16, i16, bool);
+
+// This one is fine because it's not packed.
+#[derive(Debug, Default)]
 struct Y(usize);
 
-#[derive(PartialEq)]
-//~^ ERROR `#[derive]` can't be used
+#[derive(Debug, Default)]
+//~^ ERROR `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
 //~| hard error
 #[repr(packed)]
 struct X(Y);
index 1002b359f60bacaee5d0a4658e05c307e695ebcd..d3fe550c3e48f738d929c0c9b919a13c3bb31af9 100644 (file)
@@ -1,7 +1,7 @@
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133)
-  --> $DIR/deriving-with-repr-packed.rs:8:16
+error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
+  --> $DIR/deriving-with-repr-packed.rs:11:16
    |
-LL | #[derive(Copy, Clone, PartialEq, Eq)]
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
    |                ^^^^^
    |
 note: the lint level is defined here
@@ -13,43 +13,43 @@ LL | #![deny(unaligned_references)]
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133)
-  --> $DIR/deriving-with-repr-packed.rs:8:23
+error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
+  --> $DIR/deriving-with-repr-packed.rs:11:32
    |
-LL | #[derive(Copy, Clone, PartialEq, Eq)]
-   |                       ^^^^^^^^^
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
+   |                                ^^^^^^^^^
    |
    = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
-  --> $DIR/deriving-with-repr-packed.rs:16:10
+error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
+  --> $DIR/deriving-with-repr-packed.rs:19:19
    |
-LL | #[derive(PartialEq, Eq)]
-   |          ^^^^^^^^^
+LL | #[derive(Default, Hash)]
+   |                   ^^^^
    |
    = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
-  --> $DIR/deriving-with-repr-packed.rs:25:10
+error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
+  --> $DIR/deriving-with-repr-packed.rs:39:10
    |
-LL | #[derive(PartialEq)]
-   |          ^^^^^^^^^
+LL | #[derive(Debug, 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 4 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133)
-  --> $DIR/deriving-with-repr-packed.rs:8:16
+error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
+  --> $DIR/deriving-with-repr-packed.rs:11:16
    |
-LL | #[derive(Copy, Clone, PartialEq, Eq)]
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
    |                ^^^^^
    |
 note: the lint level is defined here
@@ -62,11 +62,11 @@ LL | #![deny(unaligned_references)]
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct with type or const parameters (error E0133)
-  --> $DIR/deriving-with-repr-packed.rs:8:23
+error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
+  --> $DIR/deriving-with-repr-packed.rs:11:32
    |
-LL | #[derive(Copy, Clone, PartialEq, Eq)]
-   |                       ^^^^^^^^^
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
+   |                                ^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/deriving-with-repr-packed.rs:1:9
@@ -78,11 +78,11 @@ LL | #![deny(unaligned_references)]
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
-  --> $DIR/deriving-with-repr-packed.rs:16:10
+error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
+  --> $DIR/deriving-with-repr-packed.rs:19:19
    |
-LL | #[derive(PartialEq, Eq)]
-   |          ^^^^^^^^^
+LL | #[derive(Default, Hash)]
+   |                   ^^^^
    |
 note: the lint level is defined here
   --> $DIR/deriving-with-repr-packed.rs:1:9
@@ -91,14 +91,14 @@ LL | #![deny(unaligned_references)]
    |         ^^^^^^^^^^^^^^^^^^^^
    = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
-  --> $DIR/deriving-with-repr-packed.rs:25:10
+error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
+  --> $DIR/deriving-with-repr-packed.rs:39:10
    |
-LL | #[derive(PartialEq)]
-   |          ^^^^^^^^^
+LL | #[derive(Debug, Default)]
+   |          ^^^^^
    |
 note: the lint level is defined here
   --> $DIR/deriving-with-repr-packed.rs:1:9
@@ -107,5 +107,5 @@ LL | #![deny(unaligned_references)]
    |         ^^^^^^^^^^^^^^^^^^^^
    = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index fbd77d96700911550dcd9264d3b32e9bd77e9895..d11a24f7768552f853b2b1caceb770d258f054d5 100644 (file)
@@ -23,6 +23,17 @@ LL |     A(u8),
 LL ~     B(&'a bool),
    |
 
+error[E0106]: missing lifetime specifier
+  --> $DIR/E0106.rs:10:14
+   |
+LL | type MyStr = &str;
+   |              ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | type MyStr<'a> = &'a str;
+   |           ++++    ++
+
 error[E0106]: missing lifetime specifier
   --> $DIR/E0106.rs:17:10
    |
@@ -50,17 +61,6 @@ LL |
 LL ~     buzz: Buzz<'a, 'a>,
    |
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/E0106.rs:10:14
-   |
-LL | type MyStr = &str;
-   |              ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL | type MyStr<'a> = &'a str;
-   |           ++++    ++
-
 error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs
deleted file mode 100644 (file)
index d2edd97..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-static FOO: i32 = 42;
-static BAR: i32 = 42;
-
-static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
-//~^ ERROR pointers cannot be reliably compared during const eval
-
-fn main() {
-}
diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr
deleted file mode 100644 (file)
index ea17e95..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error: pointers cannot be reliably compared during const eval
-  --> $DIR/E0395.rs:4:29
-   |
-LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) };
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-
-error: aborting due to previous error
-
index 87aaba65a73adc431a8f24e3787ddda67edb05b2..35a4b34fb0a4d457e77b2e5de653dbc75cb4f1a4 100644 (file)
@@ -4,12 +4,6 @@ error[E0637]: `'_` cannot be used here
 LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
    |                        ^^ `'_` is a reserved lifetime name
 
-error[E0637]: `&` without an explicit lifetime name cannot be used here
-  --> $DIR/E0637.rs:13:13
-   |
-LL |     T: Into<&u32>,
-   |             ^ explicit lifetime name needed here
-
 error[E0106]: missing lifetime specifier
   --> $DIR/E0637.rs:1:62
    |
@@ -22,6 +16,12 @@ help: consider introducing a named lifetime parameter
 LL | fn underscore_lifetime<'a, '_>(str1: &'a str, str2: &'a str) -> &'a str {
    |                        +++            ~~             ~~          ~~
 
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/E0637.rs:13:13
+   |
+LL |     T: Into<&u32>,
+   |             ^ explicit lifetime name needed here
+
 error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0106, E0637.
index b174766cd3d0c166ef49989a87bea1b502a74217..df1a23a19edd51c3b2aab0f21f87ea3c9f28c094 100644 (file)
@@ -8,7 +8,7 @@ LL |     pub fn f() -> &u8;
 help: consider using the `'static` lifetime
    |
 LL |     pub fn f() -> &'static u8;
-   |                   ~~~~~~~~
+   |                    +++++++
 
 error: aborting due to previous error
 
index 246659a268ac933d07359093c05b0acfdbdb4a4a..dbf7e02aeafccdb3d34859afab4397f225dd451e 100644 (file)
@@ -7,9 +7,10 @@ fn identity<'a>(t: &'a Self::F<'a>) -> &'a Self::F<'a> { t }
 }
 
 impl <T, T1> Foo for T {
+    //~^ ERROR: the type parameter `T1` is not constrained
     type F<T1> = &[u8];
       //~^ ERROR: the name `T1` is already used for
-      //~| ERROR: missing lifetime specifier
+      //~| ERROR: `&` without an explicit lifetime name cannot be used here
 }
 
 fn main() {}
index e82cbf7e8e5ef08efabb39dd5033699506608712..dad0dae6a44bff9fd1ccac0ebceede0089b10838 100644 (file)
@@ -1,23 +1,25 @@
 error[E0403]: the name `T1` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/gat-trait-path-generic-type-arg.rs:10:12
+  --> $DIR/gat-trait-path-generic-type-arg.rs:11:12
    |
 LL | impl <T, T1> Foo for T {
    |          -- first use of `T1`
+LL |
 LL |     type F<T1> = &[u8];
    |            ^^ already used
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/gat-trait-path-generic-type-arg.rs:10:18
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/gat-trait-path-generic-type-arg.rs:11:18
    |
 LL |     type F<T1> = &[u8];
-   |                  ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
+   |                  ^ explicit lifetime name needed here
+
+error[E0207]: the type parameter `T1` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/gat-trait-path-generic-type-arg.rs:9:10
    |
-LL |     type F<'a, T1> = &'a [u8];
-   |            +++        ++
+LL | impl <T, T1> Foo for T {
+   |          ^^ unconstrained type parameter
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0106, E0403.
-For more information about an error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0207, E0403, E0637.
+For more information about an error, try `rustc --explain E0207`.
index c7ebb9880f710a0734d39e69abc301ef2cce61da..e866b3bab7972b6efbda369e1f17cf5194f30316 100644 (file)
@@ -11,13 +11,13 @@ LL |     type Assoc2<T: std::fmt::Display> = Vec<T>;
    |                  +++++++++++++++++++
 
 error[E0276]: impl has stricter requirements than trait
-  --> $DIR/generic-associated-types-where.rs:22:5
+  --> $DIR/generic-associated-types-where.rs:22:38
    |
 LL |     type Assoc3<T>;
    |     -------------- definition of `Assoc3` from trait
 ...
 LL |     type Assoc3<T> = Vec<T> where T: Iterator;
-   |     ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
+   |                                      ^^^^^^^^ impl has extra requirement `T: Iterator`
 
 error: aborting due to 2 previous errors
 
index bb5992c88f08f0973abf045c3e663610fedbbf5f..ec1d171c044701f7c9f30e025bbfc81a87e540e9 100644 (file)
@@ -13,9 +13,9 @@ trait Foo {
 
 impl<T> Foo for Fooy<T> {
     type A<'a> = (&'a ()) where Self: 'static;
-    //~^ ERROR `impl` associated type
+    //~^ ERROR impl has stricter requirements than trait
     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
-    //~^ ERROR `impl` associated type
+    //~^ ERROR impl has stricter requirements than trait
     //~| ERROR lifetime bound not satisfied
     type C = String where Self: Copy;
     //~^ ERROR the trait bound `T: Copy` is not satisfied
index 6aa52b179a3c68a363f298faa24935db67f9bf8e..ce79c635add69ac2e94f8c8e6fd6125980115109 100644 (file)
@@ -1,20 +1,20 @@
-error: `impl` associated type signature for `A` doesn't match `trait` associated type signature
-  --> $DIR/impl_bounds.rs:15:5
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/impl_bounds.rs:15:39
    |
 LL |     type A<'a> where Self: 'a;
-   |     ---------- expected
+   |     ---------- definition of `A` from trait
 ...
 LL |     type A<'a> = (&'a ()) where Self: 'static;
-   |     ^^^^^^^^^^ found
+   |                                       ^^^^^^^ impl has extra requirement `T: 'static`
 
-error: `impl` associated type signature for `B` doesn't match `trait` associated type signature
-  --> $DIR/impl_bounds.rs:17:5
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/impl_bounds.rs:17:48
    |
 LL |     type B<'a, 'b> where 'a: 'b;
-   |     -------------- expected
+   |     -------------- definition of `B` from trait
 ...
 LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
-   |     ^^^^^^^^^^^^^^ found
+   |                                                ^^ impl has extra requirement `'b: 'a`
 
 error[E0478]: lifetime bound not satisfied
   --> $DIR/impl_bounds.rs:17:22
@@ -37,24 +37,24 @@ LL |     type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
    |                ^^
 
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/impl_bounds.rs:20:5
+  --> $DIR/impl_bounds.rs:20:33
    |
 LL |     type C = String where Self: Copy;
-   |     ^^^^^^ the trait `Copy` is not implemented for `T`
+   |                                 ^^^^ the trait `Copy` is not implemented for `T`
    |
 note: required because of the requirements on the impl of `Copy` for `Fooy<T>`
   --> $DIR/impl_bounds.rs:11:10
    |
 LL | #[derive(Copy, Clone)]
    |          ^^^^
-note: the requirement `Fooy<T>: Copy` appears on the associated impl type `C` but not on the corresponding associated trait type
-  --> $DIR/impl_bounds.rs:7:5
+note: the requirement `Fooy<T>: Copy` appears on the `impl`'s associated type `C` but not on the corresponding trait's associated type
+  --> $DIR/impl_bounds.rs:7:10
    |
 LL | trait Foo {
    |       --- in this trait
 ...
 LL |     type C where Self: Clone;
-   |     ^^^^^^ this trait associated type doesn't have the requirement `Fooy<T>: Copy`
+   |          ^ this trait's associated type doesn't have the requirement `Fooy<T>: Copy`
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider restricting type parameter `T`
    |
@@ -72,14 +72,14 @@ note: required because of the requirements on the impl of `Copy` for `Fooy<T>`
    |
 LL | #[derive(Copy, Clone)]
    |          ^^^^
-note: the requirement `Fooy<T>: Copy` appears on the impl method `d` but not on the corresponding trait method
+note: the requirement `Fooy<T>: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method
   --> $DIR/impl_bounds.rs:8:8
    |
 LL | trait Foo {
    |       --- in this trait
 ...
 LL |     fn d() where Self: Clone;
-   |        ^ this trait method doesn't have the requirement `Fooy<T>: Copy`
+   |        ^ this trait's method doesn't have the requirement `Fooy<T>: Copy`
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider restricting type parameter `T`
    |
@@ -88,5 +88,5 @@ LL | impl<T: std::marker::Copy> Foo for Fooy<T> {
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0277, E0478.
-For more information about an error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0276, E0277, E0478.
+For more information about an error, try `rustc --explain E0276`.
index c560e2405d5a77c8d6b94d1860233642aafd783e..31948a878edfaa812e4ea90f2101678c8e713261 100644 (file)
@@ -1,11 +1,11 @@
 error[E0276]: impl has stricter requirements than trait
-  --> $DIR/issue-47206-where-clause.rs:12:5
+  --> $DIR/issue-47206-where-clause.rs:12:38
    |
 LL |     type Assoc3<T>;
    |     -------------- definition of `Assoc3` from trait
 ...
 LL |     type Assoc3<T> = Vec<T> where T: Iterator;
-   |     ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
+   |                                      ^^^^^^^^ impl has extra requirement `T: Iterator`
 
 error: aborting due to previous error
 
index c9fd7248a80044038a2bb9694fde051d7ebb1982..f778f985cf0d1c277ad56f82cfd0cbc197c79320 100644 (file)
@@ -2,6 +2,7 @@
 
 trait Document {
     type Cursor<'a>: DocCursor<'a>;
+    //~^ ERROR: missing required bound on `Cursor`
 
     fn cursor(&self) -> Self::Cursor<'_>;
 }
index b3881ccb099f07d6a2707b4bf1789e764bfedd03..bba7cab7093cefdd41855b256223c80865b0b0d6 100644 (file)
@@ -1,11 +1,11 @@
 error[E0637]: `'_` cannot be used here
-  --> $DIR/issue-70304.rs:47:41
+  --> $DIR/issue-70304.rs:48:41
    |
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
    |                                         ^^ `'_` is a reserved lifetime name
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-70304.rs:47:61
+  --> $DIR/issue-70304.rs:48:61
    |
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> {
    |                                                             ^^ expected named lifetime parameter
@@ -16,7 +16,18 @@ help: consider using the `'static` lifetime
 LL | fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'static>> {
    |                                                             ~~~~~~~
 
-error: aborting due to 2 previous errors
+error: missing required bound on `Cursor`
+  --> $DIR/issue-70304.rs:4:5
+   |
+LL |     type Cursor<'a>: DocCursor<'a>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   |                                   |
+   |                                   help: add the required where clause: `where Self: 'a`
+   |
+   = note: this bound is currently required to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0106, E0637.
 For more information about an error, try `rustc --explain E0106`.
index 5fb8f7a4773d68a583015ffe71284b14a15ed32c..8171dc0ae28d62d81feab67ed6e4881d074bd92a 100644 (file)
@@ -7,7 +7,7 @@ trait Foo {
 }
 impl Foo for () {
     type Assoc<'a, 'b> = () where 'a: 'b;
-    //~^ `impl` associated type
+    //~^ impl has stricter requirements than trait
 }
 
 fn main() {}
index 0256d2f20fc1e0d9d8ac50c8dbe0c9766c86e2af..edd1f9367d129f7971de9b3481415e1cc4d4c249 100644 (file)
@@ -1,11 +1,12 @@
-error: `impl` associated type signature for `Assoc` doesn't match `trait` associated type signature
-  --> $DIR/missing-where-clause-on-trait.rs:9:5
+error[E0276]: impl has stricter requirements than trait
+  --> $DIR/missing-where-clause-on-trait.rs:9:39
    |
 LL |     type Assoc<'a, 'b>;
-   |     ------------------ expected
+   |     ------------------ definition of `Assoc` from trait
 ...
 LL |     type Assoc<'a, 'b> = () where 'a: 'b;
-   |     ^^^^^^^^^^^^^^^^^^ found
+   |                                       ^^ impl has extra requirement `'a: 'b`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0276`.
index 54b483f53d4cba42064837b786cef3d42d12db8f..9ea9fc71b557fe13a64275fa774dcf328f576114 100644 (file)
@@ -8,6 +8,7 @@ fn should_error<T>() where T : Into<&u32> {}
 trait X<'a, K: 'a> {
     fn foo<'b, L: X<&'b Nested<K>>>();
     //~^ ERROR missing lifetime specifier [E0106]
+    //~| ERROR the type `&'b Nested<K>` does not fulfill the required lifetime
 }
 
 fn bar<'b, L: X<&'b Nested<i32>>>(){}
index 270d6b8e18e2269dfbb7dda942af5d6f7e81244b..e45387acaf31df709d6c0860898fce2d5e021d6f 100644 (file)
@@ -5,21 +5,10 @@ LL | fn should_error<T>() where T : Into<&u32> {}
    |                                     ^ explicit lifetime name needed here
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:17
-   |
-LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
-   |                 ^ expected named lifetime parameter
-   |
-help: consider using the `'b` lifetime
-   |
-LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){}
-   |                 +++
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:21
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20
    |
 LL |     fn foo<'b, L: X<&'b Nested<K>>>();
-   |                     ^ expected named lifetime parameter
+   |                    ^ expected named lifetime parameter
    |
 note: these named lifetimes are available to use
   --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:9
@@ -33,7 +22,30 @@ help: consider using one of the available lifetimes here
 LL |     fn foo<'b, L: X<'lifetime, &'b Nested<K>>>();
    |                     ++++++++++
 
-error: aborting due to 3 previous errors
+error[E0106]: missing lifetime specifier
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:14:16
+   |
+LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
+   |                ^ expected named lifetime parameter
+   |
+help: consider using the `'b` lifetime
+   |
+LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){}
+   |                 +++
+
+error[E0477]: the type `&'b Nested<K>` does not fulfill the required lifetime
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19
+   |
+LL |     fn foo<'b, L: X<&'b Nested<K>>>();
+   |                   ^^^^^^^^^^^^^^^^
+   |
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:16
+   |
+LL | trait X<'a, K: 'a> {
+   |                ^^
+
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0106, E0637.
+Some errors have detailed explanations: E0106, E0477, E0637.
 For more information about an error, try `rustc --explain E0106`.
index 272cd3619680429d44d25f59455aa6dba6727019..cd2f96a1819e466cc42bb127c17439545505bc42 100644 (file)
@@ -120,6 +120,7 @@ trait GenericType<A> {
     type B = Box<dyn GenericLifetime>;
     //~^ ERROR missing lifetime specifier
     //~| HELP consider introducing
+    //~| HELP consider making the bound lifetime-generic
 
     type C = Box<dyn GenericLifetime<'static, 'static>>;
     //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
@@ -136,6 +137,7 @@ trait GenericType<A> {
     type F = Box<dyn GenericLifetime<>>;
     //~^ ERROR missing lifetime specifier
     //~| HELP consider introducing
+    //~| HELP consider making the bound lifetime-generic
 
     type G = Box<dyn GenericType<>>;
     //~^ ERROR this trait takes 1 generic argument but 0 generic arguments
@@ -161,6 +163,7 @@ trait GenericLifetimeAT<'a> {
         type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
         //~^ ERROR this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
@@ -169,6 +172,7 @@ trait GenericLifetimeAT<'a> {
         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
         //~| ERROR this trait takes 0 generic arguments but 1 generic argument
         //~| HELP remove
     }
@@ -203,6 +207,7 @@ trait GenericLifetimeTypeAT<'a, A> {
         //~| HELP add missing
         //~| ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
         //~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
@@ -217,10 +222,12 @@ trait GenericLifetimeTypeAT<'a, A> {
         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
 
         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
         //~| ERROR this trait takes 1 generic argument but 2 generic arguments
         //~| HELP remove
 
@@ -265,6 +272,7 @@ trait GenericLifetimeLifetimeAT<'a, 'b> {
         type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
 
         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
         //~^ ERROR this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
@@ -279,6 +287,7 @@ trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
         //~^ ERROR missing lifetime specifier
         //~| HELP consider introducing
+        //~| HELP consider making the bound lifetime-generic
         //~| ERROR this trait takes 1 generic argument but 0 generic arguments
         //~| HELP add missing
 
index 3b0834a5f51b271b10445bb67d466cc19b0ed5c6..388c23fc24f74e2513f0898759b435d46de50237 100644 (file)
@@ -1,3 +1,172 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:48:14
+   |
+LL |     type A = Ty;
+   |              ^^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type A<'a> = Ty<'a>;
+   |           ++++     ++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:58:16
+   |
+LL |     type C = Ty<usize>;
+   |                ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type C<'a> = Ty<'a, usize>;
+   |           ++++      +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:64:16
+   |
+LL |     type E = Ty<>;
+   |                ^ expected named lifetime parameter
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL |     type E<'a> = Ty<'a, >;
+   |           ++++      +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:120:22
+   |
+LL |     type B = Box<dyn GenericLifetime>;
+   |                      ^^^^^^^^^^^^^^^ expected named lifetime parameter
+   |
+   = 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 B = Box<dyn for<'a> GenericLifetime<'a>>;
+   |                      +++++++                ++++
+help: consider introducing a named lifetime parameter
+   |
+LL |     type B<'a> = Box<dyn GenericLifetime<'a>>;
+   |           ++++                          ++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:137:37
+   |
+LL |     type F = Box<dyn GenericLifetime<>>;
+   |                                     ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |     type F = Box<dyn for<'a> GenericLifetime<'a, >>;
+   |                      +++++++                 +++
+help: consider introducing a named lifetime parameter
+   |
+LL |     type F<'a> = Box<dyn GenericLifetime<'a, >>;
+   |           ++++                           +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:163:43
+   |
+LL |         type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
+   |                                           ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type A = Box<dyn for<'a> GenericLifetimeAT<'a, AssocTy=()>>;
+   |                          +++++++                   +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>;
+   |               ++++                             +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:172:43
+   |
+LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
+   |                                           ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type C = Box<dyn for<'a> GenericLifetimeAT<'a, (), AssocTy=()>>;
+   |                          +++++++                   +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>;
+   |               ++++                             +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:205:47
+   |
+LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
+   |                                               ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type A = Box<dyn for<'a> GenericLifetimeTypeAT<'a, AssocTy=()>>;
+   |                          +++++++                       +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>;
+   |               ++++                                 +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:222:47
+   |
+LL |         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
+   |                                               ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type D = Box<dyn for<'a> GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
+   |                          +++++++                       +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
+   |               ++++                                 +++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/wrong-number-of-args.rs:227:47
+   |
+LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
+   |                                               ^ expected named lifetime parameter
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type E = Box<dyn for<'a> GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
+   |                          +++++++                       +++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
+   |               ++++                                 +++
+
+error[E0106]: missing lifetime specifiers
+  --> $DIR/wrong-number-of-args.rs:272:51
+   |
+LL |         type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
+   |                                                   ^ expected 2 lifetime parameters
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type A = Box<dyn for<'a> GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
+   |                          +++++++                           +++++++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
+   |               ++++                                     +++++++
+
+error[E0106]: missing lifetime specifiers
+  --> $DIR/wrong-number-of-args.rs:287:55
+   |
+LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
+   |                                                       ^ expected 2 lifetime parameters
+   |
+help: consider making the bound lifetime-generic with a new `'a` lifetime
+   |
+LL |         type A = Box<dyn for<'a> GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
+   |                          +++++++                               +++++++
+help: consider introducing a named lifetime parameter
+   |
+LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
+   |               ++++                                         +++++++
+
 error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
   --> $DIR/wrong-number-of-args.rs:6:14
    |
@@ -148,17 +317,6 @@ help: add missing generic argument
 LL |     type A = Ty<T>;
    |              ~~~~~
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:48:14
-   |
-LL |     type A = Ty;
-   |              ^^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type A<'a> = Ty<'a>;
-   |           ++++   ~~~~~~
-
 error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:54:14
    |
@@ -175,17 +333,6 @@ help: add missing generic argument
 LL |     type B = Ty<'static, T>;
    |                        +++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:58:17
-   |
-LL |     type C = Ty<usize>;
-   |                 ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type C<'a> = Ty<'a, usize>;
-   |           ++++      +++
-
 error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
   --> $DIR/wrong-number-of-args.rs:64:14
    |
@@ -202,17 +349,6 @@ help: add missing generic argument
 LL |     type E = Ty<T>;
    |                 +
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:64:16
-   |
-LL |     type E = Ty<>;
-   |                ^- expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type E<'a> = Ty<'a>;
-   |           ++++      ++
-
 error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
   --> $DIR/wrong-number-of-args.rs:70:14
    |
@@ -319,19 +455,8 @@ note: trait defined here, with 0 generic parameters
 LL |     trait NonGeneric {
    |           ^^^^^^^^^^
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:120:22
-   |
-LL |     type B = Box<dyn GenericLifetime>;
-   |                      ^^^^^^^^^^^^^^^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type B<'a> = Box<dyn GenericLifetime<'a>>;
-   |           ++++           ~~~~~~~~~~~~~~~~~~~
-
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:124:22
+  --> $DIR/wrong-number-of-args.rs:125:22
    |
 LL |     type C = Box<dyn GenericLifetime<'static, 'static>>;
    |                      ^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -345,7 +470,7 @@ LL |     trait GenericLifetime<'a> {
    |           ^^^^^^^^^^^^^^^ --
 
 error[E0107]: missing generics for trait `GenericType`
-  --> $DIR/wrong-number-of-args.rs:128:22
+  --> $DIR/wrong-number-of-args.rs:129:22
    |
 LL |     type D = Box<dyn GenericType>;
    |                      ^^^^^^^^^^^ expected 1 generic argument
@@ -361,7 +486,7 @@ LL |     type D = Box<dyn GenericType<A>>;
    |                      ~~~~~~~~~~~~~~
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:132:22
+  --> $DIR/wrong-number-of-args.rs:133:22
    |
 LL |     type E = Box<dyn GenericType<String, usize>>;
    |                      ^^^^^^^^^^^         ----- help: remove this generic argument
@@ -374,19 +499,8 @@ note: trait defined here, with 1 generic parameter: `A`
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:136:37
-   |
-LL |     type F = Box<dyn GenericLifetime<>>;
-   |                                     ^- expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type F<'a> = Box<dyn GenericLifetime<'a>>;
-   |           ++++                           ++
-
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:140:22
+  --> $DIR/wrong-number-of-args.rs:142:22
    |
 LL |     type G = Box<dyn GenericType<>>;
    |                      ^^^^^^^^^^^ expected 1 generic argument
@@ -402,7 +516,7 @@ LL |     type G = Box<dyn GenericType<A>>;
    |                                  +
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:151:26
+  --> $DIR/wrong-number-of-args.rs:153:26
    |
 LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
    |                          ^^^^^^^^^^^^------------------- help: remove these generics
@@ -410,24 +524,13 @@ LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
    |                          expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:147:15
+  --> $DIR/wrong-number-of-args.rs:149:15
    |
 LL |         trait NonGenericAT {
    |               ^^^^^^^^^^^^
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:161:44
-   |
-LL |         type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
-   |                                            ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>;
-   |               ++++                             +++
-
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:165:26
+  --> $DIR/wrong-number-of-args.rs:168:26
    |
 LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -435,13 +538,13 @@ LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:157:15
+  --> $DIR/wrong-number-of-args.rs:159:15
    |
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:169:26
+  --> $DIR/wrong-number-of-args.rs:172:26
    |
 LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
@@ -449,30 +552,19 @@ LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                          expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:157:15
+  --> $DIR/wrong-number-of-args.rs:159:15
    |
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:169:44
-   |
-LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
-   |                                            ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>;
-   |               ++++                             +++
-
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:181:26
+  --> $DIR/wrong-number-of-args.rs:185:26
    |
 LL |         type A = Box<dyn GenericTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:177:15
+  --> $DIR/wrong-number-of-args.rs:181:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
@@ -482,7 +574,7 @@ LL |         type A = Box<dyn GenericTypeAT<A, AssocTy=()>>;
    |                                        ++
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:185:26
+  --> $DIR/wrong-number-of-args.rs:189:26
    |
 LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^     -- help: remove this generic argument
@@ -490,13 +582,13 @@ LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:177:15
+  --> $DIR/wrong-number-of-args.rs:181:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
 
 error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:189:26
+  --> $DIR/wrong-number-of-args.rs:193:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^--------------------- help: remove these generics
@@ -504,19 +596,19 @@ LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          expected 0 lifetime arguments
    |
 note: trait defined here, with 0 lifetime parameters
-  --> $DIR/wrong-number-of-args.rs:177:15
+  --> $DIR/wrong-number-of-args.rs:181:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:189:26
+  --> $DIR/wrong-number-of-args.rs:193:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:177:15
+  --> $DIR/wrong-number-of-args.rs:181:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
@@ -526,13 +618,13 @@ LL |         type C = Box<dyn GenericTypeAT<'static, A, AssocTy=()>>;
    |                                               +++
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:201:26
+  --> $DIR/wrong-number-of-args.rs:205:26
    |
 LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -541,25 +633,14 @@ help: add missing generic argument
 LL |         type A = Box<dyn GenericLifetimeTypeAT<A, AssocTy=()>>;
    |                                                ++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:201:48
-   |
-LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
-   |                                                ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>;
-   |               ++++                                 +++
-
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:207:26
+  --> $DIR/wrong-number-of-args.rs:212:26
    |
 LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -569,7 +650,7 @@ LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, A, AssocTy=()>>;
    |                                                       +++
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:211:26
+  --> $DIR/wrong-number-of-args.rs:216:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -577,19 +658,19 @@ LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:211:26
+  --> $DIR/wrong-number-of-args.rs:216:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -598,19 +679,8 @@ help: add missing generic argument
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, A, AssocTy=()>>;
    |                                                                +++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:217:48
-   |
-LL |         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
-   |                                                ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
-   |               ++++                                 +++
-
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:221:26
+  --> $DIR/wrong-number-of-args.rs:227:26
    |
 LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^     -- help: remove this generic argument
@@ -618,24 +688,13 @@ LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:221:48
-   |
-LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
-   |                                                ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>;
-   |               ++++                                 +++
-
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:227:26
+  --> $DIR/wrong-number-of-args.rs:234:26
    |
 LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -643,13 +702,13 @@ LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocT
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:231:26
+  --> $DIR/wrong-number-of-args.rs:238:26
    |
 LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^              -- help: remove this generic argument
@@ -657,13 +716,13 @@ LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:235:26
+  --> $DIR/wrong-number-of-args.rs:242:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -671,13 +730,13 @@ LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:235:26
+  --> $DIR/wrong-number-of-args.rs:242:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^                       -- help: remove this generic argument
@@ -685,19 +744,19 @@ LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:197:15
+  --> $DIR/wrong-number-of-args.rs:201:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:247:26
+  --> $DIR/wrong-number-of-args.rs:254:26
    |
 LL |         type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:243:15
+  --> $DIR/wrong-number-of-args.rs:250:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
@@ -707,7 +766,7 @@ LL |         type A = Box<dyn GenericTypeTypeAT<A, B, AssocTy=()>>;
    |                                            +++++
 
 error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:251:26
+  --> $DIR/wrong-number-of-args.rs:258:26
    |
 LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument
@@ -715,7 +774,7 @@ LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
    |                          expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:243:15
+  --> $DIR/wrong-number-of-args.rs:250:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
@@ -725,7 +784,7 @@ LL |         type B = Box<dyn GenericTypeTypeAT<(), B, AssocTy=()>>;
    |                                              +++
 
 error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:255:26
+  --> $DIR/wrong-number-of-args.rs:262:26
    |
 LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^         -- help: remove this generic argument
@@ -733,24 +792,13 @@ LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
    |                          expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:243:15
+  --> $DIR/wrong-number-of-args.rs:250:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
 
-error[E0106]: missing lifetime specifiers
-  --> $DIR/wrong-number-of-args.rs:265:52
-   |
-LL |         type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
-   |                                                    ^ expected 2 lifetime parameters
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>;
-   |               ++++                                     +++++++
-
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:269:26
+  --> $DIR/wrong-number-of-args.rs:277:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -758,7 +806,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:261:15
+  --> $DIR/wrong-number-of-args.rs:268:15
    |
 LL |         trait GenericLifetimeLifetimeAT<'a, 'b> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -768,13 +816,13 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'b, AssocTy=()>
    |                                                           ++++
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:279:26
+  --> $DIR/wrong-number-of-args.rs:287:26
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:275:15
+  --> $DIR/wrong-number-of-args.rs:283:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -
@@ -783,19 +831,8 @@ help: add missing generic argument
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<A, AssocTy=()>>;
    |                                                        ++
 
-error[E0106]: missing lifetime specifiers
-  --> $DIR/wrong-number-of-args.rs:279:56
-   |
-LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
-   |                                                        ^ expected 2 lifetime parameters
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=()>>;
-   |               ++++                                         +++++++
-
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:285:26
+  --> $DIR/wrong-number-of-args.rs:294:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -803,7 +840,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:275:15
+  --> $DIR/wrong-number-of-args.rs:283:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -813,13 +850,13 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, AssocTy
    |                                                               ++++
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:285:26
+  --> $DIR/wrong-number-of-args.rs:294:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:275:15
+  --> $DIR/wrong-number-of-args.rs:283:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -
@@ -829,7 +866,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, A, AssocTy=
    |                                                               +++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:291:26
+  --> $DIR/wrong-number-of-args.rs:300:26
    |
 LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -837,7 +874,7 @@ LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:275:15
+  --> $DIR/wrong-number-of-args.rs:283:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -847,7 +884,7 @@ LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, (), Ass
    |                                                               ++++
 
 error[E0107]: missing generics for struct `HashMap`
-  --> $DIR/wrong-number-of-args.rs:301:18
+  --> $DIR/wrong-number-of-args.rs:310:18
    |
 LL |         type A = HashMap;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -863,7 +900,7 @@ LL |         type A = HashMap<K, V>;
    |                  ~~~~~~~~~~~~~
 
 error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:305:18
+  --> $DIR/wrong-number-of-args.rs:314:18
    |
 LL |         type B = HashMap<String>;
    |                  ^^^^^^^ ------ supplied 1 generic argument
@@ -881,7 +918,7 @@ LL |         type B = HashMap<String, V>;
    |                                +++
 
 error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:309:18
+  --> $DIR/wrong-number-of-args.rs:318:18
    |
 LL |         type C = HashMap<'static>;
    |                  ^^^^^^^--------- help: remove these generics
@@ -895,7 +932,7 @@ LL | pub struct HashMap<K, V, S = RandomState> {
    |            ^^^^^^^
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:309:18
+  --> $DIR/wrong-number-of-args.rs:318:18
    |
 LL |         type C = HashMap<'static>;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -911,7 +948,7 @@ LL |         type C = HashMap<'static, K, V>;
    |                                 ++++++
 
 error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:315:18
+  --> $DIR/wrong-number-of-args.rs:324:18
    |
 LL |         type D = HashMap<usize, String, char, f64>;
    |                  ^^^^^^^                      --- help: remove this generic argument
@@ -925,7 +962,7 @@ LL | pub struct HashMap<K, V, S = RandomState> {
    |            ^^^^^^^ -  -  ---------------
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:319:18
+  --> $DIR/wrong-number-of-args.rs:328:18
    |
 LL |         type E = HashMap<>;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -941,7 +978,7 @@ LL |         type E = HashMap<K, V>;
    |                          ++++
 
 error[E0107]: missing generics for enum `Result`
-  --> $DIR/wrong-number-of-args.rs:325:18
+  --> $DIR/wrong-number-of-args.rs:334:18
    |
 LL |         type A = Result;
    |                  ^^^^^^ expected 2 generic arguments
@@ -957,7 +994,7 @@ LL |         type A = Result<T, E>;
    |                  ~~~~~~~~~~~~
 
 error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:329:18
+  --> $DIR/wrong-number-of-args.rs:338:18
    |
 LL |         type B = Result<String>;
    |                  ^^^^^^ ------ supplied 1 generic argument
@@ -975,7 +1012,7 @@ LL |         type B = Result<String, E>;
    |                               +++
 
 error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:333:18
+  --> $DIR/wrong-number-of-args.rs:342:18
    |
 LL |         type C = Result<'static>;
    |                  ^^^^^^--------- help: remove these generics
@@ -989,7 +1026,7 @@ LL | pub enum Result<T, E> {
    |          ^^^^^^
 
 error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:333:18
+  --> $DIR/wrong-number-of-args.rs:342:18
    |
 LL |         type C = Result<'static>;
    |                  ^^^^^^ expected 2 generic arguments
@@ -1005,7 +1042,7 @@ LL |         type C = Result<'static, T, E>;
    |                                ++++++
 
 error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:339:18
+  --> $DIR/wrong-number-of-args.rs:348:18
    |
 LL |         type D = Result<usize, String, char>;
    |                  ^^^^^^                ---- help: remove this generic argument
@@ -1019,7 +1056,7 @@ LL | pub enum Result<T, E> {
    |          ^^^^^^ -  -
 
 error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:343:18
+  --> $DIR/wrong-number-of-args.rs:352:18
    |
 LL |         type E = Result<>;
    |                  ^^^^^^ expected 2 generic arguments
index 44c46e444d66db7805e9ba6429a30309a156605b..b0089a37aa05fc1771469babced75326d4a86aee 100644 (file)
@@ -9,12 +9,12 @@ trait MyTrait {
 
 impl MyTrait for &i32 {
     type Output = &i32;
-    //~^ ERROR missing lifetime specifier
+    //~^ ERROR `&` without an explicit lifetime name cannot be used here
 }
 
 impl MyTrait for &u32 {
     type Output = &'_ i32;
-    //~^ ERROR missing lifetime specifier
+    //~^ ERROR `'_` cannot be used here
 }
 
 // This is what you have to do:
index 44955c58889aa95141d95d687ccd4360bd95ce4a..c4f27e0b80e41d5ba8a5b1424e6d39889482ec8a 100644 (file)
@@ -1,25 +1,15 @@
-error[E0106]: missing lifetime specifier
+error[E0637]: `&` without an explicit lifetime name cannot be used here
   --> $DIR/assoc-type.rs:11:19
    |
 LL |     type Output = &i32;
-   |                   ^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type Output<'a> = &'a i32;
-   |                ++++    ++
+   |                   ^ explicit lifetime name needed here
 
-error[E0106]: missing lifetime specifier
+error[E0637]: `'_` cannot be used here
   --> $DIR/assoc-type.rs:16:20
    |
 LL |     type Output = &'_ i32;
-   |                    ^^ expected named lifetime parameter
-   |
-help: consider introducing a named lifetime parameter
-   |
-LL |     type Output<'a> = &'a i32;
-   |                ++++    ~~
+   |                    ^^ `'_` is a reserved lifetime name
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+For more information about this error, try `rustc --explain E0637`.
index 97652f5462ef02487b72a2c6dc7588a4eed0f37d..efc228de58be5d482c231114cc102698ea53366b 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Swap` captures lifetime that does not appear in bounds
   --> $DIR/hidden-lifetimes.rs:29:5
    |
 LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
@@ -11,7 +11,7 @@ help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'
 LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a + 'b {
    |                                                                     ++++
 
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Swap` captures lifetime that does not appear in bounds
   --> $DIR/hidden-lifetimes.rs:46:5
    |
 LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
index bebd8286de9fec2060420df8abaadb25aec45aac..14ac688806bda2a6da34b5bc1bbe90c182125ef2 100644 (file)
@@ -7,7 +7,7 @@ fn main() {
 fn test<T: Display>(t: T, recurse: bool) -> impl Display {
     let f = || {
         let i: u32 = test::<i32>(-1, false);
-        //~^ ERROR mismatched types
+        //~^ ERROR concrete type differs from previous defining opaque type use
         println!("{i}");
     };
     if recurse {
index c1e4b823c08e7873bb4a5ba5618cba50e5e66f99..913bc8f5674acf1915d349a13f9b4b1f9585be6a 100644 (file)
@@ -1,15 +1,14 @@
-error[E0308]: mismatched types
+error: concrete type differs from previous defining opaque type use
   --> $DIR/issue-99073-2.rs:9:22
    |
-LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
-   |                                             ------------ the expected opaque type
-LL |     let f = || {
 LL |         let i: u32 = test::<i32>(-1, false);
-   |                      ^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |                      ^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `u32`
    |
-   = note: expected opaque type `impl std::fmt::Display`
-                     found type `u32`
+note: previous use here
+  --> $DIR/issue-99073-2.rs:16:5
+   |
+LL |     t
+   |     ^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
index 1d75f6086664fd6db66f24379727b7388495ff86..7798e247df0a2c77ade50b3d0a054404ec2e2526 100644 (file)
@@ -1,8 +1,8 @@
 fn main() {
-    let _ = fix(|_: &dyn Fn()| {});
+  let _ = fix(|_: &dyn Fn()| {});
 }
 
 fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
-    move || f(fix(&f))
-    //~^ ERROR mismatched types
+  move || f(fix(&f))
+  //~^ ERROR concrete type differs from previous defining opaque type use
 }
index b35d58093d5fc89c00f20762a201a11db5084879..54636795349688544df9ab794e5f53db0f0d08f1 100644 (file)
@@ -1,14 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-99073.rs:6:13
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/issue-99073.rs:6:11
    |
-LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
-   |                                    --------- the expected opaque type
-LL |     move || f(fix(&f))
-   |             ^^^^^^^^^^ types differ
+LL |   move || f(fix(&f))
+   |           ^^^^^^^^^^ expected `[closure@$DIR/issue-99073.rs:6:3: 6:10]`, got `G`
    |
-   = note: expected opaque type `impl Fn()`
-           found type parameter `G`
+note: previous use here
+  --> $DIR/issue-99073.rs:6:3
+   |
+LL |   move || f(fix(&f))
+   |   ^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
index f5aaf1185211b44d67e06cc6b7deffa351b64ea0..2a2be6b7429926c9604f9e102f439f3cffb6942a 100644 (file)
@@ -20,7 +20,7 @@ fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
         let _: &'b i32 = *u.0;
     }
     u.0
-    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+    //~^ ERROR hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds
 }
 
 fn main() {}
index b837b64110365d47585e9d702a7d52c2f51d33ca..90875708094049b19c3d45e6aa547e81a8c418a1 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds
   --> $DIR/error-handling-2.rs:22:5
    |
 LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
index 47e05bce0f8de747a9f1baa6c588917459f0bf8b..c6eea5323fd80f521780625cf3092fef5fbda1e9 100644 (file)
@@ -26,7 +26,7 @@ fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Tr
     // 'a in ['d, 'e]
     // ```
     if condition() { a } else { b }
-    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+    //~^ ERROR hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds
 }
 
 fn condition() -> bool {
index 15476c706a7f2eab942c6a0ef53faea811766d05..cb1dc0b7d50ae3cf7061270fb5eec23bf2c7fdc5 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does not appear in bounds
   --> $DIR/ordinary-bounds-unrelated.rs:28:33
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
index 321cb8c92a1774eb825e44c5d681cf48d24a5481..adcbca2a438b4132d12c5b2e31e11e6f983b2ce9 100644 (file)
@@ -29,7 +29,7 @@ fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
     //
     // We are forced to pick that '0 = 'e, because only 'e is outlived by *both* 'a and 'b.
     if condition() { a } else { b }
-    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+    //~^ ERROR hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds
 }
 
 fn condition() -> bool {
index 7315aa8e9d4787f617c65d33e42b24eee4614f08..4388e6601a6cf3d5cb092f506555c89364395af6 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does not appear in bounds
   --> $DIR/ordinary-bounds-unsuited.rs:31:33
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
index 586563c39061e34b2a3256a1ebe4cccf0520756e..16767abd72241be5988d25e8dc2593e51aa5aa5a 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds
   --> $DIR/must_outlive_least_region_or_bound.rs:3:35
    |
 LL | fn elided(x: &i32) -> impl Copy { x }
@@ -11,7 +11,7 @@ help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'
 LL | fn elided(x: &i32) -> impl Copy + '_ { x }
    |                                 ++++
 
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear in bounds
   --> $DIR/must_outlive_least_region_or_bound.rs:6:44
    |
 LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
@@ -96,7 +96,7 @@ help: alternatively, add an explicit `'static` bound to this reference
 LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x }
    |                      ~~~~~~~~~~~~
 
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Fn(&'a u32)` captures lifetime that does not appear in bounds
   --> $DIR/must_outlive_least_region_or_bound.rs:38:5
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
index 2eea726a19c5aa6622a2365b1271ee2a11a00bb7..479b451855d5517fb2a7fe6edf8358d15130874c 100644 (file)
@@ -7,7 +7,7 @@ LL | impl<T: std::fmt::Debug> AnotherTrait for T {}
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
    |
-   = note: downstream crates may implement trait `std::fmt::Debug` for type `OpaqueType`
+   = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
 
 error: cannot implement trait on type alias impl trait
   --> $DIR/negative-reasoning.rs:19:25
index a04cb1702b6388a190e5a58b1993acb9a69f9c36..fe60c76ca1755049314923ecddb553e30b05c77b 100644 (file)
@@ -15,7 +15,7 @@ fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
 where 'x: 'y
 {
     x
-    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds [E0700]
+    //~^ ERROR hidden type for `impl Trait<'y>` captures lifetime that does not appear in bounds [E0700]
 }
 
 fn main() { }
index bc02f7694d7f68d0c8f11f106bc346f2b7839886..fdb2fe022b4d250d77cd044dda70677cfe347983 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Trait<'y>` captures lifetime that does not appear in bounds
   --> $DIR/region-escape-via-bound.rs:17:5
    |
 LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y>
index 951abb127c13fdbbb0164f5c7ae3ad19a84a2a1e..b86815231550367968001756baaf66b79fafe9c3 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
   --> $DIR/static-return-lifetime-infered.rs:7:9
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
@@ -11,7 +11,7 @@ help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ++++
 
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
   --> $DIR/static-return-lifetime-infered.rs:7:9
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
@@ -24,7 +24,7 @@ help: to declare that the `impl Trait` captures `'_`, you can add an explicit `'
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
    |                                                           ++++
 
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
   --> $DIR/static-return-lifetime-infered.rs:12:9
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
@@ -37,7 +37,7 @@ help: to declare that the `impl Trait` captures `'a`, you can add an explicit `'
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
    |                                                             ++++
 
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that does not appear in bounds
   --> $DIR/static-return-lifetime-infered.rs:12:9
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
index 6103d6c6e3a6ffa1c582553b31eb8629c0002f07..d65818234ef97193dabf362725ef58395c3a40b9 100644 (file)
@@ -1,4 +1,4 @@
-error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: ~const FnOnce<()>` is not satisfied
+error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: FnOnce<()>` is not satisfied
   --> $DIR/const-eval-select-bad.rs:7:27
    |
 LL |     const_eval_select((), || {}, || {});
@@ -19,7 +19,7 @@ note: required by a bound in `const_eval_select`
 LL |     F: ~const FnOnce<ARG, Output = RET>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
-error[E0277]: the trait bound `{integer}: ~const FnOnce<()>` is not satisfied
+error[E0277]: the trait bound `{integer}: FnOnce<()>` is not satisfied
   --> $DIR/const-eval-select-bad.rs:9:27
    |
 LL |     const_eval_select((), 42, 0xDEADBEEF);
index bfe7bb2e10dccf7d9cd14252eb430fc64a0cc78c..1ced1433fe955c395c2760262ce1559f88e96a88 100644 (file)
@@ -50,13 +50,13 @@ error: arguments should be non-negative integers
 LL | #[rustc_legacy_const_generics(1, a, 2, b)]
    |                                  ^     ^
 
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
   --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:18:1
    |
 LL | #[rustc_legacy_const_generics(0)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL | struct S;
-   | --------- not a function
+   | --------- not a function definition
 
 error: #[rustc_legacy_const_generics] functions must only have const generics
   --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:29:1
@@ -66,21 +66,21 @@ LL | #[rustc_legacy_const_generics(0)]
 LL | fn foo8<X>() {}
    |         - non-const generic parameter
 
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
   --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:33:5
    |
 LL |     #[rustc_legacy_const_generics(0)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |     fn foo9<const X: usize>() {}
-   |     ---------------------------- not a function
+   |     ---------------------------- not a function definition
 
-error: attribute should be applied to a function
+error: attribute should be applied to a function definition
   --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:25:5
    |
 LL |     #[rustc_legacy_const_generics(1)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |     fn foo7<const X: usize>();
-   |     -------------------------- not a function
+   |     -------------------------- not a function definition
 
 error[E0044]: foreign items may not have const parameters
   --> $DIR/invalid-rustc_legacy_const_generics-arguments.rs:26:5
index 6521a67428eb260d7b1bc91bfc807223703eed5c..4b1d979da36e39d35200b7d66bb250ed49541d32 100644 (file)
@@ -8,7 +8,7 @@ LL |     &str
 help: consider using the `'static` lifetime
    |
 LL |     &'static str
-   |     ~~~~~~~~
+   |      +++++++
 
 error: aborting due to previous error
 
index 18f69bb57755a54c4d47659a657c01cb9cdb7fa2..3e1bb32c19b92e48676102b0544263389d645b1e 100644 (file)
@@ -22,7 +22,6 @@ LL | fn bar<F: Fn(&u8, &u8) -> &u8>(f: &F) {}
    |              ---  ---     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
-   = 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 bar<F: for<'a> Fn(&'a u8, &'a u8) -> &'a u8>(f: &F) {}
index e5f492af5b366375419267dcf17f3f9ef03f7b6d..adb721a1cbaf18c290e7eeb10cd6b62494e023e2 100644 (file)
@@ -7,8 +7,8 @@ LL | fn f(a: &S, b: i32) -> &i32 {
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `a`'s 2 lifetimes it is borrowed from
 help: consider introducing a named lifetime parameter
    |
-LL | fn f<'a>(a: &'a S, b: i32) -> &'a i32 {
-   |     ++++     ++                ++
+LL | fn f<'a>(a: &'a S<'a>, b: i32) -> &'a i32 {
+   |     ++++     ++  ++++              ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-30255.rs:14:34
@@ -19,8 +19,8 @@ LL | fn g(a: &S, b: bool, c: &i32) -> &i32 {
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `a`'s 2 lifetimes or `c`
 help: consider introducing a named lifetime parameter
    |
-LL | fn g<'a>(a: &'a S, b: bool, c: &'a i32) -> &'a i32 {
-   |     ++++     ++                 ++          ++
+LL | fn g<'a>(a: &'a S<'a>, b: bool, c: &'a i32) -> &'a i32 {
+   |     ++++     ++  ++++               ++          ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/issue-30255.rs:19:44
@@ -31,8 +31,8 @@ LL | fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a`, one of `c`'s 2 lifetimes, or `d`
 help: consider introducing a named lifetime parameter
    |
-LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S, d: &'a i32) -> &'a i32 {
-   |     ++++     ++                    ++        ++          ++
+LL | fn h<'a>(a: &'a bool, b: bool, c: &'a S<'a>, d: &'a i32) -> &'a i32 {
+   |     ++++     ++                    ++  ++++      ++          ++
 
 error: aborting due to 3 previous errors
 
index 58521b95cf637c39a887f160997bfcf1af8e0859..a1ae9a36bc1d728f6ae99d9bad3727d48b70204a 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(unreachable_code)]
-#![allow(unused_mut)] // rust-lang/rust#54586
 #![deny(unused_variables)]
 
 fn main() {
index 72fe4286a06b332ff6f4b23e25ff435886bb15bc..000ab6492bb96d6f8d0d04363e424557f7244e0c 100644 (file)
@@ -1,8 +1,11 @@
 fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
 //~^ ERROR missing lifetime specifier [E0106]
+//~| ERROR mismatched types
 
 fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
 //~^ ERROR missing lifetime specifier [E0106]
+//~| ERROR mismatched types
+//~| ERROR this function takes 1 argument but 0 arguments were supplied
 
 fn parse_type_3() -> &str { unimplemented!() }
 //~^ ERROR missing lifetime specifier [E0106]
index bb7cdcbb100fff8aa94011cce119d2bcd743ed11..f3af5cf5a35764f96c9d054889b64916afa3ccc6 100644 (file)
@@ -7,23 +7,23 @@ LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.ne
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
 help: consider introducing a named lifetime parameter
    |
-LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
-   |              ++++                                                 ++
+LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&'a str>+'static>) -> &'a str { iter.next() }
+   |              ++++                              ++                    ++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-26638.rs:4:40
+  --> $DIR/issue-26638.rs:5:40
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
    |                                        ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() }
-   |                                        ~~~~~~~~
+   |                                         +++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-26638.rs:7:22
+  --> $DIR/issue-26638.rs:10:22
    |
 LL | fn parse_type_3() -> &str { unimplemented!() }
    |                      ^ expected named lifetime parameter
@@ -32,8 +32,42 @@ LL | fn parse_type_3() -> &str { unimplemented!() }
 help: consider using the `'static` lifetime
    |
 LL | fn parse_type_3() -> &'static str { unimplemented!() }
-   |                      ~~~~~~~~
+   |                       +++++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-26638.rs:1:69
+   |
+LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
+   |                                                              ----   ^^^^^^^^^^^ expected `&str`, found enum `Option`
+   |                                                              |
+   |                                                              expected `&'static str` because of return type
+   |
+   = note: expected reference `&'static str`
+                   found enum `Option<&str>`
+
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+  --> $DIR/issue-26638.rs:5:47
+   |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+   |                                               ^^^^-- an argument of type `&u8` is missing
+   |
+help: provide the argument
+   |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter(/* &u8 */) }
+   |                                               ~~~~~~~~~~~~~~~
+
+error[E0308]: mismatched types
+  --> $DIR/issue-26638.rs:5:47
+   |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+   |                                        ----   ^^^^^^ expected `str`, found `u8`
+   |                                        |
+   |                                        expected `&'static str` because of return type
+   |
+   = note: expected reference `&'static str`
+              found reference `&u8`
 
-error: aborting due to 3 previous errors
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0061, E0106, E0308.
+For more information about an error, try `rustc --explain E0061`.
index 0e69cd50f6a825a90318c1942258775227ab2aa0..d07754879559a7c50713144adfafc6c87bc8e571 100644 (file)
@@ -8,7 +8,7 @@ LL | fn f() -> &isize {
 help: consider using the `'static` lifetime
    |
 LL | fn f() -> &'static isize {
-   |           ~~~~~~~~
+   |            +++++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:7:33
@@ -31,8 +31,8 @@ LL | fn h(_x: &Foo) -> &isize {
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `_x`'s 2 lifetimes it is borrowed from
 help: consider introducing a named lifetime parameter
    |
-LL | fn h<'a>(_x: &'a Foo) -> &'a isize {
-   |     ++++      ++          ++
+LL | fn h<'a>(_x: &'a Foo<'a>) -> &'a isize {
+   |     ++++      ++    ++++      ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:21:20
@@ -40,11 +40,11 @@ error[E0106]: missing lifetime specifier
 LL | fn i(_x: isize) -> &isize {
    |                    ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn i(_x: isize) -> &'static isize {
-   |                    ~~~~~~~~
+   |                     +++++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:34:24
@@ -52,11 +52,11 @@ error[E0106]: missing lifetime specifier
 LL | fn j(_x: StaticStr) -> &isize {
    |                        ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn j(_x: StaticStr) -> &'static isize {
-   |                        ~~~~~~~~
+   |                         +++++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:40:49
@@ -64,11 +64,11 @@ error[E0106]: missing lifetime specifier
 LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize {
    |                                                 ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'a` lifetime
    |
 LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &'a isize {
-   |                                                 ~~~
+   |                                                  ++
 
 error: aborting due to 6 previous errors
 
index d1263a4acb28a1d8cec5b00b1dac0cd9475cf277..d6c918843c700fc58d52e6a593fa2114fec5e4d1 100644 (file)
@@ -2,4 +2,4 @@ fn foo(x: &i32, y: &i32) -> &i32 { //~ ERROR missing lifetime
     if x > y { x } else { y }
 }
 
-fn main() { }
+fn main() {}
index b16b792aefee9f81e4b9e3ace0536f3d2ee0e35d..b8c68a4607da8f4dc93ca191e768dddde3748849 100644 (file)
@@ -7,7 +7,7 @@ LL | type B<'a> = <A<'a> as Trait>::Foo;
 help: consider using the `'a` lifetime
    |
 LL | type B<'a> = <A<'a> as Trait<'a>>::Foo;
-   |                        ~~~~~~~~~
+   |                             ++++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/missing-lifetime-in-alias.rs:26:28
@@ -20,6 +20,10 @@ note: these named lifetimes are available to use
    |
 LL | type C<'a, 'b> = <A<'a> as Trait>::Bar;
    |        ^^  ^^
+help: consider using one of the available lifetimes here
+   |
+LL | type C<'a, 'b> = <A<'a> as Trait<'lifetime>>::Bar;
+   |                                 +++++++++++
 
 error[E0107]: missing generics for associated type `Trait::Bar`
   --> $DIR/missing-lifetime-in-alias.rs:26:36
index 6aa34354a7ad947ca048e74bc57f1db900ebbc37..c7842667dc614ba09e725a9861bab73abbc9ec78 100644 (file)
@@ -9,6 +9,7 @@ impl<T, S: Iterator<Item = T>> Iterator for ChunkingIterator<T, S> {
     type Item = IteratorChunk<T, S>; //~ ERROR missing lifetime
 
     fn next(&mut self) -> Option<IteratorChunk<T, S>> {
+        //~^ ERROR `impl` item signature doesn't match `trait` item signature
         todo!()
     }
 }
index c7e1f87f2d4d4509c158a0e429d8d5c18e0312e9..94a9c97576f674b186ef8d7c14f12441860191c5 100644 (file)
@@ -1,14 +1,30 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-74918-missing-lifetime.rs:9:31
+  --> $DIR/issue-74918-missing-lifetime.rs:9:30
    |
 LL |     type Item = IteratorChunk<T, S>;
-   |                               ^ expected named lifetime parameter
+   |                              ^ expected named lifetime parameter
    |
 help: consider introducing a named lifetime parameter
    |
 LL |     type Item<'a> = IteratorChunk<'a, T, S>;
    |              ++++                 +++
 
-error: aborting due to previous error
+error: `impl` item signature doesn't match `trait` item signature
+  --> $DIR/issue-74918-missing-lifetime.rs:11:5
+   |
+LL |     fn next(&mut self) -> Option<IteratorChunk<T, S>> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+   |
+  ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn next(&mut self) -> Option<Self::Item>;
+   |     ----------------------------------------- expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+   |
+   = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+              found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
+   = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+   = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.fixed b/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.fixed
new file mode 100644 (file)
index 0000000..63b65ab
--- /dev/null
@@ -0,0 +1,17 @@
+// run-rustfix
+
+macro_rules! my_wrapper {
+    ($expr:expr) => { MyWrapper($expr) }
+}
+
+pub struct MyWrapper(u32);
+
+fn main() {
+    let value = MyWrapper(123);
+    some_fn(value); //~ ERROR mismatched types
+    some_fn(my_wrapper!(123)); //~ ERROR mismatched types
+}
+
+fn some_fn(wrapped: MyWrapper) {
+    drop(wrapped);
+}
diff --git a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.rs b/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.rs
new file mode 100644 (file)
index 0000000..2ab4e39
--- /dev/null
@@ -0,0 +1,17 @@
+// run-rustfix
+
+macro_rules! my_wrapper {
+    ($expr:expr) => { MyWrapper($expr) }
+}
+
+pub struct MyWrapper(u32);
+
+fn main() {
+    let value = MyWrapper(123);
+    some_fn(value.0); //~ ERROR mismatched types
+    some_fn(my_wrapper!(123).0); //~ ERROR mismatched types
+}
+
+fn some_fn(wrapped: MyWrapper) {
+    drop(wrapped);
+}
diff --git a/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.stderr b/src/test/ui/mismatched_types/suggest-removing-tulpe-struct-field.stderr
new file mode 100644 (file)
index 0000000..82a7f27
--- /dev/null
@@ -0,0 +1,41 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-removing-tulpe-struct-field.rs:11:13
+   |
+LL |     some_fn(value.0);
+   |     ------- ^^^^^^^ expected struct `MyWrapper`, found `u32`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/suggest-removing-tulpe-struct-field.rs:15:4
+   |
+LL | fn some_fn(wrapped: MyWrapper) {
+   |    ^^^^^^^ ------------------
+help: consider removing the tuple struct field `0`
+   |
+LL -     some_fn(value.0);
+LL +     some_fn(value);
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-removing-tulpe-struct-field.rs:12:13
+   |
+LL |     some_fn(my_wrapper!(123).0);
+   |     ------- ^^^^^^^^^^^^^^^^^^ expected struct `MyWrapper`, found `u32`
+   |     |
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/suggest-removing-tulpe-struct-field.rs:15:4
+   |
+LL | fn some_fn(wrapped: MyWrapper) {
+   |    ^^^^^^^ ------------------
+help: consider removing the tuple struct field `0`
+   |
+LL -     some_fn(my_wrapper!(123).0);
+LL +     some_fn(my_wrapper!(123));
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index ab0dfe5fca41c90d8cb68476ee518d371a65a340..260b9b59772ef789dce466859d8b913896e7ec65 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Iterator<Item = u8>` captures lifetime that does not appear in bounds
   --> $DIR/issue-73159-rpit-static.rs:8:9
    |
 LL | impl<'a> Foo<'a> {
index 31dc58185e90ab0bb38d941c68c74915e785438d..e13ae80f918b2be0fb9d0e341cd95421866e4fa7 100644 (file)
@@ -19,7 +19,7 @@ struct FailStruct { }
 
 impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
     const AC: Option<&'c str> = None;
-    //~^ ERROR: mismatched types
+    //~^ ERROR: const not compatible with trait
 }
 
 struct OKStruct2 { }
index 000ebc716572a9fa039b336fb8b828ccdfc5a025..ae0ffd904e7996e496e9ccf18adfe3ecb9feac32 100644 (file)
@@ -1,4 +1,4 @@
-error[E0308]: mismatched types
+error[E0308]: const not compatible with trait
   --> $DIR/trait-associated-constant.rs:21:5
    |
 LL |     const AC: Option<&'c str> = None;
index 06256ebbc29a30fb3f351f6dbdea5ca525d706a9..330c6fafa2d61a86eec9139b953d195909120a1c 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `Opaque(DefId(0:11 ~ impl_trait_captures[1afc]::foo::{opaque#0}), [ReStatic, T, ReEarlyBound(0, 'a)])` captures lifetime that does not appear in bounds
   --> $DIR/impl-trait-captures.rs:11:5
    |
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
index 549135a46cf1019b4ae42b608994b5d5ede69938..3ddf8d6ef24054f8e05793ed9db13ae580bf156b 100644 (file)
@@ -6,7 +6,7 @@
 // dont-check-compiler-stderr
 // only-linux
 // no-prefer-dynamic
-// compile-flags: -Ctarget-feature=+crt-static -Crpath=no
+// compile-flags: -Ctarget-feature=+crt-static -Crpath=no -Crelocation-model=static
 #![feature(exit_status_error)]
 #![feature(rustc_private)]
 extern crate libc;
index 4397baea4a940a76fe06293c69bd5e81959f9220..c377ecea94d0c4ab2deda58974bae6077bb08506 100644 (file)
@@ -2,5 +2,5 @@ fn main() {}
 
 trait Foo {
     fn fn_with_type_named_same_as_local_in_param(b: b);
-    //~^ ERROR cannot find type `b` in this scope
+    //~^ ERROR cannot find type `b` in this scope [E0412]
 }
index 8df68225d44cd34c1b448fbfb39e0ea2c2ec5ff1..2bc5ee512c52fd1c77672e55b8c89926409a3756 100644 (file)
@@ -3,7 +3,6 @@
 pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
     *t == *t
     //~^ ERROR can't compare
-    //~| ERROR cannot call non-const
 }
 
 fn main() {}
index cf114334cc39187dbbbe1cbc5461cb8fa40bbd55..83d395dda196ae6af7abaa9a1680e05246dcbd98 100644 (file)
@@ -1,28 +1,16 @@
-error[E0277]: can't compare `T` with `T` in const contexts
-  --> $DIR/call-generic-method-fail.rs:4:5
+error[E0277]: can't compare `T` with `_` in const contexts
+  --> $DIR/call-generic-method-fail.rs:4:8
    |
 LL |     *t == *t
-   |     ^^^^^^^^ no implementation for `T == T`
+   |        ^^ no implementation for `T == _`
    |
-note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const`
-  --> $DIR/call-generic-method-fail.rs:4:5
+note: the trait `PartialEq<_>` is implemented for `T`, but that implementation is not `const`
+  --> $DIR/call-generic-method-fail.rs:4:8
    |
 LL |     *t == *t
-   |     ^^^^^^^^
+   |        ^^
+   = help: the trait `PartialEq<&B>` is implemented for `&A`
 
-error[E0015]: cannot call non-const operator in constant functions
-  --> $DIR/call-generic-method-fail.rs:4:5
-   |
-LL |     *t == *t
-   |     ^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: consider further restricting this bound
-   |
-LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
-   |                                       ++++++++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0015, E0277.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
index 0b981d1621ecaf06f80bf1da905d932455bdc1da..140a06a73ac6d636909b49517ba77a2d4161846a 100644 (file)
@@ -23,7 +23,6 @@ fn b(self) {}
 const fn test() {
     NonConstImpl.a();
     //~^ ERROR the trait bound
-    //~| ERROR cannot call non-const fn
     ConstImpl.a();
 }
 
index fe788b43a5416b4330279af3a43c805930b8dfa9..ec724cc9675f134dc8d422b7209ec448ed4c6cbe 100644 (file)
@@ -2,23 +2,18 @@ error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satis
   --> $DIR/const-default-method-bodies.rs:24:18
    |
 LL |     NonConstImpl.a();
-   |                  ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
+   |                  ^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
    |
 note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
   --> $DIR/const-default-method-bodies.rs:24:18
    |
 LL |     NonConstImpl.a();
-   |                  ^^^
-
-error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
-  --> $DIR/const-default-method-bodies.rs:24:18
-   |
-LL |     NonConstImpl.a();
-   |                  ^^^
+   |                  ^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+LL | const fn test() where NonConstImpl: ~const ConstDefaultFn {
+   |                 +++++++++++++++++++++++++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0015, E0277.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr
deleted file mode 100644 (file)
index 3ca9abb..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
-  --> $DIR/cross-crate.rs:15:14
-   |
-LL |     NonConst.func();
-   |              ^^^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
-   |
-note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
-  --> $DIR/cross-crate.rs:15:14
-   |
-LL |     NonConst.func();
-   |              ^^^^^^
-
-error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:15:14
-   |
-LL |     NonConst.func();
-   |              ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0015, E0277.
-For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.gatednc.stderr
new file mode 100644 (file)
index 0000000..174c629
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
+  --> $DIR/cross-crate.rs:17:14
+   |
+LL |     NonConst.func();
+   |              ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
+   |
+note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
+  --> $DIR/cross-crate.rs:17:14
+   |
+LL |     NonConst.func();
+   |              ^^^^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | const fn const_context() where cross_crate::NonConst: ~const cross_crate::MyTrait {
+   |                          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index fa049ab86ff49c0b1016760e0e3618e7cf4b5463..6df47022cc948077b0d64c82871d7e3db3a2ec6c 100644 (file)
@@ -1,5 +1,6 @@
-// revisions: stock gated
-#![cfg_attr(gated, feature(const_trait_impl))]
+// revisions: stock gated stocknc gatednc
+// [gated] check-pass
+#![cfg_attr(any(gated, gatednc), feature(const_trait_impl))]
 
 // aux-build: cross-crate.rs
 extern crate cross_crate;
@@ -12,10 +13,12 @@ fn non_const_context() {
 }
 
 const fn const_context() {
-    NonConst.func(); //~ ERROR: cannot call non-const fn
-    //[gated]~^ ERROR: the trait bound
+    #[cfg(any(stocknc, gatednc))]
+    NonConst.func();
+    //[stocknc]~^ ERROR: the trait bound
+    //[gatednc]~^^ ERROR: the trait bound
     Const.func();
-    //[stock]~^ ERROR: cannot call non-const fn
+    //[stock]~^ ERROR: cannot call
 }
 
 fn main() {}
index ea75ad0aeaf8c2eba9b92532aa86fa856f9a9833..086547542bb095323cd027ca5d7ea5746a1289f3 100644 (file)
@@ -1,19 +1,11 @@
-error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:15:14
-   |
-LL |     NonConst.func();
-   |              ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
 error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:17:11
+  --> $DIR/cross-crate.rs:20:11
    |
 LL |     Const.func();
    |           ^^^^^^
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr b/src/test/ui/rfc-2632-const-trait-impl/cross-crate.stocknc.stderr
new file mode 100644 (file)
index 0000000..4619dd1
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `cross_crate::NonConst: cross_crate::MyTrait` is not satisfied
+  --> $DIR/cross-crate.rs:17:14
+   |
+LL |     NonConst.func();
+   |              ^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
+   |
+note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
+  --> $DIR/cross-crate.rs:17:14
+   |
+LL |     NonConst.func();
+   |              ^^^^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | const fn const_context() where cross_crate::NonConst: ~const cross_crate::MyTrait {
+   |                          ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index d798516ff70fd05608449ff0b7e0c44c39d624e7..f70ecbc3746f992c8b4974a4a6dccc3b950e42f5 100644 (file)
@@ -7,7 +7,6 @@ fn a(&self) {}
     fn b(&self) {
         ().a()
         //~^ ERROR the trait bound
-        //~| ERROR cannot call
     }
 }
 
index 8bb7f0141033de1ab601b90c0c39fb0857e25c6c..b229053eb50cfa5e3aaa1bcd6a2aaa10e6bd5499 100644 (file)
@@ -2,23 +2,18 @@ error[E0277]: the trait bound `(): ~const Tr` is not satisfied
   --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
    |
 LL |         ().a()
-   |            ^^^ the trait `~const Tr` is not implemented for `()`
+   |            ^ the trait `~const Tr` is not implemented for `()`
    |
 note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
   --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
    |
 LL |         ().a()
-   |            ^^^
-
-error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
-   |
-LL |         ().a()
-   |            ^^^
+   |            ^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+LL | pub trait Tr where (): ~const Tr {
+   |              +++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0015, E0277.
-For more information about an error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
index 35a2ef10c2e3c48612ffc274c0587cba5d02355d..26fa6fdb57f95a90482c357a4d926c331bd7c7db 100644 (file)
@@ -9,5 +9,6 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
 //~^ ERROR missing lifetime specifier [E0106]
     &(non_elidable as fn(&u8, &u8) -> &u8);
     //~^ ERROR missing lifetime specifier [E0106]
+    //~| ERROR non-primitive cast
 
 fn main() {}
index 65b9f68817aa42f28d951d1a4ce5cf929d2523b7..495d45e2234169843d93cbbc599169ec2ca3d37b 100644 (file)
@@ -18,12 +18,18 @@ LL |     &(non_elidable as fn(&u8, &u8) -> &u8);
    |                          ---  ---     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
-   = 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 |     &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
    |                       +++++++     ++      ++         ++
 
-error: aborting due to 2 previous errors
+error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'r, 's> fn(&'r u8, &'s u8) -> &u8`
+  --> $DIR/rfc1623-2.rs:10:6
+   |
+LL |     &(non_elidable as fn(&u8, &u8) -> &u8);
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0106`.
+Some errors have detailed explanations: E0106, E0605.
+For more information about an error, try `rustc --explain E0106`.
index 5b8b9bb68ad1e916c397e2413614d6ad3b6baebd..7e7d60d0ff90aef2027871ce6ede64c0200cbab6 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Clone` captures lifetime that does not appear in bounds
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48
    |
 LL |     async fn f(self: Pin<&Self>) -> impl Clone { self }
index abdc650c68e78d46b85949e92ba38e38c448123a..30d2250c0c81df7df862e1a5cef0def48e0f6377 100644 (file)
@@ -1,4 +1,4 @@
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl Clone` captures lifetime that does not appear in bounds
   --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
    |
 LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-child.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-child.rs
new file mode 100644 (file)
index 0000000..15e0af1
--- /dev/null
@@ -0,0 +1,8 @@
+#![crate_type = "lib"]
+
+extern crate core;
+
+pub mod __private {
+    #[doc(hidden)]
+    pub use core::option::Option::{self, None, Some};
+}
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-parent.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/hidden-parent.rs
new file mode 100644 (file)
index 0000000..5a5079d
--- /dev/null
@@ -0,0 +1,8 @@
+#![crate_type = "lib"]
+
+extern crate core;
+
+#[doc(hidden)]
+pub mod __private {
+    pub use core::option::Option::{self, None, Some};
+}
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.rs
new file mode 100644 (file)
index 0000000..38dabc9
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:hidden-child.rs
+
+// FIXME(compiler-errors): This currently suggests the wrong thing.
+// UI test exists to track the problem.
+
+extern crate hidden_child;
+
+fn main() {
+    let x: Option<i32> = 1i32; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-child.stderr
new file mode 100644 (file)
index 0000000..67f4ac0
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/hidden-child.rs:9:26
+   |
+LL |     let x: Option<i32> = 1i32;
+   |            -----------   ^^^^ expected enum `Option`, found `i32`
+   |            |
+   |            expected due to this
+   |
+   = note: expected enum `Option<i32>`
+              found type `i32`
+help: try wrapping the expression in `hidden_child::__private::Some`
+   |
+LL |     let x: Option<i32> = hidden_child::__private::Some(1i32);
+   |                          ++++++++++++++++++++++++++++++    +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.rs
new file mode 100644 (file)
index 0000000..4d96d6c
--- /dev/null
@@ -0,0 +1,7 @@
+// aux-build:hidden-parent.rs
+
+extern crate hidden_parent;
+
+fn main() {
+    let x: Option<i32> = 1i32; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.stderr b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/hidden-parent.stderr
new file mode 100644 (file)
index 0000000..d92b812
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/hidden-parent.rs:6:26
+   |
+LL |     let x: Option<i32> = 1i32;
+   |            -----------   ^^^^ expected enum `Option`, found `i32`
+   |            |
+   |            expected due to this
+   |
+   = note: expected enum `Option<i32>`
+              found type `i32`
+help: try wrapping the expression in `Some`
+   |
+LL |     let x: Option<i32> = Some(1i32);
+   |                          +++++    +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index a761ec5916745d5a5df8bcdd450159165eed0abb..6d7c3d73097a9e2f0daa5c6e27eaeff4ba23afb4 100644 (file)
@@ -21,7 +21,6 @@ LL | struct S2<F: Fn(&i32, &i32) -> &i32>(F);
    |                 ----  ----     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
-   = 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 | struct S2<F: for<'a> Fn(&'a i32, &'a i32) -> &'a i32>(F);
index 9adc9679eee479d6777ca20e1f02383ed996fef5..e82a6f769e090083d7c8ce9165d59309b61eae0f 100644 (file)
@@ -1,43 +1,43 @@
-error[E0658]: anonymous lifetimes in `impl Trait` are unstable
-  --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31
-   |
-LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
-   |                               ^^
-   |
-   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
-
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:8:50
    |
 LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
    |                                                  ^^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
    |                                                  ~~~~~~~
 
-error[E0658]: anonymous lifetimes in `impl Trait` are unstable
-  --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31
-   |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                               ^^
-   |
-   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
-
 error[E0106]: missing lifetime specifier
   --> $DIR/impl-trait-missing-lifetime-gated.rs:18:56
    |
 LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
    |                                                        ^^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
    |                                                        ~~~~~~~
 
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:5:31
+   |
+LL | fn f(_: impl Iterator<Item = &'_ ()>) {}
+   |                               ^^
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+
+error[E0658]: anonymous lifetimes in `impl Trait` are unstable
+  --> $DIR/impl-trait-missing-lifetime-gated.rs:8:31
+   |
+LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                               ^^
+   |
+   = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable
+
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0106, E0658.
index dcc716f56b70510ac6b39960b47a2de4dcfb0e16..6f7c912d707cf187a0d71b183b8ca144a6a944c2 100644 (file)
@@ -6,14 +6,15 @@
 fn f(_: impl Iterator<Item = &'_ ()>) {}
 
 // But that lifetime does not participate in resolution.
-fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
 //~^ ERROR missing lifetime specifier
 
 // This is understood as `fn foo<'_1>(_: impl Iterator<Item = &'_1 ()>) {}`.
 async fn h(_: impl Iterator<Item = &'_ ()>) {}
 
 // But that lifetime does not participate in resolution.
-async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
 //~^ ERROR missing lifetime specifier
+//~| ERROR lifetime may not live long enough
 
 fn main() {}
index d3c64cb466d74089f643c86791db05cbe4741dbf..b476d61017f1489161f69cf1eb5bb07a74fe1604 100644 (file)
@@ -1,27 +1,35 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-trait-missing-lifetime.rs:9:50
+  --> $DIR/impl-trait-missing-lifetime.rs:9:54
    |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                                                  ^^ expected named lifetime parameter
+LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                      ^^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | fn g(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
-   |                                                  ~~~~~~~
+LL | fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                      ~~~~~~~
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-trait-missing-lifetime.rs:16:56
+  --> $DIR/impl-trait-missing-lifetime.rs:16:60
    |
-LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
-   |                                                        ^^ expected named lifetime parameter
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                            ^^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | async fn i(x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
-   |                                                        ~~~~~~~
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'static ()> { x.next() }
+   |                                                            ~~~~~~~
 
-error: aborting due to 2 previous errors
+error: lifetime may not live long enough
+  --> $DIR/impl-trait-missing-lifetime.rs:16:69
+   |
+LL | async fn i(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> { x.next() }
+   |                                                    --------------   ^^^^^^^^ returning this value requires that `'1` must outlive `'static`
+   |                                                    |
+   |                                                    return type `impl Future<Output = Option<&'static ()>>` contains a lifetime `'1`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
index 6aceb13746937cc1cfedf32ba0fd28d8e6f613b2..366787df1b4dd8c89ba94991e85b71e2cf1e7c22 100644 (file)
@@ -6,6 +6,7 @@
 async fn a(s1: &str, s2: &str) -> &str {
 //~^ ERROR: missing lifetime specifier [E0106]
     s1
+//~^ ERROR: lifetime may not live long enough
 }
 
 fn b(s1: &str, s2: &str) -> &str {
index 14dbbfffb0e622b8fc1f5b76a0dd24292e7ef112..8d611641626e136dfa6d2b88e54b3d486ba14311 100644 (file)
@@ -11,7 +11,7 @@ LL | async fn a<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    |           ++++      ++           ++          ++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-86667.rs:11:29
+  --> $DIR/issue-86667.rs:12:29
    |
 LL | fn b(s1: &str, s2: &str) -> &str {
    |          ----      ----     ^ expected named lifetime parameter
@@ -22,6 +22,15 @@ help: consider introducing a named lifetime parameter
 LL | fn b<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    |     ++++      ++           ++          ++
 
-error: aborting due to 2 previous errors
+error: lifetime may not live long enough
+  --> $DIR/issue-86667.rs:8:5
+   |
+LL | async fn a(s1: &str, s2: &str) -> &str {
+   |                - let's call the lifetime of this reference `'1`
+LL |
+LL |     s1
+   |     ^^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
index 19a791a8c43afaba403b497eb8a6124d7dd0f3d4..b641f5941dcef64708f90cc6cdc2843bf40489cf 100644 (file)
@@ -17,7 +17,7 @@ fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
     G: Get<T>,
 {
     move || {
-        //~^ ERROR hidden type for `impl Trait` captures lifetime
+        //~^ ERROR hidden type for `impl FnOnce()` captures lifetime
         *dest = g.get();
     }
 }
index e3fe25d5f9c97e3e3484b3b6e61284a4ef36268f..0d749f04bea770154c7c43b7b1b85e4de6a8cef3 100644 (file)
@@ -6,7 +6,7 @@ LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
    |        |
    |        help: consider introducing lifetime `'a` here: `'a,`
 
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+error[E0700]: hidden type for `impl FnOnce()` 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()
index 1ecaade93c8ca8026df321a4d97546a0ea343291..233f1bc5a86eed3ffb6a3772ba7e57a88075bfcd 100644 (file)
@@ -4,10 +4,6 @@ error[E0106]: missing lifetime specifier
 LL |     const A: &str = "";
    |              ^ expected named lifetime parameter
    |
-help: consider using the `'static` lifetime
-   |
-LL |     const A: &'static str = "";
-   |               +++++++
 help: consider introducing a named lifetime parameter
    |
 LL ~ trait ZstAssert<'a>: Sized {
@@ -20,10 +16,6 @@ error[E0106]: missing lifetime specifier
 LL |     const B: S = S { s: &() };
    |              ^ expected named lifetime parameter
    |
-help: consider using the `'static` lifetime
-   |
-LL |     const B: S<'static> = S { s: &() };
-   |               +++++++++
 help: consider introducing a named lifetime parameter
    |
 LL ~ trait ZstAssert<'a>: Sized {
@@ -37,10 +29,6 @@ error[E0106]: missing lifetime specifier
 LL |     const C: &'_ str = "";
    |               ^^ expected named lifetime parameter
    |
-help: consider using the `'static` lifetime
-   |
-LL |     const C: &'static str = "";
-   |               ~~~~~~~
 help: consider introducing a named lifetime parameter
    |
 LL ~ trait ZstAssert<'a>: Sized {
@@ -55,10 +43,6 @@ error[E0106]: missing lifetime specifiers
 LL |     const D: T = T { a: &(), b: &() };
    |              ^ expected 2 lifetime parameters
    |
-help: consider using the `'static` lifetime
-   |
-LL |     const D: T<'static, 'static> = T { a: &(), b: &() };
-   |               ++++++++++++++++++
 help: consider introducing a named lifetime parameter
    |
 LL ~ trait ZstAssert<'a>: Sized {
index ce847c86bedde078bf1190e1127ba9f86d8fa6d8..24f5f782f35211dc7904478e86773c94af614ab3 100644 (file)
@@ -21,22 +21,18 @@ trait Tar<'t, 'k, I> {}
 }
 thread_local! {
     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-      //~^ ERROR missing lifetime specifier
-      //~| ERROR missing lifetime specifier
-      //~| ERROR missing lifetime specifier
-      //~| ERROR missing lifetime specifier
+      //~^ ERROR missing lifetime specifiers
+      //~| ERROR missing lifetime specifiers
 }
 thread_local! {
     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
-    //~^ ERROR missing lifetime
-    //~| ERROR missing lifetime
+    //~^ ERROR missing lifetime specifiers
+    //~| ERROR missing lifetime specifiers
 }
 thread_local! {
     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-    //~^ ERROR missing lifetime
-    //~| ERROR missing lifetime
-    //~| ERROR missing lifetime
-    //~| ERROR missing lifetime
+    //~^ ERROR missing lifetime specifiers
+    //~| ERROR missing lifetime specifiers
 }
 
 thread_local! {
index 1498337549d81f2f976ba5050cace6126002087f..10fb28c1891973898a36c303f84283c6bb4ef4a9 100644 (file)
@@ -8,7 +8,7 @@ LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::
 help: consider using the `'static` lifetime
    |
 LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefCell::new(HashMap::new());
-   |                                            ~~~~~~~~~~~~~~~~~~~~~
+   |                                               ++++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
   --> $DIR/missing-lifetime-specifier.rs:18:44
@@ -23,38 +23,28 @@ LL | | }
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
   --> $DIR/missing-lifetime-specifier.rs:23:44
    |
 LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   |                                            ^ expected named lifetime parameter
+   |                                            ^^^^ expected 2 lifetime parameters
+   |                                            |
+   |                                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar>>>> = RefCell::new(HashMap::new());
-   |                                            ~~~~~~~~
+LL |     static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
+   |                                             +++++++    ++++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:23:45
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^ expected 2 lifetime parameters
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
-   |                                             ~~~~~~~~~~~~~~~~~~~~~
-
-error[E0106]: missing lifetime specifier
   --> $DIR/missing-lifetime-specifier.rs:23:44
    |
 LL | / thread_local! {
 LL | |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   | |                                            ^ expected named lifetime parameter
-LL | |
-LL | |
+   | |                                            ^^^^ expected 2 lifetime parameters
+   | |                                            |
+   | |                                            expected named lifetime parameter
 LL | |
 LL | |
 LL | | }
@@ -63,25 +53,10 @@ LL | | }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:23:45
-   |
-LL | / thread_local! {
-LL | |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   | |                                             ^^^ expected 2 lifetime parameters
-LL | |
-LL | |
-LL | |
-LL | |
-LL | | }
-   | |_-
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
-
-error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:30:48
+  --> $DIR/missing-lifetime-specifier.rs:28:47
    |
 LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
-   |                                                ^ expected 2 lifetime parameters
+   |                                               ^ expected 2 lifetime parameters
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
@@ -90,11 +65,11 @@ LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                +++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:30:48
+  --> $DIR/missing-lifetime-specifier.rs:28:47
    |
 LL | / thread_local! {
 LL | |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
-   | |                                                ^ expected 2 lifetime parameters
+   | |                                               ^ expected 2 lifetime parameters
 LL | |
 LL | |
 LL | | }
@@ -102,38 +77,28 @@ LL | | }
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:35:44
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ~~~~~~~~
-
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:35:49
+  --> $DIR/missing-lifetime-specifier.rs:33:44
    |
 LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                                 ^ expected 2 lifetime parameters
+   |                                            ^   ^ expected 2 lifetime parameters
+   |                                            |
+   |                                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                                 +++++++++++++++++
+LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                             +++++++     +++++++++++++++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:35:44
+error[E0106]: missing lifetime specifiers
+  --> $DIR/missing-lifetime-specifier.rs:33:44
    |
 LL | / thread_local! {
 LL | |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   | |                                            ^ expected named lifetime parameter
-LL | |
-LL | |
+   | |                                            ^   ^ expected 2 lifetime parameters
+   | |                                            |
+   | |                                            expected named lifetime parameter
 LL | |
 LL | |
 LL | | }
@@ -141,23 +106,35 @@ LL | | }
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
 
-error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:35:49
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lifetime-specifier.rs:47:44
+   |
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                            ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+   |
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                             +++++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/missing-lifetime-specifier.rs:47:44
    |
 LL | / thread_local! {
-LL | |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   | |                                                 ^ expected 2 lifetime parameters
-LL | |
+LL | |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+   | |                                            ^ expected named lifetime parameter
 LL | |
 LL | |
+...  |
 LL | |
 LL | | }
    | |_-
    |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -175,7 +152,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                       +++++++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -193,7 +170,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefC
    |                                                       ++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -211,7 +188,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefC
    |                                                       ++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -229,7 +206,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'k, i32>>>>> = RefC
    |                                                       ++++
 
 error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:43:44
+  --> $DIR/missing-lifetime-specifier.rs:39:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -247,7 +224,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                       +++++++++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -264,20 +241,8 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:51:44
-   |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ~~~~~~~~
-
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -294,23 +259,8 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        ++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:51:44
-   |
-LL | / thread_local! {
-LL | |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   | |                                            ^ expected named lifetime parameter
-LL | |
-LL | |
-...  |
-LL | |
-LL | | }
-   | |_-
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
-
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -328,7 +278,7 @@ LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = Ref
    |                                                        ++++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -346,7 +296,7 @@ LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'k, i32>>>>> = Ref
    |                                                        ++++
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:51:45
+  --> $DIR/missing-lifetime-specifier.rs:47:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -363,7 +313,7 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error: aborting due to 24 previous errors
+error: aborting due to 20 previous errors
 
 Some errors have detailed explanations: E0106, E0107.
 For more information about an error, try `rustc --explain E0106`.
index a90a90122ad19f1cb3f79b8c881f544eaea1e84d..04ea3d831c93a9cd6b595d9fff8335208ed6bc67 100644 (file)
@@ -1,10 +1,8 @@
 struct X<'a>(&'a ());
 struct S<'a>(&'a dyn Fn(&X) -> &X);
-//~^ ERROR missing lifetime specifier
-//~| ERROR missing lifetime specifier
+//~^ ERROR missing lifetime specifiers
 struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-//~^ ERROR missing lifetime specifier
-//~| ERROR missing lifetime specifier
+//~^ ERROR missing lifetime specifiers
 
 fn main() {
     let x = S(&|x| {
index 33f9d092e6ee0444a7b5d685e11c7b54c1404053..fa515644431ac0a3e5564ed662f95cbcfedeb8d5 100644 (file)
@@ -1,67 +1,36 @@
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
   --> $DIR/missing-lt-for-hrtb.rs:2:32
    |
 LL | struct S<'a>(&'a dyn Fn(&X) -> &X);
-   |                         --     ^ expected named lifetime parameter
+   |                         --     ^^ expected named lifetime parameter
+   |                                |
+   |                                expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
-   = 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 | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &'b X);
-   |                      +++++++    ~~~~~     ~~~
-help: consider using the `'a` lifetime
-   |
-LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X);
-   |                                ~~~
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lt-for-hrtb.rs:2:33
-   |
-LL | struct S<'a>(&'a dyn Fn(&X) -> &X);
-   |                         --      ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
-   = 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 | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &X<'b>);
-   |                      +++++++    ~~~~~      ~~~~~
 help: consider using the `'a` lifetime
    |
-LL | struct S<'a>(&'a dyn Fn(&X) -> &X<'a>);
-   |                                 ~~~~~
+LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X<'a>);
+   |                                 ++  ++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lt-for-hrtb.rs:5:40
+error[E0106]: missing lifetime specifiers
+  --> $DIR/missing-lt-for-hrtb.rs:4:40
    |
 LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-   |                                 --     ^ expected named lifetime parameter
+   |                                 --     ^^ expected named lifetime parameter
+   |                                        |
+   |                                        expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
 note: these named lifetimes are available to use
-  --> $DIR/missing-lt-for-hrtb.rs:5:10
+  --> $DIR/missing-lt-for-hrtb.rs:4:10
    |
 LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
    |          ^^              ^^
 help: consider using one of the available lifetimes here
    |
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X);
-   |                                         +++++++++
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lt-for-hrtb.rs:5:41
-   |
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-   |                                 --      ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
-note: these named lifetimes are available to use
-  --> $DIR/missing-lt-for-hrtb.rs:5:10
-   |
-LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X);
-   |          ^^              ^^
+LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &'lifetime X<'lifetime>);
+   |                                         +++++++++  +++++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
index ca336bbb056d5105847adb9c12be2fc39b0ac935..012d5492a0404300fc618e4736f0c392dc32aa0f 100644 (file)
@@ -6,32 +6,27 @@
 fn f1() -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f1_() -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 fn f2(a: i32, b: i32) -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 struct S<'a, 'b> { a: &'a i32, b: &'b i32 }
 fn f3(s: &S) -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
 //~^ ERROR missing lifetime specifier [E0106]
 fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
-//~^ ERROR missing lifetime specifier [E0106]
-//~^^ ERROR missing lifetime specifier [E0106]
+//~^ ERROR missing lifetime specifiers [E0106]
 
 fn main() {}
index f147b4463e2f21e7af310676bbb9c9e16c4790b0..273d95bc747d37b24c04b55f48b8ebb6f25bd1ed 100644 (file)
@@ -8,70 +8,50 @@ LL | fn f1() -> &i32 { loop {} }
 help: consider using the `'static` lifetime
    |
 LL | fn f1() -> &'static i32 { loop {} }
-   |            ~~~~~~~~
+   |             +++++++
 
-error[E0106]: missing lifetime specifier
+error[E0106]: missing lifetime specifiers
   --> $DIR/return-elided-lifetime.rs:8:14
    |
 LL | fn f1_() -> (&i32, &i32) { loop {} }
-   |              ^ expected named lifetime parameter
+   |              ^     ^ expected named lifetime parameter
+   |              |
+   |              expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | fn f1_() -> (&'static i32, &i32) { loop {} }
-   |              ~~~~~~~~
+LL | fn f1_() -> (&'static i32, &'static i32) { loop {} }
+   |               +++++++       +++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:8:20
-   |
-LL | fn f1_() -> (&i32, &i32) { loop {} }
-   |                    ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
-   |
-LL | fn f1_() -> (&i32, &'static i32) { loop {} }
-   |                    ~~~~~~~~
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:12:26
+  --> $DIR/return-elided-lifetime.rs:11:26
    |
 LL | fn f2(a: i32, b: i32) -> &i32 { loop {} }
    |                          ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
 LL | fn f2(a: i32, b: i32) -> &'static i32 { loop {} }
-   |                          ~~~~~~~~
+   |                           +++++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:14:28
+error[E0106]: missing lifetime specifiers
+  --> $DIR/return-elided-lifetime.rs:13:28
    |
 LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
-   |                            ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-help: consider using the `'static` lifetime
+   |                            ^     ^ expected named lifetime parameter
+   |                            |
+   |                            expected named lifetime parameter
    |
-LL | fn f2_(a: i32, b: i32) -> (&'static i32, &i32) { loop {} }
-   |                            ~~~~~~~~
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:14:34
-   |
-LL | fn f2_(a: i32, b: i32) -> (&i32, &i32) { loop {} }
-   |                                  ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime
    |
-LL | fn f2_(a: i32, b: i32) -> (&i32, &'static i32) { loop {} }
-   |                                  ~~~~~~~~
+LL | fn f2_(a: i32, b: i32) -> (&'static i32, &'static i32) { loop {} }
+   |                             +++++++       +++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:19:17
+  --> $DIR/return-elided-lifetime.rs:17:17
    |
 LL | fn f3(s: &S) -> &i32 { loop {} }
    |          --     ^ expected named lifetime parameter
@@ -79,42 +59,32 @@ LL | fn f3(s: &S) -> &i32 { loop {} }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `s`'s 3 lifetimes it is borrowed from
 help: consider introducing a named lifetime parameter
    |
-LL | fn f3<'a>(s: &'a S) -> &'a i32 { loop {} }
-   |      ++++     ++        ++
+LL | fn f3<'a>(s: &'a S<'a, 'a>) -> &'a i32 { loop {} }
+   |      ++++     ++  ++++++++      ++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:21:26
+error[E0106]: missing lifetime specifiers
+  --> $DIR/return-elided-lifetime.rs:19:26
    |
 LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
-   |           --     --      ^ expected named lifetime parameter
+   |           --     --      ^     ^ expected named lifetime parameter
+   |                          |
+   |                          expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes
 help: consider introducing a named lifetime parameter
    |
-LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&'a i32, &i32) { loop {} }
-   |       ++++     ++        ++         ++
+LL | fn f3_<'a>(s: &'a S<'a, 'a>, t: &'a S<'a, 'a>) -> (&'a i32, &'a i32) { loop {} }
+   |       ++++     ++  ++++++++      ++  ++++++++       ++       ++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:21:32
-   |
-LL | fn f3_(s: &S, t: &S) -> (&i32, &i32) { loop {} }
-   |           --     --            ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `s`'s 3 lifetimes or one of `t`'s 3 lifetimes
-help: consider introducing a named lifetime parameter
-   |
-LL | fn f3_<'a>(s: &'a S, t: &'a S) -> (&i32, &'a i32) { loop {} }
-   |       ++++     ++        ++               ++
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:25:42
+  --> $DIR/return-elided-lifetime.rs:22:42
    |
 LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
    |                  -------     -------     ^ expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
 note: these named lifetimes are available to use
-  --> $DIR/return-elided-lifetime.rs:25:7
+  --> $DIR/return-elided-lifetime.rs:22:7
    |
 LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &i32 { loop {} }
    |       ^^  ^^
@@ -123,42 +93,27 @@ help: consider using one of the available lifetimes here
 LL | fn f4<'a, 'b>(a: &'a i32, b: &'b i32) -> &'lifetime i32 { loop {} }
    |                                           +++++++++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:27:44
-   |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-   |                   -------     -------      ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
-note: these named lifetimes are available to use
-  --> $DIR/return-elided-lifetime.rs:27:8
-   |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-   |        ^^  ^^
-help: consider using one of the available lifetimes here
-   |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &i32) { loop {} }
-   |                                             +++++++++
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:27:50
+error[E0106]: missing lifetime specifiers
+  --> $DIR/return-elided-lifetime.rs:24:44
    |
 LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
-   |                   -------     -------            ^ expected named lifetime parameter
+   |                   -------     -------      ^     ^ expected named lifetime parameter
+   |                                            |
+   |                                            expected named lifetime parameter
    |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
+   = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
 note: these named lifetimes are available to use
-  --> $DIR/return-elided-lifetime.rs:27:8
+  --> $DIR/return-elided-lifetime.rs:24:8
    |
 LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &i32) { loop {} }
    |        ^^  ^^
 help: consider using one of the available lifetimes here
    |
-LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&i32, &'lifetime i32) { loop {} }
-   |                                                   +++++++++
+LL | fn f4_<'a, 'b>(a: &'a i32, b: &'b i32) -> (&'lifetime i32, &'lifetime i32) { loop {} }
+   |                                             +++++++++       +++++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:31:35
+  --> $DIR/return-elided-lifetime.rs:27:35
    |
 LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
    |              -------     ----     ^ expected named lifetime parameter
@@ -167,32 +122,22 @@ LL | fn f5<'a>(a: &'a i32, b: &i32) -> &i32 { loop {} }
 help: consider using the `'a` lifetime
    |
 LL | fn f5<'a>(a: &'a i32, b: &i32) -> &'a i32 { loop {} }
-   |                                   ~~~
-
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:33:37
-   |
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
-   |               -------     ----      ^ expected named lifetime parameter
-   |
-   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
-help: consider using the `'a` lifetime
-   |
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &i32) { loop {} }
-   |                                     ~~~
+   |                                    ++
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/return-elided-lifetime.rs:33:43
+error[E0106]: missing lifetime specifiers
+  --> $DIR/return-elided-lifetime.rs:29:37
    |
 LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &i32) { loop {} }
-   |               -------     ----            ^ expected named lifetime parameter
+   |               -------     ----      ^     ^ expected named lifetime parameter
+   |                                     |
+   |                                     expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `a` or `b`
 help: consider using the `'a` lifetime
    |
-LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&i32, &'a i32) { loop {} }
-   |                                           ~~~
+LL | fn f5_<'a>(a: &'a i32, b: &i32) -> (&'a i32, &'a i32) { loop {} }
+   |                                      ++       ++
 
-error: aborting due to 15 previous errors
+error: aborting due to 10 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
index 449a61d48090cec206d6a704a4ebd4445861494a..5028e8d628f270a69ed48bafae4046cb96dc82db 100644 (file)
@@ -7,7 +7,7 @@ LL | struct Foo<'a>(&usize);
 help: consider using the `'a` lifetime
    |
 LL | struct Foo<'a>(&'a usize);
-   |                ~~~
+   |                 ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/return-without-lifetime.rs:5:34
@@ -19,7 +19,7 @@ LL | fn func1<'a>(_arg: &'a Thing) -> &() { unimplemented!() }
 help: consider using the `'a` lifetime
    |
 LL | fn func1<'a>(_arg: &'a Thing) -> &'a () { unimplemented!() }
-   |                                  ~~~
+   |                                   ++
 
 error[E0106]: missing lifetime specifier
   --> $DIR/return-without-lifetime.rs:7:35
@@ -31,7 +31,7 @@ LL | fn func2<'a>(_arg: &Thing<'a>) -> &() { unimplemented!() }
 help: consider using the `'a` lifetime
    |
 LL | fn func2<'a>(_arg: &Thing<'a>) -> &'a () { unimplemented!() }
-   |                                   ~~~
+   |                                    ++
 
 error: aborting due to 3 previous errors
 
index d25452456bb21a4f981e8be1c39c4003231c5dac..2b8fec86c8a18f5bc954a5bbd44b83a7373ee586 100644 (file)
@@ -5,6 +5,11 @@ LL |     let _: dyn Foo(&isize, &usize) -> &usize;
    |                    ------  ------     ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
+   = 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 |     let _: dyn for<'a> Foo(&'a isize, &'a usize) -> &'a usize;
+   |                +++++++      ++         ++            ++
 help: consider introducing a named lifetime parameter
    |
 LL ~ fn main<'a>() {
index 37c87dbeaa9e57c87d0af6c23ba5e99330fce59f..e1deab736cf56eb185e781a8294d4e65b1524dc7 100644 (file)
@@ -7,7 +7,6 @@
 
 struct Foo {
     x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier
-    //~^ ERROR E0228
 }
 
-fn main() { }
+fn main() {}
index b865278e25fd8de5e40aa7ea51211f14f08fba37..fd0860028039307c1feade7a2b262027bb1048d9 100644 (file)
@@ -10,13 +10,6 @@ LL ~ struct Foo<'a> {
 LL ~     x: Box<dyn Debug + 'a>,
    |
 
-error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound
-  --> $DIR/dyn-trait-underscore-in-struct.rs:9:12
-   |
-LL |     x: Box<dyn Debug + '_>,
-   |            ^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0106, E0228.
-For more information about an error, try `rustc --explain E0106`.
+For more information about this error, try `rustc --explain E0106`.
index 22bf1fdba326f303031a711d6bbd73597edc9375..50401791effb8321802617fe5dda3be45ef5457a 100644 (file)
@@ -1,3 +1,14 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/underscore-lifetime-binders.rs:2:17
+   |
+LL | struct Baz<'a>(&'_ &'a u8);
+   |                 ^^ expected named lifetime parameter
+   |
+help: consider using the `'a` lifetime
+   |
+LL | struct Baz<'a>(&'a &'a u8);
+   |                 ~~
+
 error[E0637]: `'_` cannot be used here
   --> $DIR/underscore-lifetime-binders.rs:4:8
    |
@@ -10,17 +21,6 @@ error[E0637]: `'_` cannot be used here
 LL | fn meh() -> Box<dyn for<'_> Meh<'_>>
    |                         ^^ `'_` is a reserved lifetime name
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/underscore-lifetime-binders.rs:2:17
-   |
-LL | struct Baz<'a>(&'_ &'a u8);
-   |                 ^^ expected named lifetime parameter
-   |
-help: consider using the `'a` lifetime
-   |
-LL | struct Baz<'a>(&'a &'a u8);
-   |                 ~~
-
 error[E0106]: missing lifetime specifier
   --> $DIR/underscore-lifetime-binders.rs:10:33
    |
index d8d30a75376f78bb0fabe3d28ee9d87aa8035309..85b500ccad8cd0b63995fd94a03ddd4b83f7905b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d8d30a75376f78bb0fabe3d28ee9d87aa8035309
+Subproject commit 85b500ccad8cd0b63995fd94a03ddd4b83f7905b
index 083c437a293c0937b6be1cdc9f3431bc8ec631f0..826353aafc0690c2a9caf64d26fd95358f49cb1a 100644 (file)
@@ -9,12 +9,14 @@
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
     BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
-    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef,
-    PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+    ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
+    TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter as middle_nested_filter;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, Ident, Symbol};
 
@@ -129,7 +131,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
 enum RefLt {
     Unnamed,
     Static,
-    Named(Symbol),
+    Named(LocalDefId),
 }
 
 fn check_fn_inner<'tcx>(
@@ -232,7 +234,7 @@ fn could_use_elision<'tcx>(
     // level of the current item.
 
     // check named LTs
-    let allowed_lts = allowed_lts_from(named_generics);
+    let allowed_lts = allowed_lts_from(cx.tcx, named_generics);
 
     // these will collect all the lifetimes for references in arg/return types
     let mut input_visitor = RefVisitor::new(cx);
@@ -254,22 +256,6 @@ fn could_use_elision<'tcx>(
         return false;
     }
 
-    if allowed_lts
-        .intersection(
-            &input_visitor
-                .nested_elision_site_lts
-                .iter()
-                .chain(output_visitor.nested_elision_site_lts.iter())
-                .cloned()
-                .filter(|v| matches!(v, RefLt::Named(_)))
-                .collect(),
-        )
-        .next()
-        .is_some()
-    {
-        return false;
-    }
-
     let input_lts = input_visitor.lts;
     let output_lts = output_visitor.lts;
 
@@ -303,6 +289,31 @@ fn could_use_elision<'tcx>(
         }
     }
 
+    // check for higher-ranked trait bounds
+    if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() {
+        let allowed_lts: FxHashSet<_> = allowed_lts
+            .iter()
+            .filter_map(|lt| match lt {
+                RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())),
+                _ => None,
+            })
+            .collect();
+        for lt in input_visitor.nested_elision_site_lts {
+            if let RefLt::Named(def_id) = lt {
+                if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
+                    return false;
+                }
+            }
+        }
+        for lt in output_visitor.nested_elision_site_lts {
+            if let RefLt::Named(def_id) = lt {
+                if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
+                    return false;
+                }
+            }
+        }
+    }
+
     // no input lifetimes? easy case!
     if input_lts.is_empty() {
         false
@@ -335,14 +346,11 @@ fn could_use_elision<'tcx>(
     }
 }
 
-fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
+fn allowed_lts_from(tcx: TyCtxt<'_>, named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
     let mut allowed_lts = FxHashSet::default();
     for par in named_generics.iter() {
-        if let GenericParamKind::Lifetime {
-            kind: LifetimeParamKind::Explicit,
-        } = par.kind
-        {
-            allowed_lts.insert(RefLt::Named(par.name.ident().name));
+        if let GenericParamKind::Lifetime { .. } = par.kind {
+            allowed_lts.insert(RefLt::Named(tcx.hir().local_def_id(par.hir_id)));
         }
     }
     allowed_lts.insert(RefLt::Unnamed);
@@ -385,8 +393,10 @@ fn record(&mut self, lifetime: &Option<Lifetime>) {
                 self.lts.push(RefLt::Unnamed);
             } else if lt.is_elided() {
                 self.lts.push(RefLt::Unnamed);
+            } else if let LifetimeName::Param(def_id, _) = lt.name {
+                self.lts.push(RefLt::Named(def_id));
             } else {
-                self.lts.push(RefLt::Named(lt.name.ident().name));
+                self.lts.push(RefLt::Unnamed);
             }
         } else {
             self.lts.push(RefLt::Unnamed);
@@ -434,10 +444,15 @@ fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
             TyKind::OpaqueDef(item, bounds) => {
                 let map = self.cx.tcx.hir();
                 let item = map.item(item);
+                let len = self.lts.len();
                 walk_item(self, item);
-                walk_ty(self, ty);
+                self.lts.truncate(len);
                 self.lts.extend(bounds.iter().filter_map(|bound| match bound {
-                    GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
+                    GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id, _) = l.name {
+                        RefLt::Named(def_id)
+                    } else {
+                        RefLt::Unnamed
+                    }),
                     _ => None,
                 }));
             },
@@ -456,9 +471,8 @@ fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
                 }
                 return;
             },
-            _ => (),
+            _ => walk_ty(self, ty),
         }
-        walk_ty(self, ty);
     }
 }
 
@@ -477,7 +491,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
                     return true;
                 }
                 // if the bounds define new lifetimes, they are fine to occur
-                let allowed_lts = allowed_lts_from(pred.bound_generic_params);
+                let allowed_lts = allowed_lts_from(cx.tcx, pred.bound_generic_params);
                 // now walk the bounds
                 for bound in pred.bounds.iter() {
                     walk_param_bound(&mut visitor, bound);
index c9b1649200d9cb2a8c7a21fd2983f5027f172cf8..a7c78d80ccd768d1cd0484bed46b93a997040cb5 100644 (file)
@@ -348,11 +348,6 @@ fn check(&mut self, file: &Path, report: &mut Report) {
                     return;
                 }
 
-                // These appear to be broken in mdbook right now?
-                if fragment.starts_with('-') {
-                    return;
-                }
-
                 parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report);
 
                 if target_ids.borrow().contains(*fragment) {
index 963f08b702caf7a06eed564312933ec50dd07f54..b938529fb8ed8f7b5b374282ffc3ffa74c313111 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 963f08b702caf7a06eed564312933ec50dd07f54
+Subproject commit b938529fb8ed8f7b5b374282ffc3ffa74c313111
index ea7eff1a4148e317b0061009b1e0e5059150d2de..333f85f6d62b8615e3d52cc41824e8ce85e6f079 100644 (file)
     ("cranelift-codegen-shared", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-entity", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-frontend", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-isle", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-jit", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
     ("mach", "BSD-2-Clause"),
-    ("regalloc", "Apache-2.0 WITH LLVM-exception"),
+    ("regalloc2", "Apache-2.0 WITH LLVM-exception"),
     ("target-lexicon", "Apache-2.0 WITH LLVM-exception"),
 ];
 
 ];
 
 const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
+    "ahash",
     "anyhow",
     "ar",
     "autocfg",
     "bitflags",
+    "byteorder",
     "cfg-if",
     "cranelift-bforest",
     "cranelift-codegen",
     "cranelift-codegen-shared",
     "cranelift-entity",
     "cranelift-frontend",
+    "cranelift-isle",
     "cranelift-jit",
     "cranelift-module",
     "cranelift-native",
     "cranelift-object",
     "crc32fast",
+    "fxhash",
+    "getrandom",
     "gimli",
     "hashbrown",
     "indexmap",
     "memchr",
     "object",
     "once_cell",
-    "regalloc",
+    "regalloc2",
     "region",
-    "rustc-hash",
+    "slice-group-by",
     "smallvec",
     "target-lexicon",
+    "version_check",
+    "wasi",
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-x86_64-pc-windows-gnu",