about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-11-10 10:03:45 +0100
committerRalf Jung <post@ralfj.de>2024-11-10 10:03:57 +0100
commita01f37c7f49b4bcdd4565bd642f68b289a25d832 (patch)
treea0cb06654acfe3d0136f7e59c87b12f591903512
parentce7a56072b78c9924de7c2e58378c6f206333b04 (diff)
parent668959740f97e7a22ae340742886d330ab63950f (diff)
downloadrust-a01f37c7f49b4bcdd4565bd642f68b289a25d832.tar.gz
rust-a01f37c7f49b4bcdd4565bd642f68b289a25d832.zip
Merge from rustc
-rw-r--r--compiler/rustc_abi/src/lib.rs16
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs90
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch2
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch2
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh17
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/comments.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/returning.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/pointer.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs60
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs23
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs2
-rw-r--r--compiler/rustc_const_eval/messages.ftl4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs89
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs53
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs5
-rw-r--r--compiler/rustc_const_eval/src/errors.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs132
-rw-r--r--compiler/rustc_const_eval/src/interpret/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs91
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs6
-rw-r--r--compiler/rustc_feature/src/unstable.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs155
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs18
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs1
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_lexer/src/lib.rs12
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp4
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h103
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/Linker.cpp8
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp40
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp168
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp4
-rw-r--r--compiler/rustc_llvm/src/lib.rs69
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs86
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs5
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs38
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs11
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs1
-rw-r--r--compiler/rustc_middle/src/ty/util.rs1
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs14
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs2
-rw-r--r--compiler/rustc_session/src/config.rs280
-rw-r--r--compiler/rustc_session/src/parse.rs1
-rw-r--r--compiler/rustc_session/src/session.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/target_features.rs10
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs16
-rw-r--r--library/std/src/io/error.rs6
-rw-r--r--src/bootstrap/defaults/config.dist.toml1
-rw-r--r--src/bootstrap/defaults/config.library.toml3
-rw-r--r--src/bootstrap/defaults/config.tools.toml5
-rw-r--r--src/bootstrap/src/core/config/config.rs55
-rw-r--r--src/bootstrap/src/core/config/tests.rs3
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md21
-rw-r--r--src/etc/rust_analyzer_helix.toml17
-rw-r--r--src/librustdoc/lib.rs925
m---------src/tools/cargo0
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs26
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs4
-rw-r--r--src/tools/miri/src/machine.rs8
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs4
-rw-r--r--src/tools/run-make-support/src/lib.rs1
-rw-r--r--tests/assembly/asm/s390x-types.rs2
-rw-r--r--tests/codegen/asm/s390x-clobbers.rs2
-rw-r--r--tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs11
-rw-r--r--tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs53
-rw-r--r--tests/codegen/function-arguments.rs24
-rw-r--r--tests/codegen/try_question_mark_nop.rs11
-rw-r--r--tests/run-make/rustc-help/help-v.diff29
-rw-r--r--tests/run-make/rustc-help/help-v.stdout77
-rw-r--r--tests/run-make/rustc-help/help.stdout60
-rw-r--r--tests/run-make/rustc-help/rmake.rs21
-rw-r--r--tests/rustdoc/hidden-implementors-90781.rs78
-rw-r--r--tests/ui/abi/sparcv8plus.rs43
-rw-r--r--tests/ui/abi/sparcv8plus.sparc.stderr8
-rw-r--r--tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr8
-rw-r--r--tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr8
-rw-r--r--tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr8
-rw-r--r--tests/ui/abi/sparcv8plus.sparcv8plus.stderr8
-rw-r--r--tests/ui/async-await/issue-70935-complex-spans.rs2
-rw-r--r--tests/ui/async-await/issue-70935-complex-spans.stderr21
-rw-r--r--tests/ui/check-cfg/mix.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/iterators/iterator-does-not-need-into-iter.rs18
-rw-r--r--tests/ui/iterators/iterator-does-not-need-into-iter.stderr28
-rw-r--r--tests/ui/lifetimes/raw/immediately-followed-by-lt.rs14
-rw-r--r--tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr13
-rw-r--r--tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs20
-rw-r--r--tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr32
-rw-r--r--tests/ui/mismatched_types/similar_paths_primitive.rs4
-rw-r--r--tests/ui/mismatched_types/similar_paths_primitive.stderr27
-rw-r--r--tests/ui/pattern/usefulness/impl-trait.stderr56
-rw-r--r--tests/ui/resolve/issue-100365.stderr27
-rw-r--r--tests/ui/resolve/issue-22692.stderr33
-rw-r--r--tests/ui/resolve/suggest-path-for-tuple-struct.stderr14
-rw-r--r--tests/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr40
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs340
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr (renamed from tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr)446
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr1239
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nofeature.stderr (renamed from tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr)368
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr990
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs111
-rw-r--r--tests/ui/suggestions/assoc-const-as-field.stderr7
-rw-r--r--tests/ui/target-feature/gate.rs1
-rw-r--r--tests/ui/target-feature/gate.stderr2
-rw-r--r--tests/ui/traits/const-traits/cross-crate.rs4
-rw-r--r--tests/ui/traits/const-traits/cross-crate.stock.stderr31
-rw-r--r--tests/ui/traits/const-traits/cross-crate.stocknc.stderr58
-rw-r--r--tests/ui/traits/const-traits/staged-api-user-crate.rs3
-rw-r--r--tests/ui/traits/const-traits/staged-api-user-crate.stderr27
-rw-r--r--tests/ui/traits/const-traits/staged-api.rs50
-rw-r--r--tests/ui/traits/const-traits/staged-api.stable.stderr89
-rw-r--r--tests/ui/traits/const-traits/staged-api.stderr139
-rw-r--r--tests/ui/traits/const-traits/staged-api.unstable.stderr108
-rw-r--r--tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/closure_wf_outlives.rs6
-rw-r--r--tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr38
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs3
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr27
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs5
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr51
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs4
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr41
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs3
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr29
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs6
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr62
-rw-r--r--tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr14
-rw-r--r--tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr17
-rw-r--r--tests/ui/type-alias-impl-trait/issue-52843.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/issue-90400-2.stderr20
-rw-r--r--tests/ui/type-alias-impl-trait/not_a_defining_use.rs4
-rw-r--r--tests/ui/type-alias-impl-trait/not_a_defining_use.stderr40
-rw-r--r--tests/ui/type-alias-impl-trait/underconstrained_generic.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/underconstrained_lifetime.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/underconstrained_lifetime.stderr6
-rw-r--r--tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr19
-rw-r--r--tests/ui/type-alias-impl-trait/wf-in-associated-type.rs4
-rw-r--r--triagebot.toml1
167 files changed, 5527 insertions, 2603 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index ec758785173..7b6abdf1ea9 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1743,15 +1743,23 @@ pub enum PointerKind {
     Box { unpin: bool, global: bool },
 }
 
-/// Note that this information is advisory only, and backends are free to ignore it.
-/// It can only be used to encode potential optimizations, but no critical information.
+/// Encodes extra information we have about a pointer.
+/// Note that this information is advisory only, and backends are free to ignore it:
+/// if the information is wrong, that can cause UB, but if the information is absent,
+/// that must always be okay.
 #[derive(Copy, Clone, Debug)]
 pub struct PointeeInfo {
-    pub size: Size,
-    pub align: Align,
     /// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to
     /// be reliable.
     pub safe: Option<PointerKind>,
+    /// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes.
+    /// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration
+    /// of this function call", i.e. it is UB for the memory that this pointer points to to be freed
+    /// while this function is still running.
+    /// The size can be zero if the pointer is not dereferenceable.
+    pub size: Size,
+    /// If `safe` is `Some`, then the pointer is aligned as indicated.
+    pub align: Align,
 }
 
 impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 6585a7de245..3acca94a54b 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -48,6 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     | asm::InlineAsmArch::RiscV32
                     | asm::InlineAsmArch::RiscV64
                     | asm::InlineAsmArch::LoongArch64
+                    | asm::InlineAsmArch::S390x
             );
             if !is_stable && !self.tcx.features().asm_experimental_arch() {
                 feature_err(
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index f9dd649ab9f..d676ce59cfe 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,10 +1,7 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir::OpaqueTyOrigin;
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
-use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_macros::extension;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
@@ -12,7 +9,6 @@ use rustc_middle::ty::{
     TypingMode,
 };
 use rustc_span::Span;
-use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use tracing::{debug, instrument};
 
@@ -303,91 +299,7 @@ impl<'tcx> InferCtxt<'tcx> {
             return Ty::new_error(self.tcx, e);
         }
 
-        // `definition_ty` does not live in of the current inference context,
-        // so lets make sure that we don't accidentally misuse our current `infcx`.
-        match check_opaque_type_well_formed(
-            self.tcx,
-            self.next_trait_solver(),
-            opaque_type_key.def_id,
-            instantiated_ty.span,
-            definition_ty,
-        ) {
-            Ok(hidden_ty) => hidden_ty,
-            Err(guar) => Ty::new_error(self.tcx, guar),
-        }
-    }
-}
-
-/// This logic duplicates most of `check_opaque_meets_bounds`.
-/// FIXME(oli-obk): Also do region checks here and then consider removing
-/// `check_opaque_meets_bounds` entirely.
-fn check_opaque_type_well_formed<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    next_trait_solver: bool,
-    def_id: LocalDefId,
-    definition_span: Span,
-    definition_ty: Ty<'tcx>,
-) -> Result<Ty<'tcx>, ErrorGuaranteed> {
-    // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
-    // on stable and we'd break that.
-    let opaque_ty_hir = tcx.hir().expect_opaque_ty(def_id);
-    let OpaqueTyOrigin::TyAlias { .. } = opaque_ty_hir.origin else {
-        return Ok(definition_ty);
-    };
-    let param_env = tcx.param_env(def_id);
-
-    let mut parent_def_id = def_id;
-    while tcx.def_kind(parent_def_id) == DefKind::OpaqueTy {
-        parent_def_id = tcx.local_parent(parent_def_id);
-    }
-
-    // FIXME(#132279): This should eventually use the already defined hidden types
-    // instead. Alternatively we'll entirely remove this function given we also check
-    // the opaque in `check_opaque_meets_bounds` later.
-    let infcx = tcx
-        .infer_ctxt()
-        .with_next_trait_solver(next_trait_solver)
-        .build(TypingMode::analysis_in_body(tcx, parent_def_id));
-    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
-    let identity_args = GenericArgs::identity_for_item(tcx, def_id);
-
-    // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
-    // the bounds that the function supplies.
-    let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args);
-    ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty)
-        .map_err(|err| {
-            infcx
-                .err_ctxt()
-                .report_mismatched_types(
-                    &ObligationCause::misc(definition_span, def_id),
-                    param_env,
-                    opaque_ty,
-                    definition_ty,
-                    err,
-                )
-                .emit()
-        })?;
-
-    // Require the hidden type to be well-formed with only the generics of the opaque type.
-    // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
-    // hidden type is well formed even without those bounds.
-    let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
-        definition_ty.into(),
-    )));
-    ocx.register_obligation(Obligation::misc(tcx, definition_span, def_id, param_env, predicate));
-
-    // Check that all obligations are satisfied by the implementation's
-    // version.
-    let errors = ocx.select_all_or_error();
-
-    // This is fishy, but we check it again in `check_opaque_meets_bounds`.
-    // Remove once we can prepopulate with known hidden types.
-    let _ = infcx.take_opaque_types();
-
-    if errors.is_empty() {
-        Ok(definition_ty)
-    } else {
-        Err(infcx.err_ctxt().report_fulfillment_errors(errors))
+        definition_ty
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
index 6ed22c5a18e..1860810e7f3 100644
--- a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch
@@ -38,7 +38,7 @@ index 42a26ae..5ac1042 100644
 @@ -1,3 +1,4 @@
 +#![cfg(test)]
  // tidy-alphabetical-start
+ #![cfg_attr(bootstrap, feature(const_three_way_compare))]
  #![cfg_attr(bootstrap, feature(strict_provenance))]
- #![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
 --
 2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
index 50a42aea322..59653c6e875 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-coretests-128bit-atomic-operations.patch
@@ -15,7 +15,7 @@ index 1e336bf..35e6f54 100644
 --- a/lib.rs
 +++ b/lib.rs
 @@ -2,7 +2,6 @@
- // tidy-alphabetical-start
+ #![cfg_attr(bootstrap, feature(const_three_way_compare))]
  #![cfg_attr(bootstrap, feature(strict_provenance))]
  #![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
 -#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 2558b2b9f5d..a223cd7dbb8 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2024-11-02"
+channel = "nightly-2024-11-09"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
 profile = "minimal"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh b/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh
index 791d457993d..770f2b6df6c 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh
@@ -11,5 +11,22 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src}
 cp ../Cargo.* compiler/rustc_codegen_cranelift/
 cp -r ../src compiler/rustc_codegen_cranelift/src
 
+# FIXME(rust-lang/rust#132719) remove once it doesn't break without this patch
+cat <<EOF | git apply -
+diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
+index 3394f2a84a0..cb980dd4d7c 100644
+--- a/src/bootstrap/src/core/build_steps/compile.rs
++++ b/src/bootstrap/src/core/build_steps/compile.rs
+@@ -1976,7 +1976,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
+             }
+         }
+
+-        {
++        if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled {
+             // \`llvm-strip\` is used by rustc, which is actually just a symlink to \`llvm-objcopy\`,
+             // so copy and rename \`llvm-objcopy\`.
+             let src_exe = exe("llvm-objcopy", target_compiler.host);
+EOF
+
 ./x.py build --stage 1 library/std
 popd
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index daea789ee3e..521a250ab82 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -3,7 +3,7 @@
 
 use std::borrow::Cow;
 
-use rustc_target::abi::call::PassMode;
+use rustc_target::callconv::PassMode;
 
 use crate::prelude::*;
 
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index dfca5dcbec8..f647ee36c48 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -10,6 +10,7 @@ use std::mem;
 use cranelift_codegen::ir::{ArgumentPurpose, SigRef};
 use cranelift_codegen::isa::CallConv;
 use cranelift_module::ModuleError;
+use rustc_abi::ExternAbi;
 use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
@@ -18,8 +19,7 @@ use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
-use rustc_target::abi::call::{Conv, FnAbi, PassMode};
-use rustc_target::spec::abi::Abi;
+use rustc_target::callconv::{Conv, FnAbi, PassMode};
 
 use self::pass_mode::*;
 pub(crate) use self::returning::codegen_return;
@@ -443,7 +443,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
         RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_sig, extra_args)
     };
 
-    let is_cold = if fn_sig.abi() == Abi::RustCold {
+    let is_cold = if fn_sig.abi() == ExternAbi::RustCold {
         true
     } else {
         instance.is_some_and(|inst| {
@@ -458,7 +458,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
     }
 
     // Unpack arguments tuple for closures
-    let mut args = if fn_sig.abi() == Abi::RustCall {
+    let mut args = if fn_sig.abi() == ExternAbi::RustCall {
         let (self_arg, pack_arg) = match args {
             [pack_arg] => (None, codegen_call_argument_operand(fx, &pack_arg.node)),
             [self_arg, pack_arg] => (
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index ad0a13dc7e5..7594a53fc75 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -1,8 +1,9 @@
 //! Argument passing
 
 use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
-use rustc_target::abi::call::{
-    ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind,
+use rustc_abi::{Reg, RegKind};
+use rustc_target::callconv::{
+    ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode,
 };
 use smallvec::{SmallVec, smallvec};
 
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index a294c789b22..9e048c7badb 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -1,6 +1,6 @@
 //! Return value handling
 
-use rustc_target::abi::call::{ArgAbi, PassMode};
+use rustc_target::callconv::{ArgAbi, PassMode};
 use smallvec::{SmallVec, smallvec};
 
 use crate::prelude::*;
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 10d5dce9b36..da3818ca25e 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -934,7 +934,7 @@ fn codegen_stmt<'tcx>(
                 let dst = codegen_operand(fx, dst);
                 let pointee = dst
                     .layout()
-                    .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
+                    .pointee_info_at(fx, rustc_abi::Size::ZERO)
                     .expect("Expected pointer");
                 let dst = dst.load_scalar(fx);
                 let src = codegen_operand(fx, src).load_scalar(fx);
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 69a32cc3d43..27e71b92561 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -1,13 +1,13 @@
 use cranelift_codegen::isa::TargetFrontendConfig;
 use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
+use rustc_abi::{Float, Integer, Primitive};
 use rustc_index::IndexVec;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::layout::{
     self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
 };
 use rustc_span::source_map::Spanned;
-use rustc_target::abi::call::FnAbi;
-use rustc_target::abi::{Float, Integer, Primitive};
+use rustc_target::callconv::FnAbi;
 use rustc_target::spec::{HasTargetSpec, Target};
 
 use crate::constant::ConstantCx;
@@ -162,8 +162,8 @@ pub(crate) fn codegen_icmp_imm(
 pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value {
     let mut flags = MemFlags::new();
     flags.set_endianness(match fx.tcx.data_layout.endian {
-        rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
-        rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
+        rustc_abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
+        rustc_abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
     });
     fx.bcx.ins().bitcast(dst_ty, flags, val)
 }
@@ -333,8 +333,8 @@ impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> rustc_target::abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> {
-    fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
+impl<'tcx> rustc_abi::HasDataLayout for FunctionCx<'_, '_, 'tcx> {
+    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
         &self.tcx.data_layout
     }
 }
@@ -491,8 +491,8 @@ impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> {
     }
 }
 
-impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
-    fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
+impl<'tcx> rustc_abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
+    fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
         &self.0.data_layout
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index 78ae43b1c4d..9025ea97b81 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -20,7 +20,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefIdMap;
 use rustc_session::Session;
 use rustc_span::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId};
-use rustc_target::abi::call::FnAbi;
+use rustc_target::callconv::FnAbi;
 
 pub(crate) use self::emit::{DebugReloc, DebugRelocName};
 pub(crate) use self::types::TypeDebugContext;
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 419efa90600..8eab73ad5f9 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -2,6 +2,7 @@
 //! standalone executable.
 
 use std::fs::{self, File};
+use std::io::BufWriter;
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
 use std::thread::JoinHandle;
@@ -397,14 +398,19 @@ fn emit_module(
     }
 
     let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name));
-    let mut file = match File::create(&tmp_file) {
+    let file = match File::create(&tmp_file) {
         Ok(file) => file,
         Err(err) => return Err(format!("error creating object file: {}", err)),
     };
 
+    let mut file = BufWriter::new(file);
     if let Err(err) = object.write_stream(&mut file) {
         return Err(format!("error writing object file: {}", err));
     }
+    let file = match file.into_inner() {
+        Ok(file) => file,
+        Err(err) => return Err(format!("error writing object file: {}", err)),
+    };
 
     prof.artifact_size("object_file", &*name, file.metadata().unwrap().len());
 
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 0fbd5a16830..a3f816f70a9 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -464,7 +464,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
         let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| {
             let reg_size =
                 reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap();
-            let align = rustc_target::abi::Align::from_bytes(reg_size.bytes()).unwrap();
+            let align = rustc_abi::Align::from_bytes(reg_size.bytes()).unwrap();
             let offset = slot_size.align_to(align);
             *slot_size = offset + reg_size;
             offset
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 36a35d42c3e..f787b8a6fd9 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -1,7 +1,7 @@
 //! Codegen SIMD intrinsics.
 
 use cranelift_codegen::ir::immediates::Offset32;
-use rustc_target::abi::Endian;
+use rustc_abi::Endian;
 
 use super::*;
 use crate::prelude::*;
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index aba0c28f6b8..19a1de53d1d 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -241,6 +241,8 @@ impl CodegenBackend for CraneliftCodegenBackend {
         sess: &Session,
         outputs: &OutputFilenames,
     ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
+        let _timer = sess.timer("finish_ongoing_codegen");
+
         ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join(
             sess,
             outputs,
diff --git a/compiler/rustc_codegen_cranelift/src/pointer.rs b/compiler/rustc_codegen_cranelift/src/pointer.rs
index 11ac6b94678..2750caa216e 100644
--- a/compiler/rustc_codegen_cranelift/src/pointer.rs
+++ b/compiler/rustc_codegen_cranelift/src/pointer.rs
@@ -2,7 +2,7 @@
 //! operations.
 
 use cranelift_codegen::ir::immediates::Offset32;
-use rustc_target::abi::Align;
+use rustc_abi::Align;
 
 use crate::prelude::*;
 
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index 282763279dd..cd254b04ed9 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -64,7 +64,7 @@ use cranelift_codegen::ir::entities::AnyEntity;
 use cranelift_codegen::write::{FuncWriter, PlainWriter};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::config::{OutputFilenames, OutputType};
-use rustc_target::abi::call::FnAbi;
+use rustc_target::callconv::FnAbi;
 
 use crate::prelude::*;
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index ac6c2fb1b83..0f1909486ec 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -1,11 +1,15 @@
+use std::collections::hash_map::Entry;
+
 use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
 use rustc_codegen_ssa::traits::*;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_index::Idx;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{Body, SourceScope};
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::{self, Instance};
 use rustc_session::config::DebugInfo;
+use rustc_span::BytePos;
 
 use super::metadata::file_metadata;
 use super::utils::DIB;
@@ -37,10 +41,20 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
         None
     };
     let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
+    let mut discriminators = FxHashMap::default();
     // Instantiate all scopes.
     for idx in 0..mir.source_scopes.len() {
         let scope = SourceScope::new(idx);
-        make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope);
+        make_mir_scope(
+            cx,
+            instance,
+            mir,
+            &variables,
+            debug_context,
+            &mut instantiated,
+            &mut discriminators,
+            scope,
+        );
     }
     assert!(instantiated.count() == mir.source_scopes.len());
 }
@@ -52,6 +66,7 @@ fn make_mir_scope<'ll, 'tcx>(
     variables: &Option<BitSet<SourceScope>>,
     debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
     instantiated: &mut BitSet<SourceScope>,
+    discriminators: &mut FxHashMap<BytePos, u32>,
     scope: SourceScope,
 ) {
     if instantiated.contains(scope) {
@@ -60,7 +75,16 @@ fn make_mir_scope<'ll, 'tcx>(
 
     let scope_data = &mir.source_scopes[scope];
     let parent_scope = if let Some(parent) = scope_data.parent_scope {
-        make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent);
+        make_mir_scope(
+            cx,
+            instance,
+            mir,
+            variables,
+            debug_context,
+            instantiated,
+            discriminators,
+            parent,
+        );
         debug_context.scopes[parent]
     } else {
         // The root is the function itself.
@@ -117,7 +141,37 @@ fn make_mir_scope<'ll, 'tcx>(
         // FIXME(eddyb) this doesn't account for the macro-related
         // `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
         let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
-        cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span)
+        let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span);
+
+        // NB: In order to produce proper debug info for variables (particularly
+        // arguments) in multiply-inline functions, LLVM expects to see a single
+        // DILocalVariable with multiple different DILocations in the IR. While
+        // the source information for each DILocation would be identical, their
+        // inlinedAt attributes will be unique to the particular callsite.
+        //
+        // We generate DILocations here based on the callsite's location in the
+        // source code. A single location in the source code usually can't
+        // produce multiple distinct calls so this mostly works, until
+        // proc-macros get involved. A proc-macro can generate multiple calls
+        // at the same span, which breaks the assumption that we're going to
+        // produce a unique DILocation for every scope we process here. We
+        // have to explicitly add discriminators if we see inlines into the
+        // same source code location.
+        //
+        // Note further that we can't key this hashtable on the span itself,
+        // because these spans could have distinct SyntaxContexts. We have
+        // to key on exactly what we're giving to LLVM.
+        match discriminators.entry(callsite_span.lo()) {
+            Entry::Occupied(mut o) => {
+                *o.get_mut() += 1;
+                unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) }
+                    .expect("Failed to encode discriminator in DILocation")
+            }
+            Entry::Vacant(v) => {
+                v.insert(0);
+                loc
+            }
+        }
     });
 
     debug_context.scopes[scope] = DebugScope {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 8508f87c8d3..75a5ec44c22 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -204,7 +204,7 @@ pub enum DLLStorageClass {
     DllExport = 2, // Function to be accessible from DLL.
 }
 
-/// Matches LLVMRustAttribute in LLVMWrapper.h
+/// Must match the layout of `LLVMRustAttributeKind`.
 /// Semantically a subset of the C++ enum llvm::Attribute::AttrKind,
 /// though it is not ABI compatible (since it's a C++ enum)
 #[repr(C)]
@@ -1766,11 +1766,9 @@ unsafe extern "C" {
     pub fn LLVMRustGetLastError() -> *const c_char;
 
     /// Prints the timing information collected by `-Ztime-llvm-passes`.
-    #[expect(improper_ctypes)]
     pub(crate) fn LLVMRustPrintPassTimings(OutStr: &RustString);
 
     /// Prints the statistics collected by `-Zprint-codegen-stats`.
-    #[expect(improper_ctypes)]
     pub(crate) fn LLVMRustPrintStatistics(OutStr: &RustString);
 
     /// Prepares inline assembly.
@@ -1791,7 +1789,6 @@ unsafe extern "C" {
         ConstraintsLen: size_t,
     ) -> bool;
 
-    #[allow(improper_ctypes)]
     pub(crate) fn LLVMRustCoverageWriteFilenamesToBuffer(
         Filenames: *const *const c_char,
         FilenamesLen: size_t,
@@ -1800,7 +1797,6 @@ unsafe extern "C" {
         BufferOut: &RustString,
     );
 
-    #[allow(improper_ctypes)]
     pub(crate) fn LLVMRustCoverageWriteFunctionMappingsToBuffer(
         VirtualFileMappingIDs: *const c_uint,
         NumVirtualFileMappingIDs: size_t,
@@ -1824,13 +1820,10 @@ unsafe extern "C" {
     ) -> &Value;
     pub(crate) fn LLVMRustCoverageHashBytes(Bytes: *const c_char, NumBytes: size_t) -> u64;
 
-    #[allow(improper_ctypes)]
     pub(crate) fn LLVMRustCoverageWriteCovmapSectionNameToString(M: &Module, OutStr: &RustString);
 
-    #[allow(improper_ctypes)]
     pub(crate) fn LLVMRustCoverageWriteCovfunSectionNameToString(M: &Module, OutStr: &RustString);
 
-    #[allow(improper_ctypes)]
     pub(crate) fn LLVMRustCoverageWriteCovmapVarNameToString(OutStr: &RustString);
 
     pub(crate) fn LLVMRustCoverageMappingVersion() -> u32;
@@ -2181,18 +2174,19 @@ unsafe extern "C" {
         Scope: &'a DIScope,
         InlinedAt: Option<&'a DILocation>,
     ) -> &'a DILocation;
+    pub fn LLVMRustDILocationCloneWithBaseDiscriminator<'a>(
+        Location: &'a DILocation,
+        BD: c_uint,
+    ) -> Option<&'a DILocation>;
     pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
     pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
     pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
 
-    #[allow(improper_ctypes)]
     pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
-    #[allow(improper_ctypes)]
     pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
 
     pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
 
-    #[allow(improper_ctypes)]
     pub(crate) fn LLVMRustPrintTargetCPUs(TM: &TargetMachine, OutStr: &RustString);
     pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
     pub fn LLVMRustGetTargetFeature(
@@ -2297,10 +2291,8 @@ unsafe extern "C" {
     pub fn LLVMRustArchiveIteratorFree<'a>(AIR: &'a mut ArchiveIterator<'a>);
     pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
 
-    #[allow(improper_ctypes)]
     pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
 
-    #[allow(improper_ctypes)]
     pub fn LLVMRustUnpackOptimizationDiagnostic<'a>(
         DI: &'a DiagnosticInfo,
         pass_name_out: &RustString,
@@ -2318,7 +2310,6 @@ unsafe extern "C" {
         message_out: &mut Option<&'a Twine>,
     );
 
-    #[allow(improper_ctypes)]
     pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
     pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;
 
@@ -2327,7 +2318,6 @@ unsafe extern "C" {
         cookie_out: &mut c_uint,
     ) -> &'a SMDiagnostic;
 
-    #[allow(improper_ctypes)]
     pub fn LLVMRustUnpackSMDiagnostic(
         d: &SMDiagnostic,
         message_out: &RustString,
@@ -2374,7 +2364,6 @@ unsafe extern "C" {
     pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize;
     pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer);
     pub fn LLVMRustModuleCost(M: &Module) -> u64;
-    #[allow(improper_ctypes)]
     pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
 
     pub fn LLVMRustThinLTOBufferCreate(
@@ -2427,7 +2416,6 @@ unsafe extern "C" {
         bytecode_len: usize,
     ) -> bool;
     pub fn LLVMRustLinkerFree<'a>(linker: &'a mut Linker<'a>);
-    #[allow(improper_ctypes)]
     pub fn LLVMRustComputeLTOCacheKey(
         key_out: &RustString,
         mod_id: *const c_char,
@@ -2450,7 +2438,6 @@ unsafe extern "C" {
         pgo_available: bool,
     );
 
-    #[allow(improper_ctypes)]
     pub fn LLVMRustGetMangledName(V: &Value, out: &RustString);
 
     pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32;
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index 3b0bf47366e..909afe35a17 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -1,6 +1,5 @@
 #![allow(non_snake_case)]
 
-use std::cell::RefCell;
 use std::ffi::{CStr, CString};
 use std::ops::Deref;
 use std::ptr;
@@ -301,15 +300,11 @@ pub fn set_value_name(value: &Value, name: &[u8]) {
 }
 
 pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
-    let sr = RustString { bytes: RefCell::new(Vec::new()) };
-    f(&sr);
-    String::from_utf8(sr.bytes.into_inner())
+    String::from_utf8(RustString::build_byte_buffer(f))
 }
 
 pub fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
-    let sr = RustString { bytes: RefCell::new(Vec::new()) };
-    f(&sr);
-    sr.bytes.into_inner()
+    RustString::build_byte_buffer(f)
 }
 
 pub fn twine_to_string(tr: &Twine) -> String {
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 6f2d86cc601..c382242d8d0 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -228,6 +228,8 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
         "x86"
     } else if sess.target.arch == "arm64ec" {
         "aarch64"
+    } else if sess.target.arch == "sparc64" {
+        "sparc"
     } else {
         &*sess.target.arch
     };
@@ -280,6 +282,13 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
         // Support for `wide-arithmetic` will first land in LLVM 20 as part of
         // llvm/llvm-project#111598
         ("wasm32" | "wasm64", "wide-arithmetic") if get_version() < (20, 0, 0) => None,
+        ("sparc", "leoncasa") => Some(LLVMFeature::new("hasleoncasa")),
+        // In LLVM 19, there is no `v8plus` feature and `v9` means "SPARC-V9 instruction available and SPARC-V8+ ABI used".
+        // https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L27-L28
+        // Before LLVM 19, there is no `v8plus` feature and `v9` means "SPARC-V9 instruction available".
+        // https://github.com/llvm/llvm-project/blob/llvmorg-18.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L26
+        ("sparc", "v8plus") if get_version().0 == 19 => Some(LLVMFeature::new("v9")),
+        ("sparc", "v8plus") if get_version().0 < 19 => None,
         (_, s) => Some(LLVMFeature::new(s)),
     }
 }
@@ -619,6 +628,8 @@ pub(crate) fn global_llvm_features(
             .features
             .split(',')
             .filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some())
+            // Drop +v8plus feature introduced in LLVM 20.
+            .filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
             .map(String::from),
     );
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8f754debaf0..3120b5bf0af 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -3305,23 +3305,6 @@ fn add_lld_args(
     let self_contained_cli = sess.opts.cg.link_self_contained.is_linker_enabled();
     let self_contained_target = self_contained_components.is_linker_enabled();
 
-    // FIXME: in the future, codegen backends may need to have more control over this process: they
-    // don't always support all the features the linker expects here, and vice versa. For example,
-    // at the time of writing this, lld expects a newer style of aarch64 TLS relocations that
-    // cranelift doesn't implement yet. That in turn can impact whether linking would succeed on
-    // such a target when using the `cg_clif` backend and lld.
-    //
-    // Until interactions between backends and linker features are expressible, we limit target
-    // specs to opt-in to lld only when we're on the llvm backend, where it's expected to work and
-    // tested on CI. As usual, the CLI still has precedence over this, so that users and developers
-    // can still override this default when needed (e.g. for tests).
-    let uses_llvm_backend =
-        matches!(sess.opts.unstable_opts.codegen_backend.as_deref(), None | Some("llvm"));
-    if !uses_llvm_backend && !self_contained_cli && sess.opts.cg.linker_flavor.is_none() {
-        // We bail if we're not using llvm and lld was not explicitly requested on the CLI.
-        return;
-    }
-
     let self_contained_linker = self_contained_cli || self_contained_target;
     if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() {
         let mut linker_path_exists = false;
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 3f3cb8b4073..bdf7030f946 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -212,7 +212,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
         "riscv32" => (Architecture::Riscv32, None),
         "riscv64" => (Architecture::Riscv64, None),
         "sparc" => {
-            if sess.target.options.cpu == "v9" {
+            if sess.unstable_target_features.contains(&sym::v8plus) {
                 // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode
                 (Architecture::Sparc32Plus, None)
             } else {
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 826e34930ea..15027ae0c18 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -25,6 +25,10 @@ const_eval_closure_fndef_not_const =
     function defined here, but it is not `const`
 const_eval_closure_non_const =
     cannot call non-const closure in {const_eval_const_context}s
+
+const_eval_conditionally_const_call =
+    cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
+
 const_eval_consider_dereferencing =
     consider dereferencing here
 
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index aea3d5bd3e7..8cd0ecb3e4e 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -15,7 +15,7 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -361,31 +361,21 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         !is_transient
     }
 
+    /// Returns whether there are const-conditions.
     fn revalidate_conditional_constness(
         &mut self,
         callee: DefId,
         callee_args: ty::GenericArgsRef<'tcx>,
-        call_source: CallSource,
         call_span: Span,
-    ) {
+    ) -> bool {
         let tcx = self.tcx;
         if !tcx.is_conditionally_const(callee) {
-            return;
+            return false;
         }
 
         let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
-        // If there are any const conditions on this fn and `const_trait_impl`
-        // is not enabled, simply bail. We shouldn't be able to call conditionally
-        // const functions on stable.
-        if !const_conditions.is_empty() && !tcx.features().const_trait_impl() {
-            self.check_op(ops::FnCallNonConst {
-                callee,
-                args: callee_args,
-                span: call_span,
-                call_source,
-                feature: Some(sym::const_trait_impl),
-            });
-            return;
+        if const_conditions.is_empty() {
+            return false;
         }
 
         let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
@@ -421,6 +411,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             tcx.dcx()
                 .span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
         }
+
+        true
     }
 }
 
@@ -627,11 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     _ => unreachable!(),
                 };
 
-                let ConstCx { tcx, body, param_env, .. } = *self.ccx;
+                let ConstCx { tcx, body, .. } = *self.ccx;
 
                 let fn_ty = func.ty(body, tcx);
 
-                let (mut callee, mut fn_args) = match *fn_ty.kind() {
+                let (callee, fn_args) = match *fn_ty.kind() {
                     ty::FnDef(def_id, fn_args) => (def_id, fn_args),
 
                     ty::FnPtr(..) => {
@@ -645,57 +637,38 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     }
                 };
 
-                self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span);
+                let has_const_conditions =
+                    self.revalidate_conditional_constness(callee, fn_args, *fn_span);
 
-                let mut is_trait = false;
                 // Attempting to call a trait method?
                 if let Some(trait_did) = tcx.trait_of_item(callee) {
-                    trace!("attempting to call a trait method");
+                    // We can't determine the actual callee here, so we have to do different checks
+                    // than usual.
 
+                    trace!("attempting to call a trait method");
                     let trait_is_const = tcx.is_const_trait(trait_did);
-                    // trait method calls are only permitted when `effects` is enabled.
-                    // typeck ensures the conditions for calling a const trait method are met,
-                    // so we only error if the trait isn't const. We try to resolve the trait
-                    // into the concrete method, and uses that for const stability checks.
-                    // FIXME(const_trait_impl) we might consider moving const stability checks
-                    // to typeck as well.
-                    if tcx.features().const_trait_impl() && trait_is_const {
-                        // This skips the check below that ensures we only call `const fn`.
-                        is_trait = true;
-
-                        if let Ok(Some(instance)) =
-                            Instance::try_resolve(tcx, param_env, callee, fn_args)
-                            && let InstanceKind::Item(def) = instance.def
-                        {
-                            // Resolve a trait method call to its concrete implementation, which may be in a
-                            // `const` trait impl. This is only used for the const stability check below, since
-                            // we want to look at the concrete impl's stability.
-                            fn_args = instance.args;
-                            callee = def;
-                        }
+
+                    if trait_is_const {
+                        // Trait calls are always conditionally-const.
+                        self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
+                        // FIXME(const_trait_impl): do a more fine-grained check whether this
+                        // particular trait can be const-stably called.
                     } else {
-                        // if the trait is const but the user has not enabled the feature(s),
-                        // suggest them.
-                        let feature = if trait_is_const {
-                            Some(if tcx.features().const_trait_impl() {
-                                sym::effects
-                            } else {
-                                sym::const_trait_impl
-                            })
-                        } else {
-                            None
-                        };
+                        // Not even a const trait.
                         self.check_op(ops::FnCallNonConst {
                             callee,
                             args: fn_args,
                             span: *fn_span,
                             call_source,
-                            feature,
                         });
-                        // If we allowed this, we're in miri-unleashed mode, so we might
-                        // as well skip the remaining checks.
-                        return;
                     }
+                    // That's all we can check here.
+                    return;
+                }
+
+                // Even if we know the callee, ensure we can use conditionally-const calls.
+                if has_const_conditions {
+                    self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
                 }
 
                 // At this point, we are calling a function, `callee`, whose `DefId` is known...
@@ -783,14 +756,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     return;
                 }
 
-                // Trait functions are not `const fn` so we have to skip them here.
-                if !tcx.is_const_fn(callee) && !is_trait {
+                if !tcx.is_const_fn(callee) {
                     self.check_op(ops::FnCallNonConst {
                         callee,
                         args: fn_args,
                         span: *fn_span,
                         call_source,
-                        feature: None,
                     });
                     // If we allowed this, we're in miri-unleashed mode, so we might
                     // as well skip the remaining checks.
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 2931159842f..036ca763280 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -70,6 +70,37 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
     }
 }
 
+/// A call to a function that is in a trait, or has trait bounds that make it conditionally-const.
+#[derive(Debug)]
+pub(crate) struct ConditionallyConstCall<'tcx> {
+    pub callee: DefId,
+    pub args: GenericArgsRef<'tcx>,
+}
+
+impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
+    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
+        // We use the `const_trait_impl` gate for all conditionally-const calls.
+        Status::Unstable {
+            gate: sym::const_trait_impl,
+            safe_to_expose_on_stable: false,
+            // We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
+            is_function_call: false,
+        }
+    }
+
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
+        ccx.tcx.sess.create_feature_err(
+            errors::ConditionallyConstCall {
+                span,
+                def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args),
+                def_descr: ccx.tcx.def_descr(self.callee),
+                kind: ccx.const_kind(),
+            },
+            sym::const_trait_impl,
+        )
+    }
+}
+
 /// A function call where the callee is not marked as `const`.
 #[derive(Debug, Clone, Copy)]
 pub(crate) struct FnCallNonConst<'tcx> {
@@ -77,7 +108,6 @@ pub(crate) struct FnCallNonConst<'tcx> {
     pub args: GenericArgsRef<'tcx>,
     pub span: Span,
     pub call_source: CallSource,
-    pub feature: Option<Symbol>,
 }
 
 impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
@@ -85,7 +115,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
     #[allow(rustc::diagnostic_outside_of_impl)]
     #[allow(rustc::untranslatable_diagnostic)]
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
-        let FnCallNonConst { callee, args, span, call_source, feature } = *self;
+        let FnCallNonConst { callee, args, span, call_source } = *self;
         let ConstCx { tcx, param_env, .. } = *ccx;
         let caller = ccx.def_id();
 
@@ -285,14 +315,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
             ccx.const_kind(),
         ));
 
-        if let Some(feature) = feature {
-            ccx.tcx.disabled_nightly_features(
-                &mut err,
-                Some(ccx.tcx.local_def_id_to_hir_id(caller)),
-                [(String::new(), feature)],
-            );
-        }
-
         if let ConstContext::Static(_) = ccx.const_kind() {
             err.note(fluent_generated::const_eval_lazy_lock);
         }
@@ -398,15 +420,8 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
 
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
         let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
-        if let hir::CoroutineKind::Desugared(
-            hir::CoroutineDesugaring::Async,
-            hir::CoroutineSource::Block,
-        ) = self.0
-        {
-            ccx.tcx.sess.create_feature_err(
-                errors::UnallowedOpInConstContext { span, msg },
-                sym::const_async_blocks,
-            )
+        if let Status::Unstable { gate, .. } = self.status_in_item(ccx) {
+            ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate)
         } else {
             ccx.dcx().create_err(errors::UnallowedOpInConstContext { span, msg })
         }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 81b9d73b952..a430d9dc797 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -472,8 +472,9 @@ fn report_validation_error<'tcx>(
     backtrace.print_backtrace();
 
     let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
-    let (size, align, _) = ecx.get_alloc_info(alloc_id);
-    let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes };
+    let info = ecx.get_alloc_info(alloc_id);
+    let raw_bytes =
+        errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes };
 
     crate::const_eval::report(
         *ecx.tcx,
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 14e8bebbb18..604e5ed61a3 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -177,6 +177,16 @@ pub(crate) struct NonConstFmtMacroCall {
 }
 
 #[derive(Diagnostic)]
+#[diag(const_eval_conditionally_const_call)]
+pub(crate) struct ConditionallyConstCall {
+    #[primary_span]
+    pub span: Span,
+    pub def_path_str: String,
+    pub def_descr: &'static str,
+    pub kind: ConstContext,
+}
+
+#[derive(Diagnostic)]
 #[diag(const_eval_non_const_fn_call, code = E0015)]
 pub(crate) struct NonConstFnCall {
     #[primary_span]
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 1ad8ffa4b53..09635c96e57 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -14,10 +14,9 @@ use std::{fmt, mem, ptr};
 use rustc_abi::{Align, HasDataLayout, Size};
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
-use rustc_hir::def::DefKind;
 use rustc_middle::bug;
 use rustc_middle::mir::display_allocation;
-use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use tracing::{debug, instrument, trace};
 
 use super::{
@@ -72,6 +71,21 @@ pub enum AllocKind {
     Dead,
 }
 
+/// Metadata about an `AllocId`.
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct AllocInfo {
+    pub size: Size,
+    pub align: Align,
+    pub kind: AllocKind,
+    pub mutbl: Mutability,
+}
+
+impl AllocInfo {
+    fn new(size: Size, align: Align, kind: AllocKind, mutbl: Mutability) -> Self {
+        Self { size, align, kind, mutbl }
+    }
+}
+
 /// The value of a function pointer.
 #[derive(Debug, Copy, Clone)]
 pub enum FnVal<'tcx, Other> {
@@ -524,17 +538,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         match self.ptr_try_get_alloc_id(ptr, 0) {
             Err(addr) => is_offset_misaligned(addr, align),
             Ok((alloc_id, offset, _prov)) => {
-                let (_size, alloc_align, kind) = self.get_alloc_info(alloc_id);
-                if let Some(misalign) =
-                    M::alignment_check(self, alloc_id, alloc_align, kind, offset, align)
-                {
+                let alloc_info = self.get_alloc_info(alloc_id);
+                if let Some(misalign) = M::alignment_check(
+                    self,
+                    alloc_id,
+                    alloc_info.align,
+                    alloc_info.kind,
+                    offset,
+                    align,
+                ) {
                     Some(misalign)
                 } else if M::Provenance::OFFSET_IS_ADDR {
                     is_offset_misaligned(ptr.addr().bytes(), align)
                 } else {
                     // Check allocation alignment and offset alignment.
-                    if alloc_align.bytes() < align.bytes() {
-                        Some(Misalignment { has: alloc_align, required: align })
+                    if alloc_info.align.bytes() < align.bytes() {
+                        Some(Misalignment { has: alloc_info.align, required: align })
                     } else {
                         is_offset_misaligned(offset.bytes(), align)
                     }
@@ -818,82 +837,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
     /// Obtain the size and alignment of an allocation, even if that allocation has
     /// been deallocated.
-    pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) {
+    pub fn get_alloc_info(&self, id: AllocId) -> AllocInfo {
         // # Regular allocations
         // Don't use `self.get_raw` here as that will
         // a) cause cycles in case `id` refers to a static
         // b) duplicate a global's allocation in miri
         if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
-            return (alloc.size(), alloc.align, AllocKind::LiveData);
+            return AllocInfo::new(
+                alloc.size(),
+                alloc.align,
+                AllocKind::LiveData,
+                alloc.mutability,
+            );
         }
 
         // # Function pointers
         // (both global from `alloc_map` and local from `extra_fn_ptr_map`)
         if self.get_fn_alloc(id).is_some() {
-            return (Size::ZERO, Align::ONE, AllocKind::Function);
+            return AllocInfo::new(Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);
         }
 
-        // # Statics
-        // Can't do this in the match argument, we may get cycle errors since the lock would
-        // be held throughout the match.
-        match self.tcx.try_get_global_alloc(id) {
-            Some(GlobalAlloc::Static(def_id)) => {
-                // Thread-local statics do not have a constant address. They *must* be accessed via
-                // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value.
-                assert!(!self.tcx.is_thread_local_static(def_id));
-
-                let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else {
-                    bug!("GlobalAlloc::Static is not a static")
-                };
-
-                let (size, align) = if nested {
-                    // Nested anonymous statics are untyped, so let's get their
-                    // size and alignment from the allocation itself. This always
-                    // succeeds, as the query is fed at DefId creation time, so no
-                    // evaluation actually occurs.
-                    let alloc = self.tcx.eval_static_initializer(def_id).unwrap();
-                    (alloc.0.size(), alloc.0.align)
-                } else {
-                    // Use size and align of the type for everything else. We need
-                    // to do that to
-                    // * avoid cycle errors in case of self-referential statics,
-                    // * be able to get information on extern statics.
-                    let ty = self
-                        .tcx
-                        .type_of(def_id)
-                        .no_bound_vars()
-                        .expect("statics should not have generic parameters");
-                    let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
-                    assert!(layout.is_sized());
-                    (layout.size, layout.align.abi)
-                };
-                (size, align, AllocKind::LiveData)
-            }
-            Some(GlobalAlloc::Memory(alloc)) => {
-                // Need to duplicate the logic here, because the global allocations have
-                // different associated types than the interpreter-local ones.
-                let alloc = alloc.inner();
-                (alloc.size(), alloc.align, AllocKind::LiveData)
-            }
-            Some(GlobalAlloc::Function { .. }) => {
-                bug!("We already checked function pointers above")
-            }
-            Some(GlobalAlloc::VTable(..)) => {
-                // No data to be accessed here. But vtables are pointer-aligned.
-                return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable);
-            }
-            // The rest must be dead.
-            None => {
-                // Deallocated pointers are allowed, we should be able to find
-                // them in the map.
-                let (size, align) = *self
-                    .memory
-                    .dead_alloc_map
-                    .get(&id)
-                    .expect("deallocated pointers should all be recorded in `dead_alloc_map`");
-                (size, align, AllocKind::Dead)
-            }
+        // # Global allocations
+        if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
+            let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env);
+            let mutbl = global_alloc.mutability(*self.tcx, self.param_env);
+            let kind = match global_alloc {
+                GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,
+                GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"),
+                GlobalAlloc::VTable { .. } => AllocKind::VTable,
+            };
+            return AllocInfo::new(size, align, kind, mutbl);
         }
+
+        // # Dead pointers
+        let (size, align) = *self
+            .memory
+            .dead_alloc_map
+            .get(&id)
+            .expect("deallocated pointers should all be recorded in `dead_alloc_map`");
+        AllocInfo::new(size, align, AllocKind::Dead, Mutability::Not)
     }
 
     /// Obtain the size and alignment of a *live* allocation.
@@ -902,11 +884,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         id: AllocId,
         msg: CheckInAllocMsg,
     ) -> InterpResult<'tcx, (Size, Align)> {
-        let (size, align, kind) = self.get_alloc_info(id);
-        if matches!(kind, AllocKind::Dead) {
+        let info = self.get_alloc_info(id);
+        if matches!(info.kind, AllocKind::Dead) {
             throw_ub!(PointerUseAfterFree(id, msg))
         }
-        interp_ok((size, align))
+        interp_ok((info.size, info.align))
     }
 
     fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {
@@ -1458,7 +1440,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let ptr = scalar.to_pointer(self)?;
                 match self.ptr_try_get_alloc_id(ptr, 0) {
                     Ok((alloc_id, offset, _)) => {
-                        let (size, _align, _kind) = self.get_alloc_info(alloc_id);
+                        let size = self.get_alloc_info(alloc_id).size;
                         // If the pointer is out-of-bounds, it may be null.
                         // Note that one-past-the-end (offset == size) is still inbounds, and never null.
                         offset > size
diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs
index 5e84626f77e..f5792aba207 100644
--- a/compiler/rustc_const_eval/src/interpret/mod.rs
+++ b/compiler/rustc_const_eval/src/interpret/mod.rs
@@ -31,7 +31,7 @@ pub use self::intern::{
 };
 pub(crate) use self::intrinsics::eval_nullary_intrinsic;
 pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine};
-pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
+pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
 use self::operand::Operand;
 pub use self::operand::{ImmTy, Immediate, OpTy};
 pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index cd2c1ef3613..3a68db9f7f7 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -31,8 +31,8 @@ use tracing::trace;
 
 use super::machine::AllocMap;
 use super::{
-    AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult,
-    MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub,
+    AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy,
+    Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub,
     format_interp_error,
 };
 
@@ -557,9 +557,20 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                 if let Ok((alloc_id, _offset, _prov)) =
                     self.ecx.ptr_try_get_alloc_id(place.ptr(), 0)
                 {
-                    if let Some(GlobalAlloc::Static(did)) =
-                        self.ecx.tcx.try_get_global_alloc(alloc_id)
-                    {
+                    // Everything should be already interned.
+                    let Some(global_alloc) = self.ecx.tcx.try_get_global_alloc(alloc_id) else {
+                        assert!(self.ecx.memory.alloc_map.get(alloc_id).is_none());
+                        // We can't have *any* references to non-existing allocations in const-eval
+                        // as the rest of rustc isn't happy with them... so we throw an error, even
+                        // though for zero-sized references this isn't really UB.
+                        // A potential future alternative would be to resurrect this as a zero-sized allocation
+                        // (which codegen will then compile to an aligned dummy pointer anyway).
+                        throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
+                    };
+                    let (size, _align) =
+                        global_alloc.size_and_align(*self.ecx.tcx, self.ecx.param_env);
+
+                    if let GlobalAlloc::Static(did) = global_alloc {
                         let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else {
                             bug!()
                         };
@@ -593,17 +604,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                         }
                     }
 
-                    // Dangling and Mutability check.
-                    let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id);
-                    if alloc_kind == AllocKind::Dead {
-                        // This can happen for zero-sized references. We can't have *any* references to
-                        // non-existing allocations in const-eval though, interning rejects them all as
-                        // the rest of rustc isn't happy with them... so we throw an error, even though
-                        // this isn't really UB.
-                        // A potential future alternative would be to resurrect this as a zero-sized allocation
-                        // (which codegen will then compile to an aligned dummy pointer anyway).
-                        throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind });
-                    }
                     // If this allocation has size zero, there is no actual mutability here.
                     if size != Size::ZERO {
                         // Determine whether this pointer expects to be pointing to something mutable.
@@ -618,7 +618,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                             }
                         };
                         // Determine what it actually points to.
-                        let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
+                        let alloc_actual_mutbl =
+                            global_alloc.mutability(*self.ecx.tcx, self.ecx.param_env);
                         // Mutable pointer to immutable memory is no good.
                         if ptr_expected_mutbl == Mutability::Mut
                             && alloc_actual_mutbl == Mutability::Not
@@ -842,9 +843,16 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
     }
 
     fn in_mutable_memory(&self, val: &PlaceTy<'tcx, M::Provenance>) -> bool {
+        debug_assert!(self.ctfe_mode.is_some());
         if let Some(mplace) = val.as_mplace_or_local().left() {
             if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) {
-                mutability(self.ecx, alloc_id).is_mut()
+                let tcx = *self.ecx.tcx;
+                // Everything must be already interned.
+                let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.param_env);
+                if let Some((_, alloc)) = self.ecx.memory.alloc_map.get(alloc_id) {
+                    assert_eq!(alloc.mutability, mutbl);
+                }
+                mutbl.is_mut()
             } else {
                 // No memory at all.
                 false
@@ -1016,53 +1024,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
     }
 }
 
-/// Returns whether the allocation is mutable, and whether it's actually a static.
-/// For "root" statics we look at the type to account for interior
-/// mutability; for nested statics we have no type and directly use the annotated mutability.
-fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) -> Mutability {
-    // Let's see what kind of memory this points to.
-    // We're not using `try_global_alloc` since dangling pointers have already been handled.
-    match ecx.tcx.global_alloc(alloc_id) {
-        GlobalAlloc::Static(did) => {
-            let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else {
-                bug!()
-            };
-            if nested {
-                assert!(
-                    ecx.memory.alloc_map.get(alloc_id).is_none(),
-                    "allocations of nested statics are already interned: {alloc_id:?}, {did:?}"
-                );
-                // Nested statics in a `static` are never interior mutable,
-                // so just use the declared mutability.
-                mutability
-            } else {
-                let mutability = match mutability {
-                    Mutability::Not
-                        if !ecx
-                            .tcx
-                            .type_of(did)
-                            .no_bound_vars()
-                            .expect("statics should not have generic parameters")
-                            .is_freeze(*ecx.tcx, ty::ParamEnv::reveal_all()) =>
-                    {
-                        Mutability::Mut
-                    }
-                    _ => mutability,
-                };
-                if let Some((_, alloc)) = ecx.memory.alloc_map.get(alloc_id) {
-                    assert_eq!(alloc.mutability, mutability);
-                }
-                mutability
-            }
-        }
-        GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
-        GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => {
-            // These are immutable, we better don't allow mutable pointers here.
-            Mutability::Not
-        }
-    }
-}
-
 impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, 'tcx, M> {
     type V = PlaceTy<'tcx, M::Provenance>;
 
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index d2c4335cf2b..78ba841d89f 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -937,7 +937,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
     let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
     let mut options = getopts::Options::new();
     for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
-        (option.apply)(&mut options);
+        option.apply(&mut options);
     }
     let message = "Usage: rustc [OPTIONS] INPUT";
     let nightly_help = if nightly_build {
@@ -1219,7 +1219,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
     let mut options = getopts::Options::new();
     let optgroups = config::rustc_optgroups();
     for option in &optgroups {
-        (option.apply)(&mut options);
+        option.apply(&mut options);
     }
     let matches = options.parse(args).unwrap_or_else(|e| {
         let msg: Option<String> = match e {
@@ -1233,7 +1233,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
                 optgroups.iter().find(|option| option.name == opt).map(|option| {
                     // Print the help just for the option in question.
                     let mut options = getopts::Options::new();
-                    (option.apply)(&mut options);
+                    option.apply(&mut options);
                     // getopt requires us to pass a function for joining an iterator of
                     // strings, even though in this case we expect exactly one string.
                     options.usage_with_format(|it| {
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 5f83c211b38..8326d0031ea 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -336,6 +336,7 @@ declare_features! (
     (unstable, riscv_target_feature, "1.45.0", Some(44839)),
     (unstable, rtm_target_feature, "1.35.0", Some(44839)),
     (unstable, s390x_target_feature, "1.82.0", Some(44839)),
+    (unstable, sparc_target_feature, "CURRENT_RUSTC_VERSION", Some(132783)),
     (unstable, sse4a_target_feature, "1.27.0", Some(44839)),
     (unstable, tbm_target_feature, "1.27.0", Some(44839)),
     (unstable, wasm_target_feature, "1.30.0", Some(44839)),
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 50ea8018e76..3080d8b3510 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -5,13 +5,14 @@ use rustc_abi::FieldIdx;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::MultiSpan;
 use rustc_errors::codes::*;
-use rustc_hir::Node;
 use rustc_hir::def::{CtorKind, DefKind};
+use rustc_hir::{Node, intravisit};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
-use rustc_infer::traits::Obligation;
+use rustc_infer::traits::{Obligation, ObligationCauseCode};
 use rustc_lint_defs::builtin::{
     REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS,
 };
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
 use rustc_middle::middle::stability::EvalResult;
 use rustc_middle::span_bug;
@@ -190,7 +191,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`
 /// projections that would result in "inheriting lifetimes".
 fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    let hir::OpaqueTy { origin, .. } = tcx.hir().expect_opaque_ty(def_id);
+    let hir::OpaqueTy { origin, .. } = *tcx.hir().expect_opaque_ty(def_id);
 
     // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
     // `async-std` (and `pub async fn` in general).
@@ -200,23 +201,20 @@ fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         return;
     }
 
-    let span = tcx.def_span(def_id);
-
     if tcx.type_of(def_id).instantiate_identity().references_error() {
         return;
     }
-    if check_opaque_for_cycles(tcx, def_id, span).is_err() {
+    if check_opaque_for_cycles(tcx, def_id).is_err() {
         return;
     }
 
-    let _ = check_opaque_meets_bounds(tcx, def_id, span, origin);
+    let _ = check_opaque_meets_bounds(tcx, def_id, origin);
 }
 
 /// Checks that an opaque type does not contain cycles.
 pub(super) fn check_opaque_for_cycles<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
-    span: Span,
 ) -> Result<(), ErrorGuaranteed> {
     let args = GenericArgs::identity_for_item(tcx, def_id);
 
@@ -233,7 +231,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
             .try_expand_impl_trait_type(def_id.to_def_id(), args, InspectCoroutineFields::No)
             .is_err()
         {
-            let reported = opaque_type_cycle_error(tcx, def_id, span);
+            let reported = opaque_type_cycle_error(tcx, def_id);
             return Err(reported);
         }
 
@@ -267,10 +265,16 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
 fn check_opaque_meets_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
-    span: Span,
-    origin: &hir::OpaqueTyOrigin<LocalDefId>,
+    origin: hir::OpaqueTyOrigin<LocalDefId>,
 ) -> Result<(), ErrorGuaranteed> {
-    let defining_use_anchor = match *origin {
+    let (span, definition_def_id) =
+        if let Some((span, def_id)) = best_definition_site_of_opaque(tcx, def_id, origin) {
+            (span, Some(def_id))
+        } else {
+            (tcx.def_span(def_id), None)
+        };
+
+    let defining_use_anchor = match origin {
         hir::OpaqueTyOrigin::FnReturn { parent, .. }
         | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
         | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,
@@ -281,7 +285,7 @@ fn check_opaque_meets_bounds<'tcx>(
     let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor));
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
-    let args = match *origin {
+    let args = match origin {
         hir::OpaqueTyOrigin::FnReturn { parent, .. }
         | hir::OpaqueTyOrigin::AsyncFn { parent, .. }
         | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(
@@ -306,8 +310,33 @@ fn check_opaque_meets_bounds<'tcx>(
         _ => re,
     });
 
-    let misc_cause = traits::ObligationCause::misc(span, def_id);
+    // HACK: We eagerly instantiate some bounds to report better errors for them...
+    // This isn't necessary for correctness, since we register these bounds when
+    // equating the opaque below, but we should clean this up in the new solver.
+    for (predicate, pred_span) in
+        tcx.explicit_item_bounds(def_id).iter_instantiated_copied(tcx, args)
+    {
+        let predicate = predicate.fold_with(&mut BottomUpFolder {
+            tcx,
+            ty_op: |ty| if ty == opaque_ty { hidden_ty } else { ty },
+            lt_op: |lt| lt,
+            ct_op: |ct| ct,
+        });
+
+        ocx.register_obligation(Obligation::new(
+            tcx,
+            ObligationCause::new(
+                span,
+                def_id,
+                ObligationCauseCode::OpaqueTypeBound(pred_span, definition_def_id),
+            ),
+            param_env,
+            predicate,
+        ));
+    }
 
+    let misc_cause = ObligationCause::misc(span, def_id);
+    // FIXME: We should just register the item bounds here, rather than equating.
     match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {
         Ok(()) => {}
         Err(ty_err) => {
@@ -364,6 +393,97 @@ fn check_opaque_meets_bounds<'tcx>(
     }
 }
 
+fn best_definition_site_of_opaque<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    opaque_def_id: LocalDefId,
+    origin: hir::OpaqueTyOrigin<LocalDefId>,
+) -> Option<(Span, LocalDefId)> {
+    struct TaitConstraintLocator<'tcx> {
+        opaque_def_id: LocalDefId,
+        tcx: TyCtxt<'tcx>,
+    }
+    impl<'tcx> TaitConstraintLocator<'tcx> {
+        fn check(&self, item_def_id: LocalDefId) -> ControlFlow<(Span, LocalDefId)> {
+            if !self.tcx.has_typeck_results(item_def_id) {
+                return ControlFlow::Continue(());
+            }
+
+            if let Some(hidden_ty) =
+                self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id)
+            {
+                ControlFlow::Break((hidden_ty.span, item_def_id))
+            } else {
+                ControlFlow::Continue(())
+            }
+        }
+    }
+    impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
+        type NestedFilter = nested_filter::All;
+        type Result = ControlFlow<(Span, LocalDefId)>;
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.tcx.hir()
+        }
+        fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
+            if let hir::ExprKind::Closure(closure) = ex.kind {
+                self.check(closure.def_id)?;
+            }
+            intravisit::walk_expr(self, ex)
+        }
+        fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result {
+            self.check(it.owner_id.def_id)?;
+            intravisit::walk_item(self, it)
+        }
+        fn visit_impl_item(&mut self, it: &'tcx hir::ImplItem<'tcx>) -> Self::Result {
+            self.check(it.owner_id.def_id)?;
+            intravisit::walk_impl_item(self, it)
+        }
+        fn visit_trait_item(&mut self, it: &'tcx hir::TraitItem<'tcx>) -> Self::Result {
+            self.check(it.owner_id.def_id)?;
+            intravisit::walk_trait_item(self, it)
+        }
+        fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> Self::Result {
+            intravisit::walk_foreign_item(self, it)
+        }
+    }
+
+    let mut locator = TaitConstraintLocator { tcx, opaque_def_id };
+    match origin {
+        hir::OpaqueTyOrigin::FnReturn { parent, .. }
+        | hir::OpaqueTyOrigin::AsyncFn { parent, .. } => locator.check(parent).break_value(),
+        hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty: true } => {
+            let impl_def_id = tcx.local_parent(parent);
+            for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
+                match assoc.kind {
+                    ty::AssocKind::Const | ty::AssocKind::Fn => {
+                        if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
+                        {
+                            return Some(span);
+                        }
+                    }
+                    ty::AssocKind::Type => {}
+                }
+            }
+
+            None
+        }
+        hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {
+            let scope = tcx.hir().get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id));
+            let found = if scope == hir::CRATE_HIR_ID {
+                tcx.hir().walk_toplevel_module(&mut locator)
+            } else {
+                match tcx.hir_node(scope) {
+                    Node::Item(it) => locator.visit_item(it),
+                    Node::ImplItem(it) => locator.visit_impl_item(it),
+                    Node::TraitItem(it) => locator.visit_trait_item(it),
+                    Node::ForeignItem(it) => locator.visit_foreign_item(it),
+                    other => bug!("{:?} is not a valid scope for an opaque type item", other),
+                }
+            };
+            found.break_value()
+        }
+    }
+}
+
 fn sanity_check_found_hidden_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::OpaqueTypeKey<'tcx>,
@@ -1535,11 +1655,8 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
 ///
 /// If all the return expressions evaluate to `!`, then we explain that the error will go away
 /// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
-fn opaque_type_cycle_error(
-    tcx: TyCtxt<'_>,
-    opaque_def_id: LocalDefId,
-    span: Span,
-) -> ErrorGuaranteed {
+fn opaque_type_cycle_error(tcx: TyCtxt<'_>, opaque_def_id: LocalDefId) -> ErrorGuaranteed {
+    let span = tcx.def_span(opaque_def_id);
     let mut err = struct_span_code_err!(tcx.dcx(), span, E0720, "cannot resolve opaque type");
 
     let mut label = false;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index eaf40a193a6..cb20a1d7c7b 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -100,9 +100,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty: Ty<'tcx>,
         span: Span,
         unsatisfied_predicates: &Vec<(
-            ty::Predicate<'_>,
-            Option<ty::Predicate<'_>>,
-            Option<ObligationCause<'_>>,
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
         )>,
     ) -> bool {
         fn predicate_bounds_generic_param<'tcx>(
@@ -131,15 +131,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
-        fn is_iterator_predicate(predicate: ty::Predicate<'_>, tcx: TyCtxt<'_>) -> bool {
+        let is_iterator_predicate = |predicate: ty::Predicate<'tcx>| -> bool {
             if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) =
                 predicate.kind().as_ref().skip_binder()
             {
-                tcx.is_diagnostic_item(sym::Iterator, trait_pred.trait_ref.def_id)
+                self.tcx.is_diagnostic_item(sym::Iterator, trait_pred.trait_ref.def_id)
+                    // ignore unsatisfied predicates generated from trying to auto-ref ty (#127511)
+                    && trait_pred.trait_ref.self_ty() == ty
             } else {
                 false
             }
-        }
+        };
 
         // Does the `ty` implement `IntoIterator`?
         let Some(into_iterator_trait) = self.tcx.get_diagnostic_item(sym::IntoIterator) else {
@@ -164,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         generics,
                         generic_param,
                         self.tcx,
-                    ) && is_iterator_predicate(unsatisfied.0, self.tcx)
+                    ) && is_iterator_predicate(unsatisfied.0)
                     {
                         return true;
                     }
@@ -172,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::Slice(..) | ty::Adt(..) | ty::Alias(ty::Opaque, _) => {
                 for unsatisfied in unsatisfied_predicates.iter() {
-                    if is_iterator_predicate(unsatisfied.0, self.tcx) {
+                    if is_iterator_predicate(unsatisfied.0) {
                         return true;
                     }
                 }
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index e0e03a29220..b1d5d688295 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -104,6 +104,7 @@ impl<'tcx> InferCtxt<'tcx> {
             infer::RelateParamBound(cause.span, sup_type, match cause.code().peel_derives() {
                 ObligationCauseCode::WhereClause(_, span)
                 | ObligationCauseCode::WhereClauseInExpr(_, span, ..)
+                | ObligationCauseCode::OpaqueTypeBound(span, _)
                     if !span.is_dummy() =>
                 {
                     Some(*span)
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index ce90ceeda56..2361231b3fb 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -102,7 +102,7 @@ where
 fn optgroups() -> getopts::Options {
     let mut opts = getopts::Options::new();
     for group in rustc_optgroups() {
-        (group.apply)(&mut opts);
+        group.apply(&mut opts);
     }
     return opts;
 }
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b0ab50dd773..f9f2a14dbd2 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -715,7 +715,17 @@ impl Cursor<'_> {
             self.bump();
             self.bump();
             self.eat_while(is_id_continue);
-            return RawLifetime;
+            match self.first() {
+                '\'' => {
+                    // Check if after skipping literal contents we've met a closing
+                    // single quote (which means that user attempted to create a
+                    // string with single quotes).
+                    self.bump();
+                    let kind = Char { terminated: true };
+                    return Literal { kind, suffix_start: self.pos_within_token() };
+                }
+                _ => return RawLifetime,
+            }
         }
 
         // Either a lifetime or a character literal with
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index 2ee7454b652..0471baa1f9c 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -1,5 +1,9 @@
 #include "LLVMWrapper.h"
+
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Module.h"
 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
 #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
 #include "llvm/ProfileData/InstrProf.h"
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 73bbc9de855..f6598f9faf5 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -1,31 +1,12 @@
+#ifndef INCLUDED_RUSTC_LLVM_LLVMWRAPPER_H
+#define INCLUDED_RUSTC_LLVM_LLVMWRAPPER_H
+
 #include "SuppressLLVMWarnings.h"
 
-#include "llvm-c/BitReader.h"
-#include "llvm-c/Core.h"
-#include "llvm-c/Object.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Analysis/Lint.h"
-#include "llvm/Analysis/Passes.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/InlineAsm.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/DynamicLibrary.h"
-#include "llvm/Support/FormattedStream.h"
-#include "llvm/Support/JSON.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/Timer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetOptions.h"
-#include "llvm/Transforms/IPO.h"
-#include "llvm/Transforms/Scalar.h"
+#include "llvm/Config/llvm-config.h"  // LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR
+#include "llvm/Support/raw_ostream.h" // llvm::raw_ostream
+#include <cstddef>                    // size_t etc
+#include <cstdint>                    // uint64_t etc
 
 #define LLVM_VERSION_GE(major, minor)                                          \
   (LLVM_VERSION_MAJOR > (major) ||                                             \
@@ -33,79 +14,17 @@
 
 #define LLVM_VERSION_LT(major, minor) (!LLVM_VERSION_GE((major), (minor)))
 
-#if LLVM_VERSION_GE(20, 0)
-#include "llvm/Transforms/Utils/Instrumentation.h"
-#else
-#include "llvm/Transforms/Instrumentation.h"
-#endif
-
-#include "llvm/IR/LegacyPassManager.h"
-
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/Bitcode/BitcodeWriter.h"
-
-#include "llvm/IR/DIBuilder.h"
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/IRPrintingPasses.h"
-#include "llvm/Linker/Linker.h"
-
-#include "llvm/TargetParser/Triple.h"
-
 extern "C" void LLVMRustSetLastError(const char *);
 
 enum class LLVMRustResult { Success, Failure };
 
-enum LLVMRustAttribute {
-  AlwaysInline = 0,
-  ByVal = 1,
-  Cold = 2,
-  InlineHint = 3,
-  MinSize = 4,
-  Naked = 5,
-  NoAlias = 6,
-  NoCapture = 7,
-  NoInline = 8,
-  NonNull = 9,
-  NoRedZone = 10,
-  NoReturn = 11,
-  NoUnwind = 12,
-  OptimizeForSize = 13,
-  ReadOnly = 14,
-  SExt = 15,
-  StructRet = 16,
-  UWTable = 17,
-  ZExt = 18,
-  InReg = 19,
-  SanitizeThread = 20,
-  SanitizeAddress = 21,
-  SanitizeMemory = 22,
-  NonLazyBind = 23,
-  OptimizeNone = 24,
-  ReadNone = 26,
-  SanitizeHWAddress = 28,
-  WillReturn = 29,
-  StackProtectReq = 30,
-  StackProtectStrong = 31,
-  StackProtect = 32,
-  NoUndef = 33,
-  SanitizeMemTag = 34,
-  NoCfCheck = 35,
-  ShadowCallStack = 36,
-  AllocSize = 37,
-  AllocatedPointer = 38,
-  AllocAlign = 39,
-  SanitizeSafeStack = 40,
-  FnRetThunkExtern = 41,
-  Writable = 42,
-  DeadOnUnwind = 43,
-};
-
 typedef struct OpaqueRustString *RustStringRef;
 typedef struct LLVMOpaqueTwine *LLVMTwineRef;
 typedef struct LLVMOpaqueSMDiagnostic *LLVMSMDiagnosticRef;
 
-extern "C" void LLVMRustStringWriteImpl(RustStringRef Str, const char *Ptr,
-                                        size_t Size);
+extern "C" void LLVMRustStringWriteImpl(RustStringRef buf,
+                                        const char *slice_ptr,
+                                        size_t slice_len);
 
 class RawRustStringOstream : public llvm::raw_ostream {
   RustStringRef Str;
@@ -126,3 +45,5 @@ public:
     flush();
   }
 };
+
+#endif // INCLUDED_RUSTC_LLVM_LLVMWRAPPER_H
diff --git a/compiler/rustc_llvm/llvm-wrapper/Linker.cpp b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp
index f43128ed550..fdf54e2d9b4 100644
--- a/compiler/rustc_llvm/llvm-wrapper/Linker.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp
@@ -1,8 +1,10 @@
-#include "llvm/Linker/Linker.h"
-#include "SuppressLLVMWarnings.h"
-
 #include "LLVMWrapper.h"
 
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Linker/Linker.h"
+#include "llvm/Support/MemoryBuffer.h"
+
 using namespace llvm;
 
 struct RustLinker {
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index eb99d560e57..1ed702ab4cb 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1,25 +1,21 @@
-#include <stdio.h>
-
-#include <cstddef>
-#include <iomanip>
-#include <set>
-#include <vector>
-
 #include "LLVMWrapper.h"
 
-#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm-c/Core.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/Lint.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
-#include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Bitcode/BitcodeWriter.h"
 #include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/AssemblyAnnotationWriter.h"
 #include "llvm/IR/AutoUpgrade.h"
-#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/PassManager.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/LTO/LTO.h"
+#include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
-#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Passes/PassBuilder.h"
 #include "llvm/Passes/PassPlugin.h"
@@ -30,25 +26,28 @@
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/TargetParser/Host.h"
-#include "llvm/Transforms/IPO/AlwaysInliner.h"
 #include "llvm/Transforms/IPO/FunctionImport.h"
 #include "llvm/Transforms/IPO/Internalize.h"
 #include "llvm/Transforms/IPO/LowerTypeTests.h"
 #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
 #include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
 #include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
-#include "llvm/Transforms/Utils/AddDiscriminators.h"
-#include "llvm/Transforms/Utils/FunctionImportUtils.h"
-#if LLVM_VERSION_GE(19, 0)
-#include "llvm/Support/PGOOptions.h"
-#endif
 #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
 #include "llvm/Transforms/Instrumentation/InstrProfiling.h"
 #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
-#include "llvm/Transforms/Utils.h"
 #include "llvm/Transforms/Utils/CanonicalizeAliases.h"
+#include "llvm/Transforms/Utils/FunctionImportUtils.h"
 #include "llvm/Transforms/Utils/NameAnonGlobals.h"
+#include <set>
+#include <string>
+#include <vector>
+
+// Conditional includes prevent clang-format from fully sorting the list,
+// so keep them separate.
+#if LLVM_VERSION_GE(19, 0)
+#include "llvm/Support/PGOOptions.h"
+#endif
 
 using namespace llvm;
 
@@ -1624,5 +1623,6 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
                            CfiFunctionDefs, CfiFunctionDecls);
 #endif
 
-  LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size());
+  auto OS = RawRustStringOstream(KeyOut);
+  OS << Key.str();
 }
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index a68eed03e61..cd70c3f2669 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1,28 +1,38 @@
 #include "LLVMWrapper.h"
+
+#include "llvm-c/Core.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
 #include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/DIBuilder.h"
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "llvm/IR/DiagnosticHandler.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/DiagnosticPrinter.h"
 #include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Instructions.h"
-#include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsARM.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/LLVMRemarkStreamer.h"
 #include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
 #include "llvm/IR/Value.h"
-#include "llvm/Object/Archive.h"
 #include "llvm/Object/COFFImportFile.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Pass.h"
 #include "llvm/Remarks/RemarkFormat.h"
 #include "llvm/Remarks/RemarkSerializer.h"
 #include "llvm/Remarks/RemarkStreamer.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/JSON.h"
 #include "llvm/Support/ModRef.h"
 #include "llvm/Support/Signals.h"
+#include "llvm/Support/Timer.h"
 #include "llvm/Support/ToolOutputFile.h"
-
 #include <iostream>
 
 // for raw `write` in the bad-alloc handler
@@ -216,94 +226,140 @@ extern "C" LLVMValueRef LLVMRustInsertPrivateGlobal(LLVMModuleRef M,
                                  GlobalValue::PrivateLinkage, nullptr));
 }
 
-static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
+// Must match the layout of `rustc_codegen_llvm::llvm::ffi::AttributeKind`.
+enum class LLVMRustAttributeKind {
+  AlwaysInline = 0,
+  ByVal = 1,
+  Cold = 2,
+  InlineHint = 3,
+  MinSize = 4,
+  Naked = 5,
+  NoAlias = 6,
+  NoCapture = 7,
+  NoInline = 8,
+  NonNull = 9,
+  NoRedZone = 10,
+  NoReturn = 11,
+  NoUnwind = 12,
+  OptimizeForSize = 13,
+  ReadOnly = 14,
+  SExt = 15,
+  StructRet = 16,
+  UWTable = 17,
+  ZExt = 18,
+  InReg = 19,
+  SanitizeThread = 20,
+  SanitizeAddress = 21,
+  SanitizeMemory = 22,
+  NonLazyBind = 23,
+  OptimizeNone = 24,
+  ReadNone = 26,
+  SanitizeHWAddress = 28,
+  WillReturn = 29,
+  StackProtectReq = 30,
+  StackProtectStrong = 31,
+  StackProtect = 32,
+  NoUndef = 33,
+  SanitizeMemTag = 34,
+  NoCfCheck = 35,
+  ShadowCallStack = 36,
+  AllocSize = 37,
+  AllocatedPointer = 38,
+  AllocAlign = 39,
+  SanitizeSafeStack = 40,
+  FnRetThunkExtern = 41,
+  Writable = 42,
+  DeadOnUnwind = 43,
+};
+
+static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
   switch (Kind) {
-  case AlwaysInline:
+  case LLVMRustAttributeKind::AlwaysInline:
     return Attribute::AlwaysInline;
-  case ByVal:
+  case LLVMRustAttributeKind::ByVal:
     return Attribute::ByVal;
-  case Cold:
+  case LLVMRustAttributeKind::Cold:
     return Attribute::Cold;
-  case InlineHint:
+  case LLVMRustAttributeKind::InlineHint:
     return Attribute::InlineHint;
-  case MinSize:
+  case LLVMRustAttributeKind::MinSize:
     return Attribute::MinSize;
-  case Naked:
+  case LLVMRustAttributeKind::Naked:
     return Attribute::Naked;
-  case NoAlias:
+  case LLVMRustAttributeKind::NoAlias:
     return Attribute::NoAlias;
-  case NoCapture:
+  case LLVMRustAttributeKind::NoCapture:
     return Attribute::NoCapture;
-  case NoCfCheck:
+  case LLVMRustAttributeKind::NoCfCheck:
     return Attribute::NoCfCheck;
-  case NoInline:
+  case LLVMRustAttributeKind::NoInline:
     return Attribute::NoInline;
-  case NonNull:
+  case LLVMRustAttributeKind::NonNull:
     return Attribute::NonNull;
-  case NoRedZone:
+  case LLVMRustAttributeKind::NoRedZone:
     return Attribute::NoRedZone;
-  case NoReturn:
+  case LLVMRustAttributeKind::NoReturn:
     return Attribute::NoReturn;
-  case NoUnwind:
+  case LLVMRustAttributeKind::NoUnwind:
     return Attribute::NoUnwind;
-  case OptimizeForSize:
+  case LLVMRustAttributeKind::OptimizeForSize:
     return Attribute::OptimizeForSize;
-  case ReadOnly:
+  case LLVMRustAttributeKind::ReadOnly:
     return Attribute::ReadOnly;
-  case SExt:
+  case LLVMRustAttributeKind::SExt:
     return Attribute::SExt;
-  case StructRet:
+  case LLVMRustAttributeKind::StructRet:
     return Attribute::StructRet;
-  case UWTable:
+  case LLVMRustAttributeKind::UWTable:
     return Attribute::UWTable;
-  case ZExt:
+  case LLVMRustAttributeKind::ZExt:
     return Attribute::ZExt;
-  case InReg:
+  case LLVMRustAttributeKind::InReg:
     return Attribute::InReg;
-  case SanitizeThread:
+  case LLVMRustAttributeKind::SanitizeThread:
     return Attribute::SanitizeThread;
-  case SanitizeAddress:
+  case LLVMRustAttributeKind::SanitizeAddress:
     return Attribute::SanitizeAddress;
-  case SanitizeMemory:
+  case LLVMRustAttributeKind::SanitizeMemory:
     return Attribute::SanitizeMemory;
-  case NonLazyBind:
+  case LLVMRustAttributeKind::NonLazyBind:
     return Attribute::NonLazyBind;
-  case OptimizeNone:
+  case LLVMRustAttributeKind::OptimizeNone:
     return Attribute::OptimizeNone;
-  case ReadNone:
+  case LLVMRustAttributeKind::ReadNone:
     return Attribute::ReadNone;
-  case SanitizeHWAddress:
+  case LLVMRustAttributeKind::SanitizeHWAddress:
     return Attribute::SanitizeHWAddress;
-  case WillReturn:
+  case LLVMRustAttributeKind::WillReturn:
     return Attribute::WillReturn;
-  case StackProtectReq:
+  case LLVMRustAttributeKind::StackProtectReq:
     return Attribute::StackProtectReq;
-  case StackProtectStrong:
+  case LLVMRustAttributeKind::StackProtectStrong:
     return Attribute::StackProtectStrong;
-  case StackProtect:
+  case LLVMRustAttributeKind::StackProtect:
     return Attribute::StackProtect;
-  case NoUndef:
+  case LLVMRustAttributeKind::NoUndef:
     return Attribute::NoUndef;
-  case SanitizeMemTag:
+  case LLVMRustAttributeKind::SanitizeMemTag:
     return Attribute::SanitizeMemTag;
-  case ShadowCallStack:
+  case LLVMRustAttributeKind::ShadowCallStack:
     return Attribute::ShadowCallStack;
-  case AllocSize:
+  case LLVMRustAttributeKind::AllocSize:
     return Attribute::AllocSize;
-  case AllocatedPointer:
+  case LLVMRustAttributeKind::AllocatedPointer:
     return Attribute::AllocatedPointer;
-  case AllocAlign:
+  case LLVMRustAttributeKind::AllocAlign:
     return Attribute::AllocAlign;
-  case SanitizeSafeStack:
+  case LLVMRustAttributeKind::SanitizeSafeStack:
     return Attribute::SafeStack;
-  case FnRetThunkExtern:
+  case LLVMRustAttributeKind::FnRetThunkExtern:
     return Attribute::FnRetThunkExtern;
-  case Writable:
+  case LLVMRustAttributeKind::Writable:
     return Attribute::Writable;
-  case DeadOnUnwind:
+  case LLVMRustAttributeKind::DeadOnUnwind:
     return Attribute::DeadOnUnwind;
   }
-  report_fatal_error("bad AttributeKind");
+  report_fatal_error("bad LLVMRustAttributeKind");
 }
 
 template <typename T>
@@ -333,7 +389,7 @@ extern "C" void LLVMRustAddCallSiteAttributes(LLVMValueRef Instr,
 }
 
 extern "C" LLVMAttributeRef
-LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttribute RustAttr) {
+LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) {
   return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr)));
 }
 
@@ -1249,6 +1305,14 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
   return wrap(Loc);
 }
 
+extern "C" LLVMMetadataRef
+LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location,
+                                             unsigned BD) {
+  DILocation *Loc = unwrapDIPtr<DILocation>(Location);
+  auto NewLoc = Loc->cloneWithBaseDiscriminator(BD);
+  return wrap(NewLoc.has_value() ? NewLoc.value() : nullptr);
+}
+
 extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
   return dwarf::DW_OP_deref;
 }
@@ -1510,8 +1574,8 @@ LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut,
   const SourceMgr &LSM = *D.getSourceMgr();
   const MemoryBuffer *LBuf =
       LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc()));
-  LLVMRustStringWriteImpl(BufferOut, LBuf->getBufferStart(),
-                          LBuf->getBufferSize());
+  auto BufferOS = RawRustStringOstream(BufferOut);
+  BufferOS << LBuf->getBuffer();
 
   *LocOut = D.getLoc().getPointer() - LBuf->getBufferStart();
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
index 54ee79dc290..a910e78d489 100644
--- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
@@ -8,14 +8,14 @@
 // * https://github.com/llvm/llvm-project/blob/ef6d1ec07c693352c4a60dd58db08d2d8558f6ea/llvm/lib/Object/ArchiveWriter.cpp
 
 #include "LLVMWrapper.h"
-#include "SuppressLLVMWarnings.h"
+
 #include "llvm/ADT/SmallString.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Object/COFFImportFile.h"
 #include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/ObjectFile.h"
-#include <llvm/Support/raw_ostream.h>
+#include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 using namespace llvm::sys;
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index 055d2bd5bc9..eda9b2b1fc0 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -2,42 +2,75 @@
 #![allow(internal_features)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
+#![feature(extern_types)]
 #![feature(rustdoc_internals)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
-// NOTE: This crate only exists to allow linking on mingw targets.
-
 use std::cell::RefCell;
-use std::slice;
+use std::{ptr, slice};
 
-use libc::{c_char, size_t};
+use libc::size_t;
 
-#[repr(C)]
-pub struct RustString {
-    pub bytes: RefCell<Vec<u8>>,
+unsafe extern "C" {
+    /// Opaque type that allows C++ code to write bytes to a Rust-side buffer,
+    /// in conjunction with `RawRustStringOstream`. Use this as `&RustString`
+    /// (Rust) and `RustStringRef` (C++) in FFI signatures.
+    pub type RustString;
 }
 
 impl RustString {
-    pub fn len(&self) -> usize {
-        self.bytes.borrow().len()
+    pub fn build_byte_buffer(closure: impl FnOnce(&Self)) -> Vec<u8> {
+        let buf = RustStringInner::default();
+        closure(buf.as_opaque());
+        buf.into_inner()
     }
+}
 
-    pub fn is_empty(&self) -> bool {
-        self.bytes.borrow().is_empty()
+/// Underlying implementation of [`RustString`].
+///
+/// Having two separate types makes it possible to use the opaque [`RustString`]
+/// in FFI signatures without `improper_ctypes` warnings. This is a workaround
+/// for the fact that there is no way to opt out of `improper_ctypes` when
+/// _declaring_ a type (as opposed to using that type).
+#[derive(Default)]
+struct RustStringInner {
+    bytes: RefCell<Vec<u8>>,
+}
+
+impl RustStringInner {
+    fn as_opaque(&self) -> &RustString {
+        let ptr: *const RustStringInner = ptr::from_ref(self);
+        // We can't use `ptr::cast` here because extern types are `!Sized`.
+        let ptr = ptr as *const RustString;
+        unsafe { &*ptr }
+    }
+
+    fn from_opaque(opaque: &RustString) -> &Self {
+        // SAFETY: A valid `&RustString` must have been created via `as_opaque`.
+        let ptr: *const RustString = ptr::from_ref(opaque);
+        let ptr: *const RustStringInner = ptr.cast();
+        unsafe { &*ptr }
+    }
+
+    fn into_inner(self) -> Vec<u8> {
+        self.bytes.into_inner()
     }
 }
 
-/// Appending to a Rust string -- used by RawRustStringOstream.
+/// Appends the contents of a byte slice to a [`RustString`].
+///
+/// This function is implemented in `rustc_llvm` so that the C++ code in this
+/// crate can link to it directly, without an implied link-time dependency on
+/// `rustc_codegen_llvm`.
 #[unsafe(no_mangle)]
 pub unsafe extern "C" fn LLVMRustStringWriteImpl(
-    sr: &RustString,
-    ptr: *const c_char,
-    size: size_t,
+    buf: &RustString,
+    slice_ptr: *const u8, // Same ABI as `*const c_char`
+    slice_len: size_t,
 ) {
-    let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size) };
-
-    sr.bytes.borrow_mut().extend_from_slice(slice);
+    let slice = unsafe { slice::from_raw_parts(slice_ptr, slice_len) };
+    RustStringInner::from_opaque(buf).bytes.borrow_mut().extend_from_slice(slice);
 }
 
 /// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`.
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index b0c0e1be500..f225ad94aa7 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -12,11 +12,12 @@ use std::io::{Read, Write};
 use std::num::NonZero;
 use std::{fmt, io};
 
-use rustc_abi::{AddressSpace, Endian, HasDataLayout};
-use rustc_ast::LitKind;
+use rustc_abi::{AddressSpace, Align, Endian, HasDataLayout, Size};
+use rustc_ast::{LitKind, Mutability};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -45,7 +46,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance};
 pub use self::value::Scalar;
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::{self, Instance, Ty, TyCtxt};
+use crate::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
 
 /// Uniquely identifies one of the following:
 /// - A constant
@@ -310,6 +311,85 @@ impl<'tcx> GlobalAlloc<'tcx> {
             }
         }
     }
+
+    pub fn mutability(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Mutability {
+        // Let's see what kind of memory we are.
+        match self {
+            GlobalAlloc::Static(did) => {
+                let DefKind::Static { safety: _, mutability, nested } = tcx.def_kind(did) else {
+                    bug!()
+                };
+                if nested {
+                    // Nested statics in a `static` are never interior mutable,
+                    // so just use the declared mutability.
+                    if cfg!(debug_assertions) {
+                        let alloc = tcx.eval_static_initializer(did).unwrap();
+                        assert_eq!(alloc.0.mutability, mutability);
+                    }
+                    mutability
+                } else {
+                    let mutability = match mutability {
+                        Mutability::Not
+                            if !tcx
+                                .type_of(did)
+                                .no_bound_vars()
+                                .expect("statics should not have generic parameters")
+                                .is_freeze(tcx, param_env) =>
+                        {
+                            Mutability::Mut
+                        }
+                        _ => mutability,
+                    };
+                    mutability
+                }
+            }
+            GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
+            GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => {
+                // These are immutable.
+                Mutability::Not
+            }
+        }
+    }
+
+    pub fn size_and_align(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> (Size, Align) {
+        match self {
+            GlobalAlloc::Static(def_id) => {
+                let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else {
+                    bug!("GlobalAlloc::Static is not a static")
+                };
+
+                if nested {
+                    // Nested anonymous statics are untyped, so let's get their
+                    // size and alignment from the allocation itself. This always
+                    // succeeds, as the query is fed at DefId creation time, so no
+                    // evaluation actually occurs.
+                    let alloc = tcx.eval_static_initializer(def_id).unwrap();
+                    (alloc.0.size(), alloc.0.align)
+                } else {
+                    // Use size and align of the type for everything else. We need
+                    // to do that to
+                    // * avoid cycle errors in case of self-referential statics,
+                    // * be able to get information on extern statics.
+                    let ty = tcx
+                        .type_of(def_id)
+                        .no_bound_vars()
+                        .expect("statics should not have generic parameters");
+                    let layout = tcx.layout_of(param_env.and(ty)).unwrap();
+                    assert!(layout.is_sized());
+                    (layout.size, layout.align.abi)
+                }
+            }
+            GlobalAlloc::Memory(alloc) => {
+                let alloc = alloc.inner();
+                (alloc.size(), alloc.align)
+            }
+            GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE),
+            GlobalAlloc::VTable(..) => {
+                // No data to be accessed here. But vtables are pointer-aligned.
+                return (Size::ZERO, tcx.data_layout.pointer_align.abi);
+            }
+        }
+    }
 }
 
 pub const CTFE_ALLOC_SALT: usize = 0;
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 40e5ec45959..09731d565b6 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -193,6 +193,11 @@ pub enum ObligationCauseCode<'tcx> {
     /// The span corresponds to the clause.
     WhereClause(DefId, Span),
 
+    /// Represents a bound for an opaque we are checking the well-formedness of.
+    /// The def-id corresponds to a specific definition site that we found the
+    /// hidden type from, if any.
+    OpaqueTypeBound(Span, Option<LocalDefId>),
+
     /// Like `WhereClause`, but also identifies the expression
     /// which requires the `where` clause to be proven, and also
     /// identifies the index of the predicate in the `predicates_of`
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 76e3183fcbb..a0eb9029319 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1011,25 +1011,41 @@ where
             }
 
             _ => {
-                let mut data_variant = match this.variants {
+                let mut data_variant = match &this.variants {
                     // Within the discriminant field, only the niche itself is
                     // always initialized, so we only check for a pointer at its
                     // offset.
                     //
-                    // If the niche is a pointer, it's either valid (according
-                    // to its type), or null (which the niche field's scalar
-                    // validity range encodes). This allows using
-                    // `dereferenceable_or_null` for e.g., `Option<&T>`, and
-                    // this will continue to work as long as we don't start
-                    // using more niches than just null (e.g., the first page of
-                    // the address space, or unaligned pointers).
+                    // Our goal here is to check whether this represents a
+                    // "dereferenceable or null" pointer, so we need to ensure
+                    // that there is only one other variant, and it must be null.
+                    // Below, we will then check whether the pointer is indeed
+                    // dereferenceable.
                     Variants::Multiple {
-                        tag_encoding: TagEncoding::Niche { untagged_variant, .. },
+                        tag_encoding:
+                            TagEncoding::Niche { untagged_variant, niche_variants, niche_start },
                         tag_field,
+                        variants,
                         ..
-                    } if this.fields.offset(tag_field) == offset => {
-                        Some(this.for_variant(cx, untagged_variant))
+                    } if variants.len() == 2 && this.fields.offset(*tag_field) == offset => {
+                        let tagged_variant = if untagged_variant.as_u32() == 0 {
+                            VariantIdx::from_u32(1)
+                        } else {
+                            VariantIdx::from_u32(0)
+                        };
+                        assert_eq!(tagged_variant, *niche_variants.start());
+                        if *niche_start == 0 {
+                            // The other variant is encoded as "null", so we can recurse searching for
+                            // a pointer here. This relies on the fact that the codegen backend
+                            // only adds "dereferenceable" if there's also a "nonnull" proof,
+                            // and that null is aligned for all alignments so it's okay to forward
+                            // the pointer's alignment.
+                            Some(this.for_variant(cx, *untagged_variant))
+                        } else {
+                            None
+                        }
                     }
+                    Variants::Multiple { .. } => None,
                     _ => Some(this),
                 };
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6d9ba3d60e3..1a3128ed936 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1076,11 +1076,6 @@ impl<'tcx> ParamEnv<'tcx> {
         ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) }
     }
 
-    pub fn with_user_facing(mut self) -> Self {
-        self.packed.set_tag(ParamTag { reveal: Reveal::UserFacing, ..self.packed.tag() });
-        self
-    }
-
     /// Returns a new parameter environment with the same clauses, but
     /// which "reveals" the true results of projections in all cases
     /// (even for associated types that are specializable). This is
@@ -1095,6 +1090,12 @@ impl<'tcx> ParamEnv<'tcx> {
             return self;
         }
 
+        // No need to reveal opaques with the new solver enabled,
+        // since we have lazy norm.
+        if tcx.next_trait_solver_globally() {
+            return ParamEnv::new(self.caller_bounds(), Reveal::All);
+        }
+
         ParamEnv::new(tcx.reveal_opaque_types_in_bounds(self.caller_bounds()), Reveal::All)
     }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index e27bb2fd135..142db8a17f0 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1933,6 +1933,7 @@ impl<'tcx> Ty<'tcx> {
                 ty::UintTy::U64 => Some(sym::u64),
                 ty::UintTy::U128 => Some(sym::u128),
             },
+            ty::Str => Some(sym::str),
             _ => None,
         }
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index fc5a3b762e5..3c6e34160f4 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1751,6 +1751,7 @@ pub fn reveal_opaque_types_in_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     val: ty::Clauses<'tcx>,
 ) -> ty::Clauses<'tcx> {
+    assert!(!tcx.next_trait_solver_globally());
     let mut visitor = OpaqueTypeExpander {
         seen_opaque_tys: FxHashSet::default(),
         expanded_cache: FxHashMap::default(),
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 1af7fb9b86a..ef259703f0c 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -77,6 +77,8 @@ parse_box_syntax_removed_suggestion = use `Box::new()` instead
 
 parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
 
+parse_cannot_be_raw_lifetime = `{$ident}` cannot be a raw lifetime
+
 parse_catch_after_try = keyword `catch` cannot follow a `try` block
     .help = try using `match` on the result of the `try` block instead
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index fdd500e90f8..7ec4ad6dc35 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2019,6 +2019,14 @@ pub(crate) struct CannotBeRawIdent {
 }
 
 #[derive(Diagnostic)]
+#[diag(parse_cannot_be_raw_lifetime)]
+pub(crate) struct CannotBeRawLifetime {
+    #[primary_span]
+    pub span: Span,
+    pub ident: Symbol,
+}
+
+#[derive(Diagnostic)]
 #[diag(parse_keyword_lifetime)]
 pub(crate) struct KeywordLifetime {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index d627ef3d2cb..226de65445c 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -294,15 +294,21 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
                     let prefix_span = self.mk_sp(start, ident_start);
 
                     if prefix_span.at_least_rust_2021() {
-                        let lifetime_name_without_tick = self.str_from(ident_start);
+                        let span = self.mk_sp(start, self.pos);
+
+                        let lifetime_name_without_tick = Symbol::intern(&self.str_from(ident_start));
+                        if !lifetime_name_without_tick.can_be_raw() {
+                            self.dcx().emit_err(errors::CannotBeRawLifetime { span, ident: lifetime_name_without_tick });
+                        }
+
                         // Put the `'` back onto the lifetime name.
-                        let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.len() + 1);
+                        let mut lifetime_name = String::with_capacity(lifetime_name_without_tick.as_str().len() + 1);
                         lifetime_name.push('\'');
-                        lifetime_name += lifetime_name_without_tick;
+                        lifetime_name += lifetime_name_without_tick.as_str();
                         let sym = Symbol::intern(&lifetime_name);
 
                         // Make sure we mark this as a raw identifier.
-                        self.psess.raw_identifier_spans.push(self.mk_sp(start, self.pos));
+                        self.psess.raw_identifier_spans.push(span);
 
                         token::Lifetime(sym, IdentIsRaw::Yes)
                     } else {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 42455983575..09f5a8e96d3 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1472,7 +1472,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
             };
 
             if lhs_span.eq_ctxt(rhs_span) {
-                err.span_suggestion(
+                err.span_suggestion_verbose(
                     lhs_span.between(rhs_span),
                     MESSAGE,
                     "::",
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index fe05605c1b9..fa2403db925 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -12,7 +12,7 @@ use std::hash::Hash;
 use std::path::{Path, PathBuf};
 use std::str::{self, FromStr};
 use std::sync::LazyLock;
-use std::{fmt, fs, iter};
+use std::{cmp, fmt, fs, iter};
 
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
@@ -1367,13 +1367,38 @@ pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum OptionStability {
+pub enum OptionStability {
     Stable,
     Unstable,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum OptionKind {
+    /// An option that takes a value, and cannot appear more than once (e.g. `--out-dir`).
+    ///
+    /// Corresponds to [`getopts::Options::optopt`].
+    Opt,
+
+    /// An option that takes a value, and can appear multiple times (e.g. `--emit`).
+    ///
+    /// Corresponds to [`getopts::Options::optmulti`].
+    Multi,
+
+    /// An option that does not take a value, and cannot appear more than once (e.g. `--help`).
+    ///
+    /// Corresponds to [`getopts::Options::optflag`].
+    /// The `hint` string must be empty.
+    Flag,
+
+    /// An option that does not take a value, and can appear multiple times (e.g. `-O`).
+    ///
+    /// Corresponds to [`getopts::Options::optflagmulti`].
+    /// The `hint` string must be empty.
+    FlagMulti,
+}
+
 pub struct RustcOptGroup {
-    pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
+    apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
     pub name: &'static str,
     stability: OptionStability,
 }
@@ -1383,73 +1408,42 @@ impl RustcOptGroup {
         self.stability == OptionStability::Stable
     }
 
-    pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
-    where
-        F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
-    {
-        RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
-    }
-
-    pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
-    where
-        F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
-    {
-        RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
+    pub fn apply(&self, options: &mut getopts::Options) {
+        (self.apply)(options);
     }
 }
 
-// The `opt` local module holds wrappers around the `getopts` API that
-// adds extra rustc-specific metadata to each option; such metadata
-// is exposed by . The public
-// functions below ending with `_u` are the functions that return
-// *unstable* options, i.e., options that are only enabled when the
-// user also passes the `-Z unstable-options` debugging flag.
-mod opt {
-    // The `fn flag*` etc below are written so that we can use them
-    // in the future; do not warn about them not being used right now.
-    #![allow(dead_code)]
-
-    use super::RustcOptGroup;
-
-    type R = RustcOptGroup;
-    type S = &'static str;
-
-    fn stable<F>(name: S, f: F) -> R
-    where
-        F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
-    {
-        RustcOptGroup::stable(name, f)
-    }
-
-    fn unstable<F>(name: S, f: F) -> R
-    where
-        F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
-    {
-        RustcOptGroup::unstable(name, f)
-    }
-
-    fn longer(a: S, b: S) -> S {
-        if a.len() > b.len() { a } else { b }
-    }
-
-    pub(crate) fn opt_s(a: S, b: S, c: S, d: S) -> R {
-        stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
-    }
-    pub(crate) fn multi_s(a: S, b: S, c: S, d: S) -> R {
-        stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
-    }
-    pub(crate) fn flag_s(a: S, b: S, c: S) -> R {
-        stable(longer(a, b), move |opts| opts.optflag(a, b, c))
-    }
-    pub(crate) fn flagmulti_s(a: S, b: S, c: S) -> R {
-        stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
-    }
-
-    fn opt(a: S, b: S, c: S, d: S) -> R {
-        unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
-    }
-    pub(crate) fn multi(a: S, b: S, c: S, d: S) -> R {
-        unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
+pub fn make_opt(
+    stability: OptionStability,
+    kind: OptionKind,
+    short_name: &'static str,
+    long_name: &'static str,
+    desc: &'static str,
+    hint: &'static str,
+) -> RustcOptGroup {
+    RustcOptGroup {
+        name: cmp::max_by_key(short_name, long_name, |s| s.len()),
+        stability,
+        apply: match kind {
+            OptionKind::Opt => Box::new(move |opts: &mut getopts::Options| {
+                opts.optopt(short_name, long_name, desc, hint)
+            }),
+            OptionKind::Multi => Box::new(move |opts: &mut getopts::Options| {
+                opts.optmulti(short_name, long_name, desc, hint)
+            }),
+            OptionKind::Flag => {
+                assert_eq!(hint, "");
+                Box::new(move |opts: &mut getopts::Options| {
+                    opts.optflag(short_name, long_name, desc)
+                })
+            }
+            OptionKind::FlagMulti => {
+                assert_eq!(hint, "");
+                Box::new(move |opts: &mut getopts::Options| {
+                    opts.optflagmulti(short_name, long_name, desc)
+                })
+            }
+        },
     }
 }
 
@@ -1464,46 +1458,60 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE
 /// including metadata for each option, such as whether the option is
 /// part of the stable long-term interface for rustc.
 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
+    use OptionKind::{Flag, FlagMulti, Multi, Opt};
+    use OptionStability::Stable;
+
+    use self::make_opt as opt;
+
     vec![
-        opt::flag_s("h", "help", "Display this message"),
-        opt::multi_s("", "cfg", "Configure the compilation environment.
-                             SPEC supports the syntax `NAME[=\"VALUE\"]`.", "SPEC"),
-        opt::multi_s("", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"),
-        opt::multi_s(
+        opt(Stable, Flag, "h", "help", "Display this message", ""),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "cfg",
+            "Configure the compilation environment.\n\
+                SPEC supports the syntax `NAME[=\"VALUE\"]`.",
+            "SPEC",
+        ),
+        opt(Stable, Multi, "", "check-cfg", "Provide list of expected cfgs for checking", "SPEC"),
+        opt(
+            Stable,
+            Multi,
             "L",
             "",
-            "Add a directory to the library search path. The
-                             optional KIND can be one of dependency, crate, native,
-                             framework, or all (the default).",
+            "Add a directory to the library search path. \
+                The optional KIND can be one of dependency, crate, native, framework, or all (the default).",
             "[KIND=]PATH",
         ),
-        opt::multi_s(
+        opt(
+            Stable,
+            Multi,
             "l",
             "",
-            "Link the generated crate(s) to the specified native
-                             library NAME. The optional KIND can be one of
-                             static, framework, or dylib (the default).
-                             Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
-                             may be specified each with a prefix of either '+' to
-                             enable or '-' to disable.",
+            "Link the generated crate(s) to the specified native\n\
+                library NAME. The optional KIND can be one of\n\
+                static, framework, or dylib (the default).\n\
+                Optional comma separated MODIFIERS\n\
+                (bundle|verbatim|whole-archive|as-needed)\n\
+                may be specified each with a prefix of either '+' to\n\
+                enable or '-' to disable.",
             "[KIND[:MODIFIERS]=]NAME[:RENAME]",
         ),
         make_crate_type_option(),
-        opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
-        opt::opt_s(
-            "",
-            "edition",
-            &EDITION_STRING,
-            EDITION_NAME_LIST,
-        ),
-        opt::multi_s(
+        opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "NAME"),
+        opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
+        opt(
+            Stable,
+            Multi,
             "",
             "emit",
-            "Comma separated list of types of output for \
-             the compiler to emit",
+            "Comma separated list of types of output for the compiler to emit",
             "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
         ),
-        opt::multi_s(
+        opt(
+            Stable,
+            Multi,
             "",
             "print",
             "Compiler information to print on stdout",
@@ -1512,41 +1520,36 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
              tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
              stack-protector-strategies|link-args|deployment-target]",
         ),
-        opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
-        opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
-        opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
-        opt::opt_s(
-            "",
-            "out-dir",
-            "Write output to compiler-chosen filename \
-             in <dir>",
-            "DIR",
-        ),
-        opt::opt_s(
+        opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
+        opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=2", ""),
+        opt(Stable, Opt, "o", "", "Write output to <filename>", "FILENAME"),
+        opt(Stable, Opt, "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
+        opt(
+            Stable,
+            Opt,
             "",
             "explain",
-            "Provide a detailed explanation of an error \
-             message",
+            "Provide a detailed explanation of an error message",
             "OPT",
         ),
-        opt::flag_s("", "test", "Build a test harness"),
-        opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
-        opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
-        opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
-        opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
-        opt::multi_s("D", "deny", "Set lint denied", "LINT"),
-        opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
-        opt::multi_s(
+        opt(Stable, Flag, "", "test", "Build a test harness", ""),
+        opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", "TARGET"),
+        opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
+        opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
+        opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
+        opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
+        opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
+        opt(
+            Stable,
+            Multi,
             "",
             "cap-lints",
-            "Set the most restrictive lint level. \
-             More restrictive lints are capped at this \
-             level",
+            "Set the most restrictive lint level. More restrictive lints are capped at this level",
             "LEVEL",
         ),
-        opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
-        opt::flag_s("V", "version", "Print version info and exit"),
-        opt::flag_s("v", "verbose", "Use verbose output"),
+        opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
+        opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
+        opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
     ]
 }
 
@@ -1554,25 +1557,36 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
 /// each option, such as whether the option is part of the stable
 /// long-term interface for rustc.
 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
+    use OptionKind::{Multi, Opt};
+    use OptionStability::{Stable, Unstable};
+
+    use self::make_opt as opt;
+
     let mut opts = rustc_short_optgroups();
     // FIXME: none of these descriptions are actually used
     opts.extend(vec![
-        opt::multi_s(
+        opt(
+            Stable,
+            Multi,
             "",
             "extern",
             "Specify where an external rust library is located",
             "NAME[=PATH]",
         ),
-        opt::opt_s("", "sysroot", "Override the system root", "PATH"),
-        opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
-        opt::opt_s(
+        opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
+        opt(Unstable, Multi, "Z", "", "Set unstable / perma-unstable options", "FLAG"),
+        opt(
+            Stable,
+            Opt,
             "",
             "error-format",
             "How errors and other messages are produced",
             "human|json|short",
         ),
-        opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
-        opt::opt_s(
+        opt(Stable, Multi, "", "json", "Configure the JSON output of the compiler", "CONFIG"),
+        opt(
+            Stable,
+            Opt,
             "",
             "color",
             "Configure coloring of output:
@@ -1581,19 +1595,23 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
                                  never  = never colorize output",
             "auto|always|never",
         ),
-        opt::opt_s(
+        opt(
+            Stable,
+            Opt,
             "",
             "diagnostic-width",
             "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
             "WIDTH",
         ),
-        opt::multi_s(
+        opt(
+            Stable,
+            Multi,
             "",
             "remap-path-prefix",
             "Remap source names in all output (compiler messages and output files)",
             "FROM=TO",
         ),
-        opt::multi("", "env-set", "Inject an environment variable", "VAR=VALUE"),
+        opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"),
     ]);
     opts
 }
@@ -2756,7 +2774,9 @@ fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> O
 }
 
 pub fn make_crate_type_option() -> RustcOptGroup {
-    opt::multi_s(
+    make_opt(
+        OptionStability::Stable,
+        OptionKind::Multi,
         "",
         "crate-type",
         "Comma separated list of types of crates
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index f20ae85b8e8..21c11655110 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -155,6 +155,7 @@ pub fn feature_warn_issue(
 }
 
 /// Adds the diagnostics for a feature to an existing error.
+/// Must be a language feature!
 pub fn add_feature_diagnostics<G: EmissionGuarantee>(
     err: &mut Diag<'_, G>,
     sess: &Session,
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 470e372ee48..9d9434a7776 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -300,6 +300,7 @@ impl Session {
         self.opts.test
     }
 
+    /// `feature` must be a language feature.
     #[track_caller]
     pub fn create_feature_err<'a>(&'a self, err: impl Diagnostic<'a>, feature: Symbol) -> Diag<'a> {
         let mut err = self.dcx().create_err(err);
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 82cfbd28fff..c04c793ba46 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1867,6 +1867,7 @@ symbols! {
         slice_patterns,
         slicing_syntax,
         soft,
+        sparc_target_feature,
         specialization,
         speed,
         spotlight,
@@ -2109,6 +2110,7 @@ symbols! {
         usize_legacy_fn_max_value,
         usize_legacy_fn_min_value,
         usize_legacy_mod,
+        v8plus,
         va_arg,
         va_copy,
         va_end,
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 8c3df9c426b..aa639f1624f 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -143,7 +143,8 @@ pub struct ArgAttributes {
     pub regular: ArgAttribute,
     pub arg_ext: ArgExtension,
     /// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call
-    /// (corresponding to LLVM's dereferenceable and dereferenceable_or_null attributes).
+    /// (corresponding to LLVM's dereferenceable_or_null attributes, i.e., it is okay for this to be
+    /// set on a null pointer, but all non-null pointers must be dereferenceable).
     pub pointee_size: Size,
     pub pointee_align: Option<Align>,
 }
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
index f1854353abd..1511c0ccaad 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
+        data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
         arch: "aarch64".into(),
         options: TargetOptions {
             features: "+v8a,+outline-atomics".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
index 0dc51aaa73d..e7070778794 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs
@@ -14,7 +14,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 32,
-        data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
+        data_layout: "E-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
         arch: "aarch64".into(),
         options: TargetOptions {
             abi: "ilp32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
index f99e7fe84f5..f0f6e49eedd 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs
@@ -11,7 +11,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
+        data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
         arch: "aarch64".into(),
         options: TargetOptions {
             mcount: "__mcount".into(),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
index f33a5873c09..7b0df7d1130 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs
@@ -10,7 +10,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
+        data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
         arch: "aarch64".into(),
         options: TargetOptions {
             abi: "ilp32".into(),
diff --git a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
index 2777395757f..45941cd7c01 100644
--- a/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/sparc_unknown_linux_gnu.rs
@@ -14,6 +14,7 @@ pub(crate) fn target() -> Target {
         data_layout: "E-m:e-p:32:32-i64:64-i128:128-f128:64-n32-S64".into(),
         arch: "sparc".into(),
         options: TargetOptions {
+            features: "+v8plus".into(),
             cpu: "v9".into(),
             endian: Endian::Big,
             late_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &[
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 4dbaf1f7c95..c4f9c742650 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -545,6 +545,14 @@ const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-end
 ];
 
+const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
+    // tidy-alphabetical-start
+    ("leoncasa", Unstable(sym::sparc_target_feature), &[]),
+    ("v8plus", Unstable(sym::sparc_target_feature), &[]),
+    ("v9", Unstable(sym::sparc_target_feature), &[]),
+    // tidy-alphabetical-end
+];
+
 /// When rustdoc is running, provide a list of all known features so that all their respective
 /// primitives may be documented.
 ///
@@ -563,6 +571,7 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
         .chain(CSKY_FEATURES)
         .chain(LOONGARCH_FEATURES)
         .chain(IBMZ_FEATURES)
+        .chain(SPARC_FEATURES)
         .cloned()
         .map(|(f, s, _)| (f, s))
 }
@@ -589,6 +598,7 @@ impl super::spec::Target {
             "csky" => CSKY_FEATURES,
             "loongarch64" => LOONGARCH_FEATURES,
             "s390x" => IBMZ_FEATURES,
+            "sparc" | "sparc64" => SPARC_FEATURES,
             _ => &[],
         }
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 86fd4c230f6..a5e364d49f7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2953,6 +2953,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // We hold the `DefId` of the item introducing the obligation, but displaying it
                 // doesn't add user usable information. It always point at an associated item.
             }
+            ObligationCauseCode::OpaqueTypeBound(span, definition_def_id) => {
+                err.span_note(span, "required by a bound in an opaque type");
+                if let Some(definition_def_id) = definition_def_id
+                    // If there are any stalled coroutine obligations, then this
+                    // error may be due to that, and not because the body has more
+                    // where-clauses.
+                    && self.tcx.typeck(definition_def_id).coroutine_stalled_predicates.is_empty()
+                {
+                    // FIXME(compiler-errors): We could probably point to something
+                    // specific here if we tried hard enough...
+                    err.span_note(
+                        tcx.def_span(definition_def_id),
+                        "this definition site has more where clauses than the opaque type",
+                    );
+                }
+            }
             ObligationCauseCode::Coercion { source, target } => {
                 let source =
                     tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file);
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index adf103e9430..5d7adcace52 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -818,10 +818,12 @@ impl Error {
 
     /// Consumes the `Error`, returning its inner error (if any).
     ///
-    /// If this [`Error`] was constructed via [`new`] then this function will
-    /// return [`Some`], otherwise it will return [`None`].
+    /// If this [`Error`] was constructed via [`new`] or [`other`],
+    /// then this function will return [`Some`],
+    /// otherwise it will return [`None`].
     ///
     /// [`new`]: Error::new
+    /// [`other`]: Error::other
     ///
     /// # Examples
     ///
diff --git a/src/bootstrap/defaults/config.dist.toml b/src/bootstrap/defaults/config.dist.toml
index d4feffe0227..4346a9c2dd1 100644
--- a/src/bootstrap/defaults/config.dist.toml
+++ b/src/bootstrap/defaults/config.dist.toml
@@ -11,6 +11,7 @@ extended = true
 # Most users installing from source want to build all parts of the project from source.
 [llvm]
 download-ci-llvm = false
+
 [rust]
 # We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`).
 # Make sure they don't get set when installing from source.
diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml
index 3d697be8156..5447565a4b0 100644
--- a/src/bootstrap/defaults/config.library.toml
+++ b/src/bootstrap/defaults/config.library.toml
@@ -8,9 +8,6 @@ bench-stage = 0
 [rust]
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
-# Download rustc from CI instead of building it from source.
-# For stage > 1 builds, this cuts compile times significantly when there are no changes on "compiler" tree.
-download-rustc = "if-unchanged"
 # Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
 lto = "off"
 
diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml
index 27c1d1cf26d..76b47a841b3 100644
--- a/src/bootstrap/defaults/config.tools.toml
+++ b/src/bootstrap/defaults/config.tools.toml
@@ -3,11 +3,6 @@
 [rust]
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
-# Download rustc from CI instead of building it from source.
-# For stage > 1 builds, this cuts compile times significantly when there are no changes on "compiler" tree.
-# Using these defaults will download the stage2 compiler (see `download-rustc`
-# setting) and the stage2 toolchain should therefore be used for these defaults.
-download-rustc = "if-unchanged"
 
 [build]
 # Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile.
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index f977c285a74..a93038d51d3 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1665,10 +1665,26 @@ impl Config {
         let mut debuginfo_level_tools = None;
         let mut debuginfo_level_tests = None;
         let mut optimize = None;
-        let mut omit_git_hash = None;
         let mut lld_enabled = None;
         let mut std_features = None;
 
+        let default = config.channel == "dev";
+        config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default);
+
+        config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
+        config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo"));
+        config.rust_analyzer_info =
+            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer"));
+        config.clippy_info =
+            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy"));
+        config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri"));
+        config.rustfmt_info =
+            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
+        config.enzyme_info =
+            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme"));
+        config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project"));
+        config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc"));
+
         let mut is_user_configured_rust_channel = false;
 
         if let Some(rust) = toml.rust {
@@ -1699,7 +1715,7 @@ impl Config {
                 verbose_tests,
                 optimize_tests,
                 codegen_tests,
-                omit_git_hash: omit_git_hash_toml,
+                omit_git_hash: _, // already handled above
                 dist_src,
                 save_toolstates,
                 codegen_backends,
@@ -1750,7 +1766,6 @@ impl Config {
             std_features = std_features_toml;
 
             optimize = optimize_toml;
-            omit_git_hash = omit_git_hash_toml;
             config.rust_new_symbol_mangling = new_symbol_mangling;
             set(&mut config.rust_optimize_tests, optimize_tests);
             set(&mut config.codegen_tests, codegen_tests);
@@ -1826,24 +1841,6 @@ impl Config {
 
         config.reproducible_artifacts = flags.reproducible_artifact;
 
-        // rust_info must be set before is_ci_llvm_available() is called.
-        let default = config.channel == "dev";
-        config.omit_git_hash = omit_git_hash.unwrap_or(default);
-        config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
-
-        config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo"));
-        config.rust_analyzer_info =
-            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer"));
-        config.clippy_info =
-            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy"));
-        config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri"));
-        config.rustfmt_info =
-            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
-        config.enzyme_info =
-            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme"));
-        config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project"));
-        config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc"));
-
         // We need to override `rust.channel` if it's manually specified when using the CI rustc.
         // This is because if the compiler uses a different channel than the one specified in config.toml,
         // tests may fail due to using a different channel than the one used by the compiler during tests.
@@ -2760,9 +2757,19 @@ impl Config {
 
         // If `download-rustc` is not set, default to rebuilding.
         let if_unchanged = match download_rustc {
-            None | Some(StringOrBool::Bool(false)) => return None,
+            None => self.rust_info.is_managed_git_subrepository(),
+            Some(StringOrBool::Bool(false)) => return None,
             Some(StringOrBool::Bool(true)) => false,
-            Some(StringOrBool::String(s)) if s == "if-unchanged" => true,
+            Some(StringOrBool::String(s)) if s == "if-unchanged" => {
+                if !self.rust_info.is_managed_git_subrepository() {
+                    println!(
+                        "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources."
+                    );
+                    crate::exit!(1);
+                }
+
+                true
+            }
             Some(StringOrBool::String(other)) => {
                 panic!("unrecognized option for download-rustc: {other}")
             }
@@ -2789,7 +2796,7 @@ impl Config {
                     }
                     println!("ERROR: could not find commit hash for downloading rustc");
                     println!("HELP: maybe your repository history is too shallow?");
-                    println!("HELP: consider disabling `download-rustc`");
+                    println!("HELP: consider setting `rust.download-rustc=false` in config.toml");
                     println!("HELP: or fetch enough history to include one upstream commit");
                     crate::exit!(1);
                 }
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index 1f02757682c..b6523a458e2 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -135,6 +135,7 @@ change-id = 0
 [rust]
 lto = "off"
 deny-warnings = true
+download-rustc=false
 
 [build]
 gdb = "foo"
@@ -200,6 +201,8 @@ runner = "x86_64-runner"
             .collect(),
         "setting dictionary value"
     );
+    assert!(!config.llvm_from_ci);
+    assert!(!config.download_rustc());
 }
 
 #[test]
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index 3029c3989c9..f00a0fe7287 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -18,7 +18,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 - MSP430
 - M68k
 - CSKY
-- s390x
 - Arm64EC
 - SPARC
 
@@ -52,11 +51,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | M68k         | `reg_addr`     | `a[0-3]`                           | `a`                  |
 | CSKY         | `reg`          | `r[0-31]`                          | `r`                  |
 | CSKY         | `freg`         | `f[0-31]`                          | `f`                  |
-| s390x        | `reg`          | `r[0-10]`, `r[12-14]`              | `r`                  |
-| s390x        | `reg_addr`     | `r[1-10]`, `r[12-14]`              | `a`                  |
-| s390x        | `freg`         | `f[0-15]`                          | `f`                  |
-| s390x        | `vreg`         | `v[0-31]`                          | Only clobbers        |
-| s390x        | `areg`         | `a[2-15]`                          | Only clobbers        |
 | SPARC        | `reg`          | `r[2-29]`                          | `r`                  |
 | SPARC        | `yreg`         | `y`                                | Only clobbers        |
 | Arm64EC      | `reg`          | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r`            |
@@ -96,10 +90,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | M68k         | `reg_data`                      | None           | `i8`, `i16`, `i32`                      |
 | CSKY         | `reg`                           | None           | `i8`, `i16`, `i32`                      |
 | CSKY         | `freg`                          | None           | `f32`,                                  |
-| s390x        | `reg`, `reg_addr`               | None           | `i8`, `i16`, `i32`, `i64`               |
-| s390x        | `freg`                          | None           | `f32`, `f64`                            |
-| s390x        | `vreg`                          | N/A            | Only clobbers                           |
-| s390x        | `areg`                          | N/A            | Only clobbers                           |
 | SPARC        | `reg`                           | None           | `i8`, `i16`, `i32`, `i64` (SPARC64 only) |
 | SPARC        | `yreg`                          | N/A            | Only clobbers                           |
 | Arm64EC      | `reg`                           | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
@@ -159,8 +149,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 
 | Architecture | Unsupported register                    | Reason                                                                                                                                                                              |
 | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| All          | `sp`, `r15` (s390x), `r14`/`o6` (SPARC) | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
-| All          | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output.                             |
+| All          | `sp`, `r14`/`o6` (SPARC)                | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
+| All          | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output.                                            |
 | All          | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames.                                                             |
 | MIPS         | `$0` or `$zero`                         | This is a constant zero register which can't be modified.                                                                                                                           |
 | MIPS         | `$1` or `$at`                           | Reserved for assembler.                                                                                                                                                             |
@@ -181,8 +171,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `r15`                                   | This is the link register. |
 | CSKY         | `r[26-30]`                              | Reserved by its ABI.       |
 | CSKY         | `r31`                                   | This is the TLS register.  |
-| s390x        | `c[0-15]`                               | Reserved by the kernel. |
-| s390x        | `a[0-1]`                                | Reserved for system use. |
 | SPARC        | `r0`/`g0`                               | This is always zero and cannot be used as inputs or outputs. |
 | SPARC        | `r1`/`g1`                               | Used internally by LLVM. |
 | SPARC        | `r5`/`g5`                               | Reserved for system. (SPARC32 only) |
@@ -206,9 +194,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | PowerPC      | `reg`          | None     | `0`            | None          |
 | PowerPC      | `reg_nonzero`  | None     | `3`            | None          |
 | PowerPC      | `freg`         | None     | `0`            | None          |
-| s390x        | `reg`          | None     | `%r0`          | None          |
-| s390x        | `reg_addr`     | None     | `%r1`          | None          |
-| s390x        | `freg`         | None     | `%f0`          | None          |
 | SPARC        | `reg`          | None     | `%o0`          | None          |
 | CSKY         | `reg`          | None     | `r0`           | None          |
 | CSKY         | `freg`         | None     | `f0`           | None          |
@@ -232,8 +217,6 @@ These flags registers must be restored upon exiting the asm block if the `preser
   - The status register `r2`.
 - M68k
   - The condition code register `ccr`.
-- s390x
-  - The condition code register `cc`.
 - SPARC
   - Integer condition codes (`icc` and `xcc`)
   - Floating-point condition codes (`fcc[0-3]`)
diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml
index 9998ebcc03c..afddd089eb1 100644
--- a/src/etc/rust_analyzer_helix.toml
+++ b/src/etc/rust_analyzer_helix.toml
@@ -1,3 +1,12 @@
+# This config uses a separate build directory for rust-analyzer,
+# so that r-a's checks don't block user `x` commands and vice-verse.
+# R-a's build directory is located in `build/rust-analyzer`.
+#
+# To build rustfmt and proc macro server for r-a run the following command:
+# ```
+# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build/rust-analyzer
+# ```
+
 [language-server.rust-analyzer.config]
 linkedProjects = [
     "Cargo.toml",
@@ -17,16 +26,18 @@ overrideCommand = [
     "x.py",
     "check",
     "--json-output",
+    "--build-dir",
+    "build/rust-analyzer",
 ]
 
 [language-server.rust-analyzer.config.rustfmt]
 overrideCommand = [
-    "build-rust-analyzer/host/rustfmt/bin/rustfmt",
+    "build/rust-analyzer/host/rustfmt/bin/rustfmt",
     "--edition=2021"
 ]
 
 [language-server.rust-analyzer.config.procMacro]
-server = "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
+server = "build/rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
 enable = true
 
 [language-server.rust-analyzer.config.rustc]
@@ -47,4 +58,6 @@ overrideCommand = [
     "x.py",
     "check",
     "--json-output",
+    "--build-dir",
+    "build/rust-analyzer",
 ]
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 7c9dcd41e6a..78dc0b8e2f9 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -215,477 +215,482 @@ fn init_logging(early_dcx: &EarlyDiagCtxt) {
 }
 
 fn opts() -> Vec<RustcOptGroup> {
-    let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable;
-    let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable;
+    use rustc_session::config::OptionKind::{Flag, FlagMulti, Multi, Opt};
+    use rustc_session::config::OptionStability::{Stable, Unstable};
+    use rustc_session::config::make_opt as opt;
+
     vec![
-        stable("h", |o| o.optflagmulti("h", "help", "show this help message")),
-        stable("V", |o| o.optflagmulti("V", "version", "print rustdoc's version")),
-        stable("v", |o| o.optflagmulti("v", "verbose", "use verbose output")),
-        stable("w", |o| o.optopt("w", "output-format", "the output type to write", "[html]")),
-        stable("output", |o| {
-            o.optopt(
-                "",
-                "output",
-                "Which directory to place the output. \
-                 This option is deprecated, use --out-dir instead.",
-                "PATH",
-            )
-        }),
-        stable("o", |o| o.optopt("o", "out-dir", "which directory to place the output", "PATH")),
-        stable("crate-name", |o| {
-            o.optopt("", "crate-name", "specify the name of this crate", "NAME")
-        }),
+        opt(Stable, FlagMulti, "h", "help", "show this help message", ""),
+        opt(Stable, FlagMulti, "V", "version", "print rustdoc's version", ""),
+        opt(Stable, FlagMulti, "v", "verbose", "use verbose output", ""),
+        opt(Stable, Opt, "w", "output-format", "the output type to write", "[html]"),
+        opt(
+            Stable,
+            Opt,
+            "",
+            "output",
+            "Which directory to place the output. This option is deprecated, use --out-dir instead.",
+            "PATH",
+        ),
+        opt(Stable, Opt, "o", "out-dir", "which directory to place the output", "PATH"),
+        opt(Stable, Opt, "", "crate-name", "specify the name of this crate", "NAME"),
         make_crate_type_option(),
-        stable("L", |o| {
-            o.optmulti("L", "library-path", "directory to add to crate search path", "DIR")
-        }),
-        stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")),
-        stable("check-cfg", |o| o.optmulti("", "check-cfg", "pass a --check-cfg to rustc", "")),
-        stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")),
-        unstable("extern-html-root-url", |o| {
-            o.optmulti(
-                "",
-                "extern-html-root-url",
-                "base URL to use for dependencies; for example, \
-                 \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
-                "NAME=URL",
-            )
-        }),
-        unstable("extern-html-root-takes-precedence", |o| {
-            o.optflagmulti(
-                "",
-                "extern-html-root-takes-precedence",
-                "give precedence to `--extern-html-root-url`, not `html_root_url`",
-            )
-        }),
-        stable("C", |o| {
-            o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]")
-        }),
-        stable("document-private-items", |o| {
-            o.optflagmulti("", "document-private-items", "document private items")
-        }),
-        unstable("document-hidden-items", |o| {
-            o.optflagmulti("", "document-hidden-items", "document items that have doc(hidden)")
-        }),
-        stable("test", |o| o.optflagmulti("", "test", "run code examples as tests")),
-        stable("test-args", |o| {
-            o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS")
-        }),
-        stable("test-run-directory", |o| {
-            o.optopt(
-                "",
-                "test-run-directory",
-                "The working directory in which to run tests",
-                "PATH",
-            )
-        }),
-        stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")),
-        stable("markdown-css", |o| {
-            o.optmulti(
-                "",
-                "markdown-css",
-                "CSS files to include via <link> in a rendered Markdown file",
-                "FILES",
-            )
-        }),
-        stable("html-in-header", |o| {
-            o.optmulti(
-                "",
-                "html-in-header",
-                "files to include inline in the <head> section of a rendered Markdown file \
-                 or generated documentation",
-                "FILES",
-            )
-        }),
-        stable("html-before-content", |o| {
-            o.optmulti(
-                "",
-                "html-before-content",
-                "files to include inline between <body> and the content of a rendered \
-                 Markdown file or generated documentation",
-                "FILES",
-            )
-        }),
-        stable("html-after-content", |o| {
-            o.optmulti(
-                "",
-                "html-after-content",
-                "files to include inline between the content and </body> of a rendered \
-                 Markdown file or generated documentation",
-                "FILES",
-            )
-        }),
-        unstable("markdown-before-content", |o| {
-            o.optmulti(
-                "",
-                "markdown-before-content",
-                "files to include inline between <body> and the content of a rendered \
-                 Markdown file or generated documentation",
-                "FILES",
-            )
-        }),
-        unstable("markdown-after-content", |o| {
-            o.optmulti(
-                "",
-                "markdown-after-content",
-                "files to include inline between the content and </body> of a rendered \
-                 Markdown file or generated documentation",
-                "FILES",
-            )
-        }),
-        stable("markdown-playground-url", |o| {
-            o.optopt("", "markdown-playground-url", "URL to send code snippets to", "URL")
-        }),
-        stable("markdown-no-toc", |o| {
-            o.optflagmulti("", "markdown-no-toc", "don't include table of contents")
-        }),
-        stable("e", |o| {
-            o.optopt(
-                "e",
-                "extend-css",
-                "To add some CSS rules with a given file to generate doc with your \
-                 own theme. However, your theme might break if the rustdoc's generated HTML \
-                 changes, so be careful!",
-                "PATH",
-            )
-        }),
-        unstable("Z", |o| {
-            o.optmulti("Z", "", "unstable / perma-unstable options (only on nightly build)", "FLAG")
-        }),
-        stable("sysroot", |o| o.optopt("", "sysroot", "Override the system root", "PATH")),
-        unstable("playground-url", |o| {
-            o.optopt(
-                "",
-                "playground-url",
-                "URL to send code snippets to, may be reset by --markdown-playground-url \
-                 or `#![doc(html_playground_url=...)]`",
-                "URL",
-            )
-        }),
-        unstable("display-doctest-warnings", |o| {
-            o.optflagmulti(
-                "",
-                "display-doctest-warnings",
-                "show warnings that originate in doctests",
-            )
-        }),
-        stable("crate-version", |o| {
-            o.optopt("", "crate-version", "crate version to print into documentation", "VERSION")
-        }),
-        unstable("sort-modules-by-appearance", |o| {
-            o.optflagmulti(
-                "",
-                "sort-modules-by-appearance",
-                "sort modules by where they appear in the program, rather than alphabetically",
-            )
-        }),
-        stable("default-theme", |o| {
-            o.optopt(
-                "",
-                "default-theme",
-                "Set the default theme. THEME should be the theme name, generally lowercase. \
-                 If an unknown default theme is specified, the builtin default is used. \
-                 The set of themes, and the rustdoc built-in default, are not stable.",
-                "THEME",
-            )
-        }),
-        unstable("default-setting", |o| {
-            o.optmulti(
-                "",
-                "default-setting",
-                "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
-                 from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
-                 Supported SETTINGs and VALUEs are not documented and not stable.",
-                "SETTING[=VALUE]",
-            )
-        }),
-        stable("theme", |o| {
-            o.optmulti(
-                "",
-                "theme",
-                "additional themes which will be added to the generated docs",
-                "FILES",
-            )
-        }),
-        stable("check-theme", |o| {
-            o.optmulti("", "check-theme", "check if given theme is valid", "FILES")
-        }),
-        unstable("resource-suffix", |o| {
-            o.optopt(
-                "",
-                "resource-suffix",
-                "suffix to add to CSS and JavaScript files, e.g., \"search-index.js\" will \
-                 become \"search-index-suffix.js\"",
-                "PATH",
-            )
-        }),
-        stable("edition", |o| {
-            o.optopt(
-                "",
-                "edition",
-                "edition to use when compiling rust code (default: 2015)",
-                "EDITION",
-            )
-        }),
-        stable("color", |o| {
-            o.optopt(
-                "",
-                "color",
-                "Configure coloring of output:
+        opt(Stable, Multi, "L", "library-path", "directory to add to crate search path", "DIR"),
+        opt(Stable, Multi, "", "cfg", "pass a --cfg to rustc", ""),
+        opt(Stable, Multi, "", "check-cfg", "pass a --check-cfg to rustc", ""),
+        opt(Stable, Multi, "", "extern", "pass an --extern to rustc", "NAME[=PATH]"),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "extern-html-root-url",
+            "base URL to use for dependencies; for example, \
+                \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
+            "NAME=URL",
+        ),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "extern-html-root-takes-precedence",
+            "give precedence to `--extern-html-root-url`, not `html_root_url`",
+            "",
+        ),
+        opt(Stable, Multi, "C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]"),
+        opt(Stable, FlagMulti, "", "document-private-items", "document private items", ""),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "document-hidden-items",
+            "document items that have doc(hidden)",
+            "",
+        ),
+        opt(Stable, FlagMulti, "", "test", "run code examples as tests", ""),
+        opt(Stable, Multi, "", "test-args", "arguments to pass to the test runner", "ARGS"),
+        opt(
+            Stable,
+            Opt,
+            "",
+            "test-run-directory",
+            "The working directory in which to run tests",
+            "PATH",
+        ),
+        opt(Stable, Opt, "", "target", "target triple to document", "TRIPLE"),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "markdown-css",
+            "CSS files to include via <link> in a rendered Markdown file",
+            "FILES",
+        ),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "html-in-header",
+            "files to include inline in the <head> section of a rendered Markdown file \
+                or generated documentation",
+            "FILES",
+        ),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "html-before-content",
+            "files to include inline between <body> and the content of a rendered \
+                Markdown file or generated documentation",
+            "FILES",
+        ),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "html-after-content",
+            "files to include inline between the content and </body> of a rendered \
+                Markdown file or generated documentation",
+            "FILES",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "markdown-before-content",
+            "files to include inline between <body> and the content of a rendered \
+                Markdown file or generated documentation",
+            "FILES",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "markdown-after-content",
+            "files to include inline between the content and </body> of a rendered \
+                Markdown file or generated documentation",
+            "FILES",
+        ),
+        opt(Stable, Opt, "", "markdown-playground-url", "URL to send code snippets to", "URL"),
+        opt(Stable, FlagMulti, "", "markdown-no-toc", "don't include table of contents", ""),
+        opt(
+            Stable,
+            Opt,
+            "e",
+            "extend-css",
+            "To add some CSS rules with a given file to generate doc with your own theme. \
+                However, your theme might break if the rustdoc's generated HTML changes, so be careful!",
+            "PATH",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "Z",
+            "",
+            "unstable / perma-unstable options (only on nightly build)",
+            "FLAG",
+        ),
+        opt(Stable, Opt, "", "sysroot", "Override the system root", "PATH"),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "playground-url",
+            "URL to send code snippets to, may be reset by --markdown-playground-url \
+                or `#![doc(html_playground_url=...)]`",
+            "URL",
+        ),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "display-doctest-warnings",
+            "show warnings that originate in doctests",
+            "",
+        ),
+        opt(
+            Stable,
+            Opt,
+            "",
+            "crate-version",
+            "crate version to print into documentation",
+            "VERSION",
+        ),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "sort-modules-by-appearance",
+            "sort modules by where they appear in the program, rather than alphabetically",
+            "",
+        ),
+        opt(
+            Stable,
+            Opt,
+            "",
+            "default-theme",
+            "Set the default theme. THEME should be the theme name, generally lowercase. \
+                If an unknown default theme is specified, the builtin default is used. \
+                The set of themes, and the rustdoc built-in default, are not stable.",
+            "THEME",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "default-setting",
+            "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
+                from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
+                Supported SETTINGs and VALUEs are not documented and not stable.",
+            "SETTING[=VALUE]",
+        ),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "theme",
+            "additional themes which will be added to the generated docs",
+            "FILES",
+        ),
+        opt(Stable, Multi, "", "check-theme", "check if given theme is valid", "FILES"),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "resource-suffix",
+            "suffix to add to CSS and JavaScript files, \
+                e.g., \"search-index.js\" will become \"search-index-suffix.js\"",
+            "PATH",
+        ),
+        opt(
+            Stable,
+            Opt,
+            "",
+            "edition",
+            "edition to use when compiling rust code (default: 2015)",
+            "EDITION",
+        ),
+        opt(
+            Stable,
+            Opt,
+            "",
+            "color",
+            "Configure coloring of output:
                                           auto   = colorize, if output goes to a tty (default);
                                           always = always colorize output;
                                           never  = never colorize output",
-                "auto|always|never",
-            )
-        }),
-        stable("error-format", |o| {
-            o.optopt(
-                "",
-                "error-format",
-                "How errors and other messages are produced",
-                "human|json|short",
-            )
-        }),
-        stable("diagnostic-width", |o| {
-            o.optopt(
-                "",
-                "diagnostic-width",
-                "Provide width of the output for truncated error messages",
-                "WIDTH",
-            )
-        }),
-        stable("json", |o| {
-            o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
-        }),
-        stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "LINT")),
-        stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "LINT")),
-        stable("force-warn", |o| o.optmulti("", "force-warn", "Set lint force-warn", "LINT")),
-        stable("deny", |o| o.optmulti("D", "deny", "Set lint denied", "LINT")),
-        stable("forbid", |o| o.optmulti("F", "forbid", "Set lint forbidden", "LINT")),
-        stable("cap-lints", |o| {
-            o.optmulti(
-                "",
-                "cap-lints",
-                "Set the most restrictive lint level. \
-                 More restrictive lints are capped at this \
-                 level. By default, it is at `forbid` level.",
-                "LEVEL",
-            )
-        }),
-        unstable("index-page", |o| {
-            o.optopt("", "index-page", "Markdown file to be used as index page", "PATH")
-        }),
-        unstable("enable-index-page", |o| {
-            o.optflagmulti("", "enable-index-page", "To enable generation of the index page")
-        }),
-        unstable("static-root-path", |o| {
-            o.optopt(
-                "",
-                "static-root-path",
-                "Path string to force loading static files from in output pages. \
-                 If not set, uses combinations of '../' to reach the documentation root.",
-                "PATH",
-            )
-        }),
-        unstable("persist-doctests", |o| {
-            o.optopt(
-                "",
-                "persist-doctests",
-                "Directory to persist doctest executables into",
-                "PATH",
-            )
-        }),
-        unstable("show-coverage", |o| {
-            o.optflagmulti(
-                "",
-                "show-coverage",
-                "calculate percentage of public items with documentation",
-            )
-        }),
-        unstable("enable-per-target-ignores", |o| {
-            o.optflagmulti(
-                "",
-                "enable-per-target-ignores",
-                "parse ignore-foo for ignoring doctests on a per-target basis",
-            )
-        }),
-        unstable("runtool", |o| {
-            o.optopt(
-                "",
-                "runtool",
-                "",
-                "The tool to run tests with when building for a different target than host",
-            )
-        }),
-        unstable("runtool-arg", |o| {
-            o.optmulti(
-                "",
-                "runtool-arg",
-                "",
-                "One (of possibly many) arguments to pass to the runtool",
-            )
-        }),
-        unstable("test-builder", |o| {
-            o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH")
-        }),
-        unstable("test-builder-wrapper", |o| {
-            o.optmulti(
-                "",
-                "test-builder-wrapper",
-                "Wrapper program to pass test-builder and arguments",
-                "PATH",
-            )
-        }),
-        unstable("check", |o| o.optflagmulti("", "check", "Run rustdoc checks")),
-        unstable("generate-redirect-map", |o| {
-            o.optflagmulti(
-                "",
-                "generate-redirect-map",
-                "Generate JSON file at the top level instead of generating HTML redirection files",
-            )
-        }),
-        unstable("emit", |o| {
-            o.optmulti(
-                "",
-                "emit",
-                "Comma separated list of types of output for rustdoc to emit",
-                "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
-            )
-        }),
-        unstable("no-run", |o| {
-            o.optflagmulti("", "no-run", "Compile doctests without running them")
-        }),
-        unstable("remap-path-prefix", |o| {
-            o.optmulti(
-                "",
-                "remap-path-prefix",
-                "Remap source names in compiler messages",
-                "FROM=TO",
-            )
-        }),
-        unstable("show-type-layout", |o| {
-            o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs")
-        }),
-        unstable("nocapture", |o| {
-            o.optflag("", "nocapture", "Don't capture stdout and stderr of tests")
-        }),
-        unstable("generate-link-to-definition", |o| {
-            o.optflag(
-                "",
-                "generate-link-to-definition",
-                "Make the identifiers in the HTML source code pages navigable",
-            )
-        }),
-        unstable("scrape-examples-output-path", |o| {
-            o.optopt(
-                "",
-                "scrape-examples-output-path",
-                "",
-                "collect function call information and output at the given path",
-            )
-        }),
-        unstable("scrape-examples-target-crate", |o| {
-            o.optmulti(
-                "",
-                "scrape-examples-target-crate",
-                "",
-                "collect function call information for functions from the target crate",
-            )
-        }),
-        unstable("scrape-tests", |o| {
-            o.optflag("", "scrape-tests", "Include test code when scraping examples")
-        }),
-        unstable("with-examples", |o| {
-            o.optmulti(
-                "",
-                "with-examples",
-                "",
-                "path to function call information (for displaying examples in the documentation)",
-            )
-        }),
-        unstable("merge", |o| {
-            o.optopt(
-                "",
-                "merge",
-                "Controls how rustdoc handles files from previously documented crates in the doc root
-                      none = Do not write cross-crate information to the --out-dir
-                      shared = Append current crate's info to files found in the --out-dir
-                      finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
-                "none|shared|finalize",
-            )
-        }),
-        unstable("parts-out-dir", |o| {
-            o.optopt(
-                "",
-                "parts-out-dir",
-                "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
-                "path/to/doc.parts/<crate-name>",
-            )
-        }),
-        unstable("include-parts-dir", |o| {
-            o.optmulti(
-                "",
-                "include-parts-dir",
-                "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
-                "path/to/doc.parts/<crate-name>",
-            )
-        }),
+            "auto|always|never",
+        ),
+        opt(
+            Stable,
+            Opt,
+            "",
+            "error-format",
+            "How errors and other messages are produced",
+            "human|json|short",
+        ),
+        opt(
+            Stable,
+            Opt,
+            "",
+            "diagnostic-width",
+            "Provide width of the output for truncated error messages",
+            "WIDTH",
+        ),
+        opt(Stable, Opt, "", "json", "Configure the structure of JSON diagnostics", "CONFIG"),
+        opt(Stable, Multi, "A", "allow", "Set lint allowed", "LINT"),
+        opt(Stable, Multi, "W", "warn", "Set lint warnings", "LINT"),
+        opt(Stable, Multi, "", "force-warn", "Set lint force-warn", "LINT"),
+        opt(Stable, Multi, "D", "deny", "Set lint denied", "LINT"),
+        opt(Stable, Multi, "F", "forbid", "Set lint forbidden", "LINT"),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "cap-lints",
+            "Set the most restrictive lint level. \
+                More restrictive lints are capped at this level. \
+                By default, it is at `forbid` level.",
+            "LEVEL",
+        ),
+        opt(Unstable, Opt, "", "index-page", "Markdown file to be used as index page", "PATH"),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "enable-index-page",
+            "To enable generation of the index page",
+            "",
+        ),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "static-root-path",
+            "Path string to force loading static files from in output pages. \
+                If not set, uses combinations of '../' to reach the documentation root.",
+            "PATH",
+        ),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "persist-doctests",
+            "Directory to persist doctest executables into",
+            "PATH",
+        ),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "show-coverage",
+            "calculate percentage of public items with documentation",
+            "",
+        ),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "enable-per-target-ignores",
+            "parse ignore-foo for ignoring doctests on a per-target basis",
+            "",
+        ),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "runtool",
+            "",
+            "The tool to run tests with when building for a different target than host",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "runtool-arg",
+            "",
+            "One (of possibly many) arguments to pass to the runtool",
+        ),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "test-builder",
+            "The rustc-like binary to use as the test builder",
+            "PATH",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "test-builder-wrapper",
+            "Wrapper program to pass test-builder and arguments",
+            "PATH",
+        ),
+        opt(Unstable, FlagMulti, "", "check", "Run rustdoc checks", ""),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "generate-redirect-map",
+            "Generate JSON file at the top level instead of generating HTML redirection files",
+            "",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "emit",
+            "Comma separated list of types of output for rustdoc to emit",
+            "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]",
+        ),
+        opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "remap-path-prefix",
+            "Remap source names in compiler messages",
+            "FROM=TO",
+        ),
+        opt(
+            Unstable,
+            FlagMulti,
+            "",
+            "show-type-layout",
+            "Include the memory layout of types in the docs",
+            "",
+        ),
+        opt(Unstable, Flag, "", "nocapture", "Don't capture stdout and stderr of tests", ""),
+        opt(
+            Unstable,
+            Flag,
+            "",
+            "generate-link-to-definition",
+            "Make the identifiers in the HTML source code pages navigable",
+            "",
+        ),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "scrape-examples-output-path",
+            "",
+            "collect function call information and output at the given path",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "scrape-examples-target-crate",
+            "",
+            "collect function call information for functions from the target crate",
+        ),
+        opt(Unstable, Flag, "", "scrape-tests", "Include test code when scraping examples", ""),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "with-examples",
+            "",
+            "path to function call information (for displaying examples in the documentation)",
+        ),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "merge",
+            "Controls how rustdoc handles files from previously documented crates in the doc root\n\
+                none = Do not write cross-crate information to the --out-dir\n\
+                shared = Append current crate's info to files found in the --out-dir\n\
+                finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
+            "none|shared|finalize",
+        ),
+        opt(
+            Unstable,
+            Opt,
+            "",
+            "parts-out-dir",
+            "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
+            "path/to/doc.parts/<crate-name>",
+        ),
+        opt(
+            Unstable,
+            Multi,
+            "",
+            "include-parts-dir",
+            "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
+            "path/to/doc.parts/<crate-name>",
+        ),
         // deprecated / removed options
-        unstable("disable-minification", |o| o.optflagmulti("", "disable-minification", "removed")),
-        stable("plugin-path", |o| {
-            o.optmulti(
-                "",
-                "plugin-path",
-                "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
-                for more information",
-                "DIR",
-            )
-        }),
-        stable("passes", |o| {
-            o.optmulti(
-                "",
-                "passes",
-                "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
-                for more information",
-                "PASSES",
-            )
-        }),
-        stable("plugins", |o| {
-            o.optmulti(
-                "",
-                "plugins",
-                "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
-                for more information",
-                "PLUGINS",
-            )
-        }),
-        stable("no-default", |o| {
-            o.optflagmulti(
-                "",
-                "no-defaults",
-                "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
-                for more information",
-            )
-        }),
-        stable("r", |o| {
-            o.optopt(
-                "r",
-                "input-format",
-                "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
-                for more information",
-                "[rust]",
-            )
-        }),
-        unstable("html-no-source", |o| {
-            o.optflag("", "html-no-source", "Disable HTML source code pages generation")
-        }),
+        opt(Unstable, FlagMulti, "", "disable-minification", "removed", ""),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "plugin-path",
+            "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
+            "DIR",
+        ),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "passes",
+            "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
+            "PASSES",
+        ),
+        opt(
+            Stable,
+            Multi,
+            "",
+            "plugins",
+            "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
+            "PLUGINS",
+        ),
+        opt(
+            Stable,
+            FlagMulti,
+            "",
+            "no-defaults",
+            "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
+            "",
+        ),
+        opt(
+            Stable,
+            Opt,
+            "r",
+            "input-format",
+            "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
+            "[rust]",
+        ),
+        opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
     ]
 }
 
 fn usage(argv0: &str) {
     let mut options = getopts::Options::new();
     for option in opts() {
-        (option.apply)(&mut options);
+        option.apply(&mut options);
     }
     println!("{}", options.usage(&format!("{argv0} [options] <input>")));
     println!("    @path               Read newline separated options from `path`\n");
@@ -769,7 +774,7 @@ fn main_args(
 
     let mut options = getopts::Options::new();
     for option in opts() {
-        (option.apply)(&mut options);
+        option.apply(&mut options);
     }
     let matches = match options.parse(&args) {
         Ok(m) => m,
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 0310497822a7a673a330a5dd068b7aaa579a265
+Subproject 4a2d8dc636445b276288543882e076f254b3ae9
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index f1b7811f905..fe7d8db245b 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -134,7 +134,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // entered for addresses that are not the base address, so even zero-sized
                 // allocations will get recognized at their base address -- but all other
                 // allocations will *not* be recognized at their "end" address.
-                let size = this.get_alloc_info(alloc_id).0;
+                let size = this.get_alloc_info(alloc_id).size;
                 if offset < size.bytes() { Some(alloc_id) } else { None }
             }
         }?;
@@ -157,25 +157,25 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, u64> {
         let this = self.eval_context_ref();
         let mut rng = this.machine.rng.borrow_mut();
-        let (size, align, kind) = this.get_alloc_info(alloc_id);
+        let info = this.get_alloc_info(alloc_id);
         // This is either called immediately after allocation (and then cached), or when
         // adjusting `tcx` pointers (which never get freed). So assert that we are looking
         // at a live allocation. This also ensures that we never re-assign an address to an
         // allocation that previously had an address, but then was freed and the address
         // information was removed.
-        assert!(!matches!(kind, AllocKind::Dead));
+        assert!(!matches!(info.kind, AllocKind::Dead));
 
         // This allocation does not have a base address yet, pick or reuse one.
         if this.machine.native_lib.is_some() {
             // In native lib mode, we use the "real" address of the bytes for this allocation.
             // This ensures the interpreted program and native code have the same view of memory.
-            let base_ptr = match kind {
+            let base_ptr = match info.kind {
                 AllocKind::LiveData => {
                     if this.tcx.try_get_global_alloc(alloc_id).is_some() {
                         // For new global allocations, we always pre-allocate the memory to be able use the machine address directly.
-                        let prepared_bytes = MiriAllocBytes::zeroed(size, align)
+                        let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align)
                             .unwrap_or_else(|| {
-                                panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes")
+                                panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes", size = info.size)
                             });
                         let ptr = prepared_bytes.as_ptr();
                         // Store prepared allocation space to be picked up for use later.
@@ -203,9 +203,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return interp_ok(base_ptr.expose_provenance().try_into().unwrap());
         }
         // We are not in native lib mode, so we control the addresses ourselves.
-        if let Some((reuse_addr, clock)) =
-            global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, this.active_thread())
-        {
+        if let Some((reuse_addr, clock)) = global_state.reuse.take_addr(
+            &mut *rng,
+            info.size,
+            info.align,
+            memory_kind,
+            this.active_thread(),
+        ) {
             if let Some(clock) = clock {
                 this.acquire_clock(&clock);
             }
@@ -220,14 +224,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 .next_base_addr
                 .checked_add(slack)
                 .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
-            let base_addr = align_addr(base_addr, align.bytes());
+            let base_addr = align_addr(base_addr, info.align.bytes());
 
             // Remember next base address.  If this allocation is zero-sized, leave a gap of at
             // least 1 to avoid two allocations having the same base address. (The logic in
             // `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers
             // need to be distinguishable!)
             global_state.next_base_addr = base_addr
-                .checked_add(max(size.bytes(), 1))
+                .checked_add(max(info.size.bytes(), 1))
                 .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
             // Even if `Size` didn't overflow, we might still have filled up the address space.
             if global_state.next_base_addr > this.target_usize_max() {
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index 72319decb94..4883613dea5 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -363,7 +363,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // If it does exist, then we have the guarantee that the
             // pointer is readable, and the implicit read access inserted
             // will never cause UB on the pointer itself.
-            let (_, _, kind) = this.get_alloc_info(*alloc_id);
+            let kind = this.get_alloc_info(*alloc_id).kind;
             if matches!(kind, AllocKind::LiveData) {
                 let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static`
                 let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 47fe41d9ecd..16fcc26be33 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -626,7 +626,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
                 return interp_ok(())
             };
 
-            let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
+            let alloc_kind = this.get_alloc_info(alloc_id).kind;
             match alloc_kind {
                 AllocKind::LiveData => {
                     // This should have alloc_extra data, but `get_alloc_extra` can still fail
@@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Function pointers and dead objects don't have an alloc_extra so we ignore them.
         // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks.
         // NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
-        let (_size, _align, kind) = this.get_alloc_info(alloc_id);
+        let kind = this.get_alloc_info(alloc_id).kind;
         match kind {
             AllocKind::LiveData => {
                 // This should have alloc_extra data, but `get_alloc_extra` can still fail
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 40467aa4bc1..f92150758dc 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -274,7 +274,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 .insert(new_tag, protect);
         }
 
-        let alloc_kind = this.get_alloc_info(alloc_id).2;
+        let alloc_kind = this.get_alloc_info(alloc_id).kind;
         if !matches!(alloc_kind, AllocKind::LiveData) {
             assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
             // There's not actually any bytes here where accesses could even be tracked.
@@ -538,7 +538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Function pointers and dead objects don't have an alloc_extra so we ignore them.
         // This is okay because accessing them is UB anyway, no need for any Tree Borrows checks.
         // NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
-        let (_size, _align, kind) = this.get_alloc_info(alloc_id);
+        let kind = this.get_alloc_info(alloc_id).kind;
         match kind {
             AllocKind::LiveData => {
                 // This should have alloc_extra data, but `get_alloc_extra` can still fail
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 72e8952c543..9668998aaa3 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1125,10 +1125,10 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             let Provenance::Concrete { alloc_id, .. } = ptr.provenance else {
                 panic!("extern_statics cannot contain wildcards")
             };
-            let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id);
+            let info = ecx.get_alloc_info(alloc_id);
             let def_ty = ecx.tcx.type_of(def_id).instantiate_identity();
             let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap();
-            if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align {
+            if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align {
                 throw_unsup_format!(
                     "extern static `{link_name}` has been declared as `{krate}::{name}` \
                     with a size of {decl_size} bytes and alignment of {decl_align} bytes, \
@@ -1138,8 +1138,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
                     krate = ecx.tcx.crate_name(def_id.krate),
                     decl_size = extern_decl_layout.size.bytes(),
                     decl_align = extern_decl_layout.align.abi.bytes(),
-                    shim_size = shim_size.bytes(),
-                    shim_align = shim_align.bytes(),
+                    shim_size = info.size.bytes(),
+                    shim_align = info.align.bytes(),
                 )
             }
             interp_ok(ptr)
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 8f7c56a2907..b74491a2f8e 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -300,7 +300,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let id = this.read_scalar(id)?.to_u64()?;
                 let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
                 if let Some(id) = std::num::NonZero::new(id).map(AllocId)
-                    && this.get_alloc_info(id).2 == AllocKind::LiveData
+                    && this.get_alloc_info(id).kind == AllocKind::LiveData
                 {
                     this.print_borrow_state(id, show_unnamed)?;
                 } else {
@@ -409,7 +409,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
                 if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr, 0) {
-                    let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id);
+                    let alloc_align = this.get_alloc_info(alloc_id).align;
                     // If the newly promised alignment is bigger than the native alignment of this
                     // allocation, and bigger than the previously promised alignment, then set it.
                     if align > alloc_align
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 368b98c9f0d..5765cb97a7e 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -41,6 +41,7 @@ pub use libc;
 pub use object;
 pub use regex;
 pub use serde_json;
+pub use similar;
 pub use wasmparser;
 // tidy-alphabetical-end
 
diff --git a/tests/assembly/asm/s390x-types.rs b/tests/assembly/asm/s390x-types.rs
index e68b18d7aa6..b1522198a08 100644
--- a/tests/assembly/asm/s390x-types.rs
+++ b/tests/assembly/asm/s390x-types.rs
@@ -4,7 +4,7 @@
 //@[s390x] needs-llvm-components: systemz
 //@ compile-flags: -Zmerge-functions=disabled
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
diff --git a/tests/codegen/asm/s390x-clobbers.rs b/tests/codegen/asm/s390x-clobbers.rs
index 45f72206bdf..56d82b4b044 100644
--- a/tests/codegen/asm/s390x-clobbers.rs
+++ b/tests/codegen/asm/s390x-clobbers.rs
@@ -3,7 +3,7 @@
 //@[s390x] needs-llvm-components: systemz
 
 #![crate_type = "rlib"]
-#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
+#![feature(no_core, rustc_attrs, lang_items)]
 #![no_core]
 
 #[lang = "sized"]
diff --git a/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs b/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs
new file mode 100644
index 00000000000..159ecfd0974
--- /dev/null
+++ b/tests/codegen/debuginfo-proc-macro/auxiliary/macro_def.rs
@@ -0,0 +1,11 @@
+//@ force-host
+//@ no-prefer-dynamic
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn square_twice(_item: TokenStream) -> TokenStream {
+    "(square(env::vars().count() as i32), square(env::vars().count() as i32))".parse().unwrap()
+}
diff --git a/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs b/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs
new file mode 100644
index 00000000000..c3858044c0c
--- /dev/null
+++ b/tests/codegen/debuginfo-proc-macro/mir_inlined_twice_var_locs.rs
@@ -0,0 +1,53 @@
+//@ min-llvm-version: 19
+//@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Zmir-enable-passes=+Inline
+// MSVC is different because of the individual allocas.
+//@ ignore-msvc
+
+//@ aux-build:macro_def.rs
+
+// Find the variable.
+// CHECK-DAG: ![[#var_dbg:]] = !DILocalVariable(name: "n",{{( arg: 1,)?}} scope: ![[#var_scope:]]
+
+// Find both dbg_declares. These will proceed the variable metadata, of course, so we're looking
+// backwards.
+// CHECK-DAG: dbg_declare(ptr %n.dbg.spill{{[0-9]}}, ![[#var_dbg]], !DIExpression(), ![[#var_loc2:]])
+// CHECK-DAG: dbg_declare(ptr %n.dbg.spill, ![[#var_dbg]], !DIExpression(), ![[#var_loc1:]])
+
+// Find the first location definition, looking forwards again.
+// CHECK: ![[#var_loc1]] = !DILocation
+// CHECK-SAME: scope: ![[#var_scope:]], inlinedAt: ![[#var_inlinedAt1:]]
+
+// Find the first location's inlinedAt
+// NB: If we fail here it's *probably* because we failed to produce two
+// different locations and ended up reusing an earlier one.
+// CHECK: ![[#var_inlinedAt1]] = !DILocation
+// CHECK-SAME: scope: ![[var_inlinedAt1_scope:]]
+
+// Find the second location definition, still looking forwards.
+// NB: If we failed to produce two different locations, the test will
+// definitely fail by this point (if it hasn't already) because we won't
+// be able to find the same line again.
+// CHECK: ![[#var_loc2]] = !DILocation
+// CHECK-SAME: scope: ![[#var_scope]], inlinedAt: ![[#var_inlinedAt2:]]
+
+// Find the second location's inlinedAt.
+// CHECK: ![[#var_inlinedAt2]] = !DILocation
+// CHECK-SAME: scope: ![[#var_inlinedAt2_scope:]]
+
+// Finally, check that a discriminator was emitted for the second scope.
+// FIXMEkhuey ideally we would check that *either* scope has a discriminator
+// but I don't know that it's possible to check that with FileCheck.
+// CHECK: ![[#var_inlinedAt2_scope]] = !DILexicalBlockFile
+// CHECK-SAME: discriminator: [[#]]
+extern crate macro_def;
+
+use std::env;
+
+fn square(n: i32) -> i32 {
+    n * n
+}
+
+fn main() {
+    let (z1, z2) = macro_def::square_twice!();
+    println!("{z1} == {z2}");
+}
diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs
index 7fa1d659885..503799d3ed2 100644
--- a/tests/codegen/function-arguments.rs
+++ b/tests/codegen/function-arguments.rs
@@ -1,5 +1,6 @@
 //@ compile-flags: -O -C no-prepopulate-passes
 #![crate_type = "lib"]
+#![feature(rustc_attrs)]
 #![feature(dyn_star)]
 #![feature(allocator_api)]
 
@@ -143,13 +144,28 @@ pub fn indirect_struct(_: S) {}
 #[no_mangle]
 pub fn borrowed_struct(_: &S) {}
 
-// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %x)
+// CHECK: @option_borrow(ptr noalias noundef readonly align 4 dereferenceable_or_null(4) %_x)
 #[no_mangle]
-pub fn option_borrow(x: Option<&i32>) {}
+pub fn option_borrow(_x: Option<&i32>) {}
 
-// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %x)
+// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x)
 #[no_mangle]
-pub fn option_borrow_mut(x: Option<&mut i32>) {}
+pub fn option_borrow_mut(_x: Option<&mut i32>) {}
+
+// Function that must NOT have `dereferenceable` or `align`.
+#[rustc_layout_scalar_valid_range_start(16)]
+pub struct RestrictedAddress(&'static i16);
+enum E {
+    A(RestrictedAddress),
+    B,
+    C,
+}
+// If the `nonnull` ever goes missing, you might have to tweak the
+// scalar_valid_range on `RestrictedAddress` to get it back. You
+// might even have to add a `rustc_layout_scalar_valid_range_end`.
+// CHECK: @nonnull_and_nondereferenceable(ptr noundef nonnull %_x)
+#[no_mangle]
+pub fn nonnull_and_nondereferenceable(_x: E) {}
 
 // CHECK: @raw_struct(ptr noundef %_1)
 #[no_mangle]
diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs
index bbab0d9eb1d..b68ecce869e 100644
--- a/tests/codegen/try_question_mark_nop.rs
+++ b/tests/codegen/try_question_mark_nop.rs
@@ -1,6 +1,10 @@
 //@ compile-flags: -O -Z merge-functions=disabled --edition=2021
 //@ only-x86_64
 // FIXME: Remove the `min-llvm-version`.
+//@ revisions: NINETEEN TWENTY
+//@[NINETEEN] min-llvm-version: 19
+//@[NINETEEN] ignore-llvm-version: 20-99
+//@[TWENTY] min-llvm-version: 20
 //@ min-llvm-version: 19
 
 #![crate_type = "lib"]
@@ -13,8 +17,11 @@ use std::ptr::NonNull;
 #[no_mangle]
 pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
     // CHECK: start:
+    // TWENTY-NEXT: %trunc = trunc nuw i32 %0 to i1
+    // TWENTY-NEXT: %.2 = select i1 %trunc, i32 %1, i32 undef
     // CHECK-NEXT: [[REG1:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
-    // CHECK-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1
+    // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1
+    // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %.2, 1
     // CHECK-NEXT: ret { i32, i32 } [[REG2]]
     match x {
         Some(x) => Some(x),
@@ -26,6 +33,8 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
 #[no_mangle]
 pub fn option_nop_traits_32(x: Option<u32>) -> Option<u32> {
     // CHECK: start:
+    // TWENTY-NEXT: %trunc = trunc nuw i32 %0 to i1
+    // TWENTY-NEXT: %.1 = select i1 %trunc, i32 %1, i32 undef
     // CHECK-NEXT: insertvalue { i32, i32 }
     // CHECK-NEXT: insertvalue { i32, i32 }
     // CHECK-NEXT: ret { i32, i32 }
diff --git a/tests/run-make/rustc-help/help-v.diff b/tests/run-make/rustc-help/help-v.diff
new file mode 100644
index 00000000000..22c5dd81bdb
--- /dev/null
+++ b/tests/run-make/rustc-help/help-v.diff
@@ -0,0 +1,29 @@
+@@ -51,10 +51,27 @@
+                         Set a codegen option
+     -V, --version       Print version info and exit
+     -v, --verbose       Use verbose output
++        --extern NAME[=PATH]
++                        Specify where an external rust library is located
++        --sysroot PATH  Override the system root
++        --error-format human|json|short
++                        How errors and other messages are produced
++        --json CONFIG   Configure the JSON output of the compiler
++        --color auto|always|never
++                        Configure coloring of output:
++                        auto = colorize, if output goes to a tty (default);
++                        always = always colorize output;
++                        never = never colorize output
++        --diagnostic-width WIDTH
++                        Inform rustc of the width of the output so that
++                        diagnostics can be truncated to fit
++        --remap-path-prefix FROM=TO
++                        Remap source names in all output (compiler messages
++                        and output files)
++    @path               Read newline separated options from `path`
+ 
+ Additional help:
+     -C help             Print codegen options
+     -W help             Print 'lint' options and default settings
+     -Z help             Print unstable compiler options
+-    --help -v           Print the full set of options rustc accepts
+ 
diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout
new file mode 100644
index 00000000000..dbd67b57df2
--- /dev/null
+++ b/tests/run-make/rustc-help/help-v.stdout
@@ -0,0 +1,77 @@
+Usage: rustc [OPTIONS] INPUT
+
+Options:
+    -h, --help          Display this message
+        --cfg SPEC      Configure the compilation environment.
+                        SPEC supports the syntax `NAME[="VALUE"]`.
+        --check-cfg SPEC
+                        Provide list of expected cfgs for checking
+    -L [KIND=]PATH      Add a directory to the library search path. The
+                        optional KIND can be one of dependency, crate, native,
+                        framework, or all (the default).
+    -l [KIND[:MODIFIERS]=]NAME[:RENAME]
+                        Link the generated crate(s) to the specified native
+                        library NAME. The optional KIND can be one of
+                        static, framework, or dylib (the default).
+                        Optional comma separated MODIFIERS
+                        (bundle|verbatim|whole-archive|as-needed)
+                        may be specified each with a prefix of either '+' to
+                        enable or '-' to disable.
+        --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]
+                        Comma separated list of types of crates
+                        for the compiler to emit
+        --crate-name NAME
+                        Specify the name of the crate being built
+        --edition 2015|2018|2021|2024
+                        Specify which edition of the compiler to use when
+                        compiling code. The default is 2015 and the latest
+                        stable edition is 2021.
+        --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
+                        Comma separated list of types of output for the
+                        compiler to emit
+        --print [crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|all-target-specs-json|native-static-libs|stack-protector-strategies|link-args|deployment-target]
+                        Compiler information to print on stdout
+    -g                  Equivalent to -C debuginfo=2
+    -O                  Equivalent to -C opt-level=2
+    -o FILENAME         Write output to <filename>
+        --out-dir DIR   Write output to compiler-chosen filename in <dir>
+        --explain OPT   Provide a detailed explanation of an error message
+        --test          Build a test harness
+        --target TARGET Target triple for which the code is compiled
+    -A, --allow LINT    Set lint allowed
+    -W, --warn LINT     Set lint warnings
+        --force-warn LINT
+                        Set lint force-warn
+    -D, --deny LINT     Set lint denied
+    -F, --forbid LINT   Set lint forbidden
+        --cap-lints LEVEL
+                        Set the most restrictive lint level. More restrictive
+                        lints are capped at this level
+    -C, --codegen OPT[=VALUE]
+                        Set a codegen option
+    -V, --version       Print version info and exit
+    -v, --verbose       Use verbose output
+        --extern NAME[=PATH]
+                        Specify where an external rust library is located
+        --sysroot PATH  Override the system root
+        --error-format human|json|short
+                        How errors and other messages are produced
+        --json CONFIG   Configure the JSON output of the compiler
+        --color auto|always|never
+                        Configure coloring of output:
+                        auto = colorize, if output goes to a tty (default);
+                        always = always colorize output;
+                        never = never colorize output
+        --diagnostic-width WIDTH
+                        Inform rustc of the width of the output so that
+                        diagnostics can be truncated to fit
+        --remap-path-prefix FROM=TO
+                        Remap source names in all output (compiler messages
+                        and output files)
+    @path               Read newline separated options from `path`
+
+Additional help:
+    -C help             Print codegen options
+    -W help             Print 'lint' options and default settings
+    -Z help             Print unstable compiler options
+
diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout
new file mode 100644
index 00000000000..a7d07162799
--- /dev/null
+++ b/tests/run-make/rustc-help/help.stdout
@@ -0,0 +1,60 @@
+Usage: rustc [OPTIONS] INPUT
+
+Options:
+    -h, --help          Display this message
+        --cfg SPEC      Configure the compilation environment.
+                        SPEC supports the syntax `NAME[="VALUE"]`.
+        --check-cfg SPEC
+                        Provide list of expected cfgs for checking
+    -L [KIND=]PATH      Add a directory to the library search path. The
+                        optional KIND can be one of dependency, crate, native,
+                        framework, or all (the default).
+    -l [KIND[:MODIFIERS]=]NAME[:RENAME]
+                        Link the generated crate(s) to the specified native
+                        library NAME. The optional KIND can be one of
+                        static, framework, or dylib (the default).
+                        Optional comma separated MODIFIERS
+                        (bundle|verbatim|whole-archive|as-needed)
+                        may be specified each with a prefix of either '+' to
+                        enable or '-' to disable.
+        --crate-type [bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]
+                        Comma separated list of types of crates
+                        for the compiler to emit
+        --crate-name NAME
+                        Specify the name of the crate being built
+        --edition 2015|2018|2021|2024
+                        Specify which edition of the compiler to use when
+                        compiling code. The default is 2015 and the latest
+                        stable edition is 2021.
+        --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
+                        Comma separated list of types of output for the
+                        compiler to emit
+        --print [crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|target-list|target-cpus|target-features|relocation-models|code-models|tls-models|target-spec-json|all-target-specs-json|native-static-libs|stack-protector-strategies|link-args|deployment-target]
+                        Compiler information to print on stdout
+    -g                  Equivalent to -C debuginfo=2
+    -O                  Equivalent to -C opt-level=2
+    -o FILENAME         Write output to <filename>
+        --out-dir DIR   Write output to compiler-chosen filename in <dir>
+        --explain OPT   Provide a detailed explanation of an error message
+        --test          Build a test harness
+        --target TARGET Target triple for which the code is compiled
+    -A, --allow LINT    Set lint allowed
+    -W, --warn LINT     Set lint warnings
+        --force-warn LINT
+                        Set lint force-warn
+    -D, --deny LINT     Set lint denied
+    -F, --forbid LINT   Set lint forbidden
+        --cap-lints LEVEL
+                        Set the most restrictive lint level. More restrictive
+                        lints are capped at this level
+    -C, --codegen OPT[=VALUE]
+                        Set a codegen option
+    -V, --version       Print version info and exit
+    -v, --verbose       Use verbose output
+
+Additional help:
+    -C help             Print codegen options
+    -W help             Print 'lint' options and default settings
+    -Z help             Print unstable compiler options
+    --help -v           Print the full set of options rustc accepts
+
diff --git a/tests/run-make/rustc-help/rmake.rs b/tests/run-make/rustc-help/rmake.rs
new file mode 100644
index 00000000000..85e90e6352d
--- /dev/null
+++ b/tests/run-make/rustc-help/rmake.rs
@@ -0,0 +1,21 @@
+// Tests `rustc --help` and similar invocations against snapshots and each other.
+
+use run_make_support::{bare_rustc, diff, similar};
+
+fn main() {
+    // `rustc --help`
+    let help = bare_rustc().arg("--help").run().stdout_utf8();
+    diff().expected_file("help.stdout").actual_text("(rustc --help)", &help).run();
+
+    // `rustc` should be the same as `rustc --help`
+    let bare = bare_rustc().run().stdout_utf8();
+    diff().expected_text("(rustc --help)", &help).actual_text("(rustc)", &bare).run();
+
+    // `rustc --help -v` should give a similar but longer help message
+    let help_v = bare_rustc().arg("--help").arg("-v").run().stdout_utf8();
+    diff().expected_file("help-v.stdout").actual_text("(rustc --help -v)", &help_v).run();
+
+    // Check the diff between `rustc --help` and `rustc --help -v`.
+    let help_v_diff = similar::TextDiff::from_lines(&help, &help_v).unified_diff().to_string();
+    diff().expected_file("help-v.diff").actual_text("actual", &help_v_diff).run();
+}
diff --git a/tests/rustdoc/hidden-implementors-90781.rs b/tests/rustdoc/hidden-implementors-90781.rs
new file mode 100644
index 00000000000..960a85b91f0
--- /dev/null
+++ b/tests/rustdoc/hidden-implementors-90781.rs
@@ -0,0 +1,78 @@
+//@ compile-flags: -Z unstable-options --document-hidden-items --document-private-items
+
+// regression test for https://github.com/rust-lang/rust/issues/90781
+#![crate_name = "foo"]
+
+//@ has foo/trait.TPubVis.html
+//@ has - '//*[@id="implementors-list"]' 'HidPriv'
+//@ has - '//*[@id="implementors-list"]' 'HidPub'
+//@ has - '//*[@id="implementors-list"]' 'VisPriv'
+//@ has - '//*[@id="implementors-list"]' 'VisPub'
+pub trait TPubVis {}
+
+//@ has foo/trait.TPubHidden.html
+//@ has - '//*[@id="implementors-list"]' 'HidPriv'
+//@ has - '//*[@id="implementors-list"]' 'HidPub'
+//@ has - '//*[@id="implementors-list"]' 'VisPriv'
+//@ has - '//*[@id="implementors-list"]' 'VisPub'
+#[doc(hidden)]
+pub trait TPubHidden {}
+
+//@ has foo/trait.TPrivVis.html
+//@ has - '//*[@id="implementors-list"]' 'HidPriv'
+//@ has - '//*[@id="implementors-list"]' 'HidPub'
+//@ has - '//*[@id="implementors-list"]' 'VisPriv'
+//@ has - '//*[@id="implementors-list"]' 'VisPub'
+trait TPrivVis {}
+
+#[doc(hidden)]
+//@ has foo/trait.TPrivHidden.html
+//@ has - '//*[@id="impl-TPrivHidden-for-HidPriv"]' 'HidPriv'
+//@ has - '//*[@id="impl-TPrivHidden-for-HidPub"]' 'HidPub'
+//@ has - '//*[@id="impl-TPrivHidden-for-VisPriv"]' 'VisPriv'
+//@ has - '//*[@id="impl-TPrivHidden-for-VisPub"]' 'VisPub'
+trait TPrivHidden {}
+
+//@ has foo/struct.VisPub.html
+//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis'
+pub struct VisPub;
+
+//@ has foo/struct.VisPriv.html
+//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis'
+struct VisPriv;
+
+//@ has foo/struct.HidPub.html
+//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis'
+#[doc(hidden)]
+pub struct HidPub;
+
+//@ has foo/struct.HidPriv.html
+//@ has - '//*[@id="trait-implementations-list"]' 'TPrivHidden'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPrivVis'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPubHidden'
+//@ has - '//*[@id="trait-implementations-list"]' 'TPubVis'
+#[doc(hidden)]
+struct HidPriv;
+
+macro_rules! implement {
+    ($trait:ident - $($struct:ident)+) => {
+        $(
+            impl $trait for $struct {}
+        )+
+    }
+}
+
+
+implement!(TPubVis - VisPub VisPriv HidPub HidPriv);
+implement!(TPubHidden - VisPub VisPriv HidPub HidPriv);
+implement!(TPrivVis - VisPub VisPriv HidPub HidPriv);
+implement!(TPrivHidden - VisPub VisPriv HidPub HidPriv);
diff --git a/tests/ui/abi/sparcv8plus.rs b/tests/ui/abi/sparcv8plus.rs
new file mode 100644
index 00000000000..108279b3494
--- /dev/null
+++ b/tests/ui/abi/sparcv8plus.rs
@@ -0,0 +1,43 @@
+//@ revisions: sparc sparcv8plus sparc_cpu_v9 sparc_feature_v8plus sparc_cpu_v9_feature_v8plus
+//@[sparc] compile-flags: --target sparc-unknown-none-elf
+//@[sparc] needs-llvm-components: sparc
+//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu
+//@[sparcv8plus] needs-llvm-components: sparc
+//@[sparc_cpu_v9] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9
+//@[sparc_cpu_v9] needs-llvm-components: sparc
+//@[sparc_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-feature=+v8plus
+//@[sparc_feature_v8plus] needs-llvm-components: sparc
+//@[sparc_cpu_v9_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -C target-feature=+v8plus
+//@[sparc_cpu_v9_feature_v8plus] needs-llvm-components: sparc
+//@ min-llvm-version: 19
+
+#![crate_type = "rlib"]
+#![feature(no_core, rustc_attrs, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[rustc_builtin_macro]
+macro_rules! compile_error {
+    () => {};
+}
+
+#[cfg(all(not(target_feature = "v8plus"), not(target_feature = "v9")))]
+compile_error!("-v8plus,-v9");
+//[sparc]~^ ERROR -v8plus,-v9
+
+// FIXME: sparc_cpu_v9 should be in "-v8plus,+v9" group (fixed in LLVM 20)
+#[cfg(all(target_feature = "v8plus", target_feature = "v9"))]
+compile_error!("+v8plus,+v9");
+//[sparcv8plus,sparc_cpu_v9_feature_v8plus,sparc_cpu_v9]~^ ERROR +v8plus,+v9
+
+// FIXME: should be rejected
+#[cfg(all(target_feature = "v8plus", not(target_feature = "v9")))]
+compile_error!("+v8plus,-v9 (FIXME)");
+//[sparc_feature_v8plus]~^ ERROR +v8plus,-v9 (FIXME)
+
+#[cfg(all(not(target_feature = "v8plus"), target_feature = "v9"))]
+compile_error!("-v8plus,+v9");
diff --git a/tests/ui/abi/sparcv8plus.sparc.stderr b/tests/ui/abi/sparcv8plus.sparc.stderr
new file mode 100644
index 00000000000..6d14ff53ab9
--- /dev/null
+++ b/tests/ui/abi/sparcv8plus.sparc.stderr
@@ -0,0 +1,8 @@
+error: -v8plus,-v9
+  --> $DIR/sparcv8plus.rs:29:1
+   |
+LL | compile_error!("-v8plus,-v9");
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr b/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr
new file mode 100644
index 00000000000..5e1e1fa5c79
--- /dev/null
+++ b/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr
@@ -0,0 +1,8 @@
+error: +v8plus,+v9
+  --> $DIR/sparcv8plus.rs:34:1
+   |
+LL | compile_error!("+v8plus,+v9");
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr
new file mode 100644
index 00000000000..5e1e1fa5c79
--- /dev/null
+++ b/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr
@@ -0,0 +1,8 @@
+error: +v8plus,+v9
+  --> $DIR/sparcv8plus.rs:34:1
+   |
+LL | compile_error!("+v8plus,+v9");
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr
new file mode 100644
index 00000000000..8a5375a46bc
--- /dev/null
+++ b/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr
@@ -0,0 +1,8 @@
+error: +v8plus,-v9 (FIXME)
+  --> $DIR/sparcv8plus.rs:39:1
+   |
+LL | compile_error!("+v8plus,-v9 (FIXME)");
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/sparcv8plus.sparcv8plus.stderr b/tests/ui/abi/sparcv8plus.sparcv8plus.stderr
new file mode 100644
index 00000000000..5e1e1fa5c79
--- /dev/null
+++ b/tests/ui/abi/sparcv8plus.sparcv8plus.stderr
@@ -0,0 +1,8 @@
+error: +v8plus,+v9
+  --> $DIR/sparcv8plus.rs:34:1
+   |
+LL | compile_error!("+v8plus,+v9");
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/issue-70935-complex-spans.rs b/tests/ui/async-await/issue-70935-complex-spans.rs
index a74bd9890ca..2851637ae78 100644
--- a/tests/ui/async-await/issue-70935-complex-spans.rs
+++ b/tests/ui/async-await/issue-70935-complex-spans.rs
@@ -14,8 +14,8 @@ async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
 
 fn foo(x: NotSync) -> impl Future + Send {
     //~^ ERROR `*mut ()` cannot be shared between threads safely
-    //~| ERROR `*mut ()` cannot be shared between threads safely
     async move {
+    //~^ ERROR `*mut ()` cannot be shared between threads safely
         baz(|| async {
             foo(x.clone());
         }).await;
diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr
index c6b7e21b9dd..31d15c45921 100644
--- a/tests/ui/async-await/issue-70935-complex-spans.stderr
+++ b/tests/ui/async-await/issue-70935-complex-spans.stderr
@@ -1,8 +1,13 @@
 error[E0277]: `*mut ()` cannot be shared between threads safely
-  --> $DIR/issue-70935-complex-spans.rs:15:23
+  --> $DIR/issue-70935-complex-spans.rs:17:5
    |
-LL | fn foo(x: NotSync) -> impl Future + Send {
-   |                       ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely
+LL | /     async move {
+LL | |
+LL | |         baz(|| async {
+LL | |             foo(x.clone());
+LL | |         }).await;
+LL | |     }
+   | |_____^ `*mut ()` cannot be shared between threads safely
    |
    = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`
 note: required because it appears within the type `PhantomData<*mut ()>`
@@ -26,10 +31,15 @@ LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
 LL | | }
    | |_^
 note: required because it's used within this `async` block
-  --> $DIR/issue-70935-complex-spans.rs:18:5
+  --> $DIR/issue-70935-complex-spans.rs:17:5
    |
 LL |     async move {
    |     ^^^^^^^^^^
+note: required by a bound in an opaque type
+  --> $DIR/issue-70935-complex-spans.rs:15:37
+   |
+LL | fn foo(x: NotSync) -> impl Future + Send {
+   |                                     ^^^^
 
 error[E0277]: `*mut ()` cannot be shared between threads safely
   --> $DIR/issue-70935-complex-spans.rs:15:23
@@ -59,11 +69,10 @@ LL |   async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
 LL | | }
    | |_^
 note: required because it's used within this `async` block
-  --> $DIR/issue-70935-complex-spans.rs:18:5
+  --> $DIR/issue-70935-complex-spans.rs:17:5
    |
 LL |     async move {
    |     ^^^^^^^^^^
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 43766788de7..ab212dda015 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra`
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 247 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 250 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 224313c6c8d..f51271dc3de 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `wide-arithmetic`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `leoncasa`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v8plus`, `v9`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `wide-arithmetic`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/iterators/iterator-does-not-need-into-iter.rs b/tests/ui/iterators/iterator-does-not-need-into-iter.rs
new file mode 100644
index 00000000000..29196449e30
--- /dev/null
+++ b/tests/ui/iterators/iterator-does-not-need-into-iter.rs
@@ -0,0 +1,18 @@
+//! regression test for #127511: don't suggest `.into_iter()` on iterators
+
+trait Missing {}
+trait HasMethod {
+    fn foo(self);
+}
+impl<T: Iterator + Missing> HasMethod for T {
+    fn foo(self) {}
+}
+
+fn get_iter() -> impl Iterator {
+    core::iter::once(())
+}
+
+fn main() {
+    get_iter().foo();
+    //~^ ERROR the method `foo` exists for opaque type `impl Iterator`, but its trait bounds were not satisfied [E0599]
+}
diff --git a/tests/ui/iterators/iterator-does-not-need-into-iter.stderr b/tests/ui/iterators/iterator-does-not-need-into-iter.stderr
new file mode 100644
index 00000000000..3d3861e959f
--- /dev/null
+++ b/tests/ui/iterators/iterator-does-not-need-into-iter.stderr
@@ -0,0 +1,28 @@
+error[E0599]: the method `foo` exists for opaque type `impl Iterator`, but its trait bounds were not satisfied
+  --> $DIR/iterator-does-not-need-into-iter.rs:16:16
+   |
+LL |     get_iter().foo();
+   |                ^^^ method cannot be called on `impl Iterator` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `&impl Iterator: Iterator`
+      `&impl Iterator: Missing`
+      `&mut impl Iterator: Missing`
+      `impl Iterator: Missing`
+  --> $DIR/iterator-does-not-need-into-iter.rs:7:9
+   |
+LL | impl<T: Iterator + Missing> HasMethod for T {
+   |         ^^^^^^^^   ^^^^^^^  ---------     -
+   |         |          |
+   |         |          unsatisfied trait bound introduced here
+   |         unsatisfied trait bound introduced here
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `HasMethod` defines an item `foo`, perhaps you need to implement it
+  --> $DIR/iterator-does-not-need-into-iter.rs:4:1
+   |
+LL | trait HasMethod {
+   | ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs b/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs
new file mode 100644
index 00000000000..fe2b6de7bb3
--- /dev/null
+++ b/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs
@@ -0,0 +1,14 @@
+//@ edition: 2021
+
+// Make sure we reject the case where a raw lifetime is immediately followed by another
+// lifetime. This reserves a modest amount of space for changing lexing to, for example,
+// delay rejection of overlong char literals like `'r#long'id`.
+
+macro_rules! w {
+    ($($tt:tt)*) => {}
+}
+
+w!('r#long'id);
+//~^ ERROR character literal may only contain one codepoint
+
+fn main() {}
diff --git a/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr b/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr
new file mode 100644
index 00000000000..1caeec84b22
--- /dev/null
+++ b/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr
@@ -0,0 +1,13 @@
+error: character literal may only contain one codepoint
+  --> $DIR/immediately-followed-by-lt.rs:11:4
+   |
+LL | w!('r#long'id);
+   |    ^^^^^^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL | w!("r#long"id);
+   |    ~      ~
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs
new file mode 100644
index 00000000000..882fad925f3
--- /dev/null
+++ b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.rs
@@ -0,0 +1,20 @@
+//@ edition: 2021
+
+// Reject raw lifetimes with identifier parts that wouldn't be valid raw identifiers.
+
+macro_rules! w {
+    ($tt:tt) => {};
+}
+
+w!('r#_);
+//~^ ERROR `_` cannot be a raw lifetime
+w!('r#self);
+//~^ ERROR `self` cannot be a raw lifetime
+w!('r#super);
+//~^ ERROR `super` cannot be a raw lifetime
+w!('r#Self);
+//~^ ERROR `Self` cannot be a raw lifetime
+w!('r#crate);
+//~^ ERROR `crate` cannot be a raw lifetime
+
+fn main() {}
diff --git a/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr
new file mode 100644
index 00000000000..4cbb89b7a55
--- /dev/null
+++ b/tests/ui/lifetimes/raw/raw-lt-invalid-raw-id.stderr
@@ -0,0 +1,32 @@
+error: `_` cannot be a raw lifetime
+  --> $DIR/raw-lt-invalid-raw-id.rs:9:4
+   |
+LL | w!('r#_);
+   |    ^^^^
+
+error: `self` cannot be a raw lifetime
+  --> $DIR/raw-lt-invalid-raw-id.rs:11:4
+   |
+LL | w!('r#self);
+   |    ^^^^^^^
+
+error: `super` cannot be a raw lifetime
+  --> $DIR/raw-lt-invalid-raw-id.rs:13:4
+   |
+LL | w!('r#super);
+   |    ^^^^^^^^
+
+error: `Self` cannot be a raw lifetime
+  --> $DIR/raw-lt-invalid-raw-id.rs:15:4
+   |
+LL | w!('r#Self);
+   |    ^^^^^^^
+
+error: `crate` cannot be a raw lifetime
+  --> $DIR/raw-lt-invalid-raw-id.rs:17:4
+   |
+LL | w!('r#crate);
+   |    ^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs
index 8f5b7cce469..98890a15d98 100644
--- a/tests/ui/mismatched_types/similar_paths_primitive.rs
+++ b/tests/ui/mismatched_types/similar_paths_primitive.rs
@@ -1,10 +1,14 @@
 #![allow(non_camel_case_types)]
 
 struct bool;
+struct str;
 
 fn foo(_: bool) {}
+fn bar(_: &str) {}
 
 fn main() {
     foo(true);
     //~^ ERROR mismatched types [E0308]
+    bar("hello");
+    //~^ ERROR mismatched types [E0308]
 }
diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr
index c9881891319..0530bf5863e 100644
--- a/tests/ui/mismatched_types/similar_paths_primitive.stderr
+++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/similar_paths_primitive.rs:8:9
+  --> $DIR/similar_paths_primitive.rs:10:9
    |
 LL |     foo(true);
    |     --- ^^^^ expected `bool`, found a different `bool`
@@ -14,11 +14,32 @@ note: `bool` is defined in the current crate
 LL | struct bool;
    | ^^^^^^^^^^^
 note: function defined here
-  --> $DIR/similar_paths_primitive.rs:5:4
+  --> $DIR/similar_paths_primitive.rs:6:4
    |
 LL | fn foo(_: bool) {}
    |    ^^^ -------
 
-error: aborting due to 1 previous error
+error[E0308]: mismatched types
+  --> $DIR/similar_paths_primitive.rs:12:9
+   |
+LL |     bar("hello");
+   |     --- ^^^^^^^ expected `str`, found a different `str`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note: str and `str` have similar names, but are actually distinct types
+   = note: str is a primitive defined by the language
+note: `str` is defined in the current crate
+  --> $DIR/similar_paths_primitive.rs:4:1
+   |
+LL | struct str;
+   | ^^^^^^^^^^
+note: function defined here
+  --> $DIR/similar_paths_primitive.rs:7:4
+   |
+LL | fn bar(_: &str) {}
+   |    ^^^ -------
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/usefulness/impl-trait.stderr b/tests/ui/pattern/usefulness/impl-trait.stderr
index 75cba4b5f02..34f8eb1e163 100644
--- a/tests/ui/pattern/usefulness/impl-trait.stderr
+++ b/tests/ui/pattern/usefulness/impl-trait.stderr
@@ -25,6 +25,20 @@ LL |             _ => {}
    |
    = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
 
+error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty
+  --> $DIR/impl-trait.rs:23:11
+   |
+LL |     match return_never_rpit(x) {}
+   |           ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `impl Copy`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match return_never_rpit(x) {
+LL +         _ => todo!(),
+LL +     }
+   |
+
 error: unreachable pattern
   --> $DIR/impl-trait.rs:45:13
    |
@@ -93,6 +107,20 @@ LL |             _ => {}
    |
    = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
 
+error[E0004]: non-exhaustive patterns: type `T` is non-empty
+  --> $DIR/impl-trait.rs:37:11
+   |
+LL |     match return_never_tait(x) {}
+   |           ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the matched value is of type `T`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     match return_never_tait(x) {
+LL +         _ => todo!(),
+LL +     }
+   |
+
 error: unreachable pattern
   --> $DIR/impl-trait.rs:105:9
    |
@@ -131,34 +159,6 @@ LL |             _ => {}
    |
    = note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
 
-error[E0004]: non-exhaustive patterns: type `impl Copy` is non-empty
-  --> $DIR/impl-trait.rs:23:11
-   |
-LL |     match return_never_rpit(x) {}
-   |           ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the matched value is of type `impl Copy`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match return_never_rpit(x) {
-LL +         _ => todo!(),
-LL +     }
-   |
-
-error[E0004]: non-exhaustive patterns: type `T` is non-empty
-  --> $DIR/impl-trait.rs:37:11
-   |
-LL |     match return_never_tait(x) {}
-   |           ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the matched value is of type `T`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
-   |
-LL ~     match return_never_tait(x) {
-LL +         _ => todo!(),
-LL +     }
-   |
-
 error: aborting due to 15 previous errors
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/resolve/issue-100365.stderr b/tests/ui/resolve/issue-100365.stderr
index 372d7726668..2d9bab4304d 100644
--- a/tests/ui/resolve/issue-100365.stderr
+++ b/tests/ui/resolve/issue-100365.stderr
@@ -2,19 +2,34 @@ error[E0423]: expected value, found trait `Into`
   --> $DIR/issue-100365.rs:2:16
    |
 LL |     let addr = Into::<std::net::IpAddr>.into([127, 0, 0, 1]);
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     let addr = Into::<std::net::IpAddr>::into([127, 0, 0, 1]);
+   |                                        ~~
 
 error[E0423]: expected value, found trait `Into`
   --> $DIR/issue-100365.rs:6:13
    |
 LL |     let _ = Into.into(());
-   |             ^^^^- help: use the path separator to refer to an item: `::`
+   |             ^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     let _ = Into::into(());
+   |                 ~~
 
 error[E0423]: expected value, found trait `Into`
   --> $DIR/issue-100365.rs:10:13
    |
 LL |     let _ = Into::<()>.into;
-   |             ^^^^^^^^^^- help: use the path separator to refer to an item: `::`
+   |             ^^^^^^^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     let _ = Into::<()>::into;
+   |                       ~~
 
 error[E0423]: expected value, found trait `std::iter::Iterator`
   --> $DIR/issue-100365.rs:17:9
@@ -42,12 +57,16 @@ error[E0423]: expected value, found trait `Into`
   --> $DIR/issue-100365.rs:25:9
    |
 LL |         Into::<String>.into("")
-   |         ^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
+   |         ^^^^^^^^^^^^^^
 ...
 LL |     let _ = create!();
    |             --------- in this macro invocation
    |
    = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use the path separator to refer to an item
+   |
+LL |         Into::<String>::into("")
+   |                       ~~
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/resolve/issue-22692.stderr b/tests/ui/resolve/issue-22692.stderr
index 6962aa161e9..be0634ebffc 100644
--- a/tests/ui/resolve/issue-22692.stderr
+++ b/tests/ui/resolve/issue-22692.stderr
@@ -2,19 +2,34 @@ error[E0423]: expected value, found struct `String`
   --> $DIR/issue-22692.rs:2:13
    |
 LL |     let _ = String.new();
-   |             ^^^^^^- help: use the path separator to refer to an item: `::`
+   |             ^^^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     let _ = String::new();
+   |                   ~~
 
 error[E0423]: expected value, found struct `String`
   --> $DIR/issue-22692.rs:6:13
    |
 LL |     let _ = String.default;
-   |             ^^^^^^- help: use the path separator to refer to an item: `::`
+   |             ^^^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     let _ = String::default;
+   |                   ~~
 
 error[E0423]: expected value, found struct `Vec`
   --> $DIR/issue-22692.rs:10:13
    |
 LL |     let _ = Vec::<()>.with_capacity(1);
-   |             ^^^^^^^^^- help: use the path separator to refer to an item: `::`
+   |             ^^^^^^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     let _ = Vec::<()>::with_capacity(1);
+   |                      ~~
 
 error[E0423]: expected value, found struct `std::cell::Cell`
   --> $DIR/issue-22692.rs:17:9
@@ -50,23 +65,31 @@ error[E0423]: expected value, found struct `Vec`
   --> $DIR/issue-22692.rs:26:9
    |
 LL |         Vec.new()
-   |         ^^^- help: use the path separator to refer to an item: `::`
+   |         ^^^
 ...
 LL |     let _ = create!(type method);
    |             -------------------- in this macro invocation
    |
    = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use the path separator to refer to an item
+   |
+LL |         Vec::new()
+   |            ~~
 
 error[E0423]: expected value, found struct `Vec`
   --> $DIR/issue-22692.rs:31:9
    |
 LL |         Vec.new
-   |         ^^^- help: use the path separator to refer to an item: `::`
+   |         ^^^
 ...
 LL |     let _ = create!(type field);
    |             ------------------- in this macro invocation
    |
    = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use the path separator to refer to an item
+   |
+LL |         Vec::new
+   |            ~~
 
 error[E0423]: expected value, found struct `std::cell::Cell`
   --> $DIR/issue-22692.rs:17:9
diff --git a/tests/ui/resolve/suggest-path-for-tuple-struct.stderr b/tests/ui/resolve/suggest-path-for-tuple-struct.stderr
index 4764cf2db20..12c631f5a83 100644
--- a/tests/ui/resolve/suggest-path-for-tuple-struct.stderr
+++ b/tests/ui/resolve/suggest-path-for-tuple-struct.stderr
@@ -2,13 +2,23 @@ error[E0423]: expected value, found struct `SomeTupleStruct`
   --> $DIR/suggest-path-for-tuple-struct.rs:22:13
    |
 LL |     let _ = SomeTupleStruct.new();
-   |             ^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
+   |             ^^^^^^^^^^^^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     let _ = SomeTupleStruct::new();
+   |                            ~~
 
 error[E0423]: expected value, found struct `SomeRegularStruct`
   --> $DIR/suggest-path-for-tuple-struct.rs:24:13
    |
 LL |     let _ = SomeRegularStruct.new();
-   |             ^^^^^^^^^^^^^^^^^- help: use the path separator to refer to an item: `::`
+   |             ^^^^^^^^^^^^^^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     let _ = SomeRegularStruct::new();
+   |                              ~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr b/tests/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
index a4ce0deeb70..9c12fd2644c 100644
--- a/tests/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
+++ b/tests/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr
@@ -2,19 +2,34 @@ error[E0423]: expected value, found module `a`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:17:5
    |
 LL |     a.I
-   |     ^- help: use the path separator to refer to an item: `::`
+   |     ^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     a::I
+   |      ~~
 
 error[E0423]: expected value, found module `a`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:23:5
    |
 LL |     a.g()
-   |     ^- help: use the path separator to refer to an item: `::`
+   |     ^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     a::g()
+   |      ~~
 
 error[E0423]: expected value, found module `a`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:29:5
    |
 LL |     a.b.J
-   |     ^- help: use the path separator to refer to an item: `::`
+   |     ^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     a::b.J
+   |      ~~
 
 error[E0423]: expected value, found module `a::b`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:35:5
@@ -38,7 +53,12 @@ error[E0423]: expected value, found module `a`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:42:5
    |
 LL |     a.b.f();
-   |     ^- help: use the path separator to refer to an item: `::`
+   |     ^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     a::b.f();
+   |      ~~
 
 error[E0423]: expected value, found module `a::b`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:46:12
@@ -117,23 +137,31 @@ error[E0423]: expected value, found module `a`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:80:9
    |
 LL |         a.f()
-   |         ^- help: use the path separator to refer to an item: `::`
+   |         ^
 ...
 LL |     let _ = create!(method);
    |             --------------- in this macro invocation
    |
    = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use the path separator to refer to an item
+   |
+LL |         a::f()
+   |          ~~
 
 error[E0423]: expected value, found module `a`
   --> $DIR/suggest-path-instead-of-mod-dot-item.rs:85:9
    |
 LL |         a.f
-   |         ^- help: use the path separator to refer to an item: `::`
+   |         ^
 ...
 LL |     let _ = create!(field);
    |             -------------- in this macro invocation
    |
    = note: this error originates in the macro `create` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use the path separator to refer to an item
+   |
+LL |         a::f
+   |          ~~
 
 error: aborting due to 13 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs
deleted file mode 100644
index 096036bb133..00000000000
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.rs
+++ /dev/null
@@ -1,340 +0,0 @@
-// Check that we don't suggest enabling a feature for code that's
-// not accepted even with that feature.
-
-#![allow(irrefutable_let_patterns)]
-
-use std::ops::Range;
-
-fn main() {}
-
-fn _if() {
-    if (let 0 = 1) {}
-    //~^ ERROR expected expression, found `let` statement
-
-    if (((let 0 = 1))) {}
-    //~^ ERROR expected expression, found `let` statement
-
-    if (let 0 = 1) && true {}
-    //~^ ERROR expected expression, found `let` statement
-
-    if true && (let 0 = 1) {}
-    //~^ ERROR expected expression, found `let` statement
-
-    if (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-
-    if (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-}
-
-fn _while() {
-    while (let 0 = 1) {}
-    //~^ ERROR expected expression, found `let` statement
-
-    while (((let 0 = 1))) {}
-    //~^ ERROR expected expression, found `let` statement
-
-    while (let 0 = 1) && true {}
-    //~^ ERROR expected expression, found `let` statement
-
-    while true && (let 0 = 1) {}
-    //~^ ERROR expected expression, found `let` statement
-
-    while (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-
-    while (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-}
-
-fn _macros() {
-    macro_rules! use_expr {
-        ($e:expr) => {
-            if $e {}
-            while $e {}
-        }
-    }
-    use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR expected expression, found `let` statement
-    use_expr!((let 0 = 1));
-    //~^ ERROR expected expression, found `let` statement
-}
-
-fn nested_within_if_expr() {
-    if &let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-
-    if !let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-    if *let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-    if -let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-
-    fn _check_try_binds_tighter() -> Result<(), ()> {
-        if let 0 = 0? {}
-        //~^ ERROR the `?` operator can only be applied to values that implement `Try`
-        Ok(())
-    }
-    if (let 0 = 0)? {}
-    //~^ ERROR expected expression, found `let` statement
-
-    if true || let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-    if (true || let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-    if true && (true || let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-    if true || (true && let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-
-    let mut x = true;
-    if x = let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-
-    if true..(let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-    if ..(let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-    if (let 0 = 0).. {}
-    //~^ ERROR expected expression, found `let` statement
-
-    // Binds as `(let ... = true)..true &&/|| false`.
-    if let Range { start: _, end: _ } = true..true && false {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-    if let Range { start: _, end: _ } = true..true || false {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-
-    // Binds as `(let Range { start: F, end } = F)..(|| true)`.
-    const F: fn() -> bool = || true;
-    if let Range { start: F, end } = F..|| true {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-
-    // Binds as `(let Range { start: true, end } = t)..(&&false)`.
-    let t = &&true;
-    if let Range { start: true, end } = t..&&false {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-
-    if let true = let true = true {}
-    //~^ ERROR expected expression, found `let` statement
-}
-
-fn nested_within_while_expr() {
-    while &let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-
-    while !let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-    while *let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-    while -let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-
-    fn _check_try_binds_tighter() -> Result<(), ()> {
-        while let 0 = 0? {}
-        //~^ ERROR the `?` operator can only be applied to values that implement `Try`
-        Ok(())
-    }
-    while (let 0 = 0)? {}
-    //~^ ERROR expected expression, found `let` statement
-
-    while true || let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-    while (true || let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-    while true && (true || let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-    while true || (true && let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-
-    let mut x = true;
-    while x = let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
-
-    while true..(let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-    while ..(let 0 = 0) {}
-    //~^ ERROR expected expression, found `let` statement
-    while (let 0 = 0).. {}
-    //~^ ERROR expected expression, found `let` statement
-
-    // Binds as `(let ... = true)..true &&/|| false`.
-    while let Range { start: _, end: _ } = true..true && false {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-    while let Range { start: _, end: _ } = true..true || false {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-
-    // Binds as `(let Range { start: F, end } = F)..(|| true)`.
-    const F: fn() -> bool = || true;
-    while let Range { start: F, end } = F..|| true {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-
-    // Binds as `(let Range { start: true, end } = t)..(&&false)`.
-    let t = &&true;
-    while let Range { start: true, end } = t..&&false {}
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
-
-    while let true = let true = true {}
-    //~^ ERROR expected expression, found `let` statement
-}
-
-fn not_error_because_clarified_intent() {
-    if let Range { start: _, end: _ } = (true..true || false) { }
-
-    if let Range { start: _, end: _ } = (true..true && false) { }
-
-    while let Range { start: _, end: _ } = (true..true || false) { }
-
-    while let Range { start: _, end: _ } = (true..true && false) { }
-}
-
-fn outside_if_and_while_expr() {
-    &let 0 = 0;
-    //~^ ERROR expected expression, found `let` statement
-
-    !let 0 = 0;
-    //~^ ERROR expected expression, found `let` statement
-    *let 0 = 0;
-    //~^ ERROR expected expression, found `let` statement
-    -let 0 = 0;
-    //~^ ERROR expected expression, found `let` statement
-    let _ = let _ = 3;
-    //~^ ERROR expected expression, found `let` statement
-
-    fn _check_try_binds_tighter() -> Result<(), ()> {
-        let 0 = 0?;
-        //~^ ERROR the `?` operator can only be applied to values that implement `Try`
-        Ok(())
-    }
-    (let 0 = 0)?;
-    //~^ ERROR expected expression, found `let` statement
-
-    true || let 0 = 0;
-    //~^ ERROR expected expression, found `let` statement
-    (true || let 0 = 0);
-    //~^ ERROR expected expression, found `let` statement
-    true && (true || let 0 = 0);
-    //~^ ERROR expected expression, found `let` statement
-
-    let mut x = true;
-    x = let 0 = 0;
-    //~^ ERROR expected expression, found `let` statement
-
-    true..(let 0 = 0);
-    //~^ ERROR expected expression, found `let` statement
-    ..(let 0 = 0);
-    //~^ ERROR expected expression, found `let` statement
-    (let 0 = 0)..;
-    //~^ ERROR expected expression, found `let` statement
-
-    (let Range { start: _, end: _ } = true..true || false);
-    //~^ ERROR mismatched types
-    //~| ERROR expected expression, found `let` statement
-
-    (let true = let true = true);
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-
-    {
-        #[cfg(FALSE)]
-        let x = true && let y = 1;
-        //~^ ERROR expected expression, found `let` statement
-    }
-
-    #[cfg(FALSE)]
-    {
-        [1, 2, 3][let _ = ()]
-        //~^ ERROR expected expression, found `let` statement
-    }
-
-    // Check function tail position.
-    &let 0 = 0
-    //~^ ERROR expected expression, found `let` statement
-}
-
-// Let's make sure that `let` inside const generic arguments are considered.
-fn inside_const_generic_arguments() {
-    struct A<const B: bool>;
-    impl<const B: bool> A<{B}> { const O: u32 = 5; }
-
-    if let A::<{
-        true && let 1 = 1
-        //~^ ERROR expected expression, found `let` statement
-    }>::O = 5 {}
-
-    while let A::<{
-        true && let 1 = 1
-        //~^ ERROR expected expression, found `let` statement
-    }>::O = 5 {}
-
-    if A::<{
-        true && let 1 = 1
-        //~^ ERROR expected expression, found `let` statement
-    }>::O == 5 {}
-
-    // In the cases above we have `ExprKind::Block` to help us out.
-    // Below however, we would not have a block and so an implementation might go
-    // from visiting expressions to types without banning `let` expressions down the tree.
-    // This tests ensures that we are not caught by surprise should the parser
-    // admit non-IDENT expressions in const generic arguments.
-
-    if A::<
-        true && let 1 = 1
-        //~^ ERROR expressions must be enclosed in braces
-        //~| ERROR expected expression, found `let` statement
-    >::O == 5 {}
-}
-
-fn with_parenthesis() {
-    let opt = Some(Some(1i32));
-
-    if (let Some(a) = opt && true) {
-    //~^ ERROR expected expression, found `let` statement
-    }
-
-    if (let Some(a) = opt) && true {
-    //~^ ERROR expected expression, found `let` statement
-    }
-    if (let Some(a) = opt) && (let Some(b) = a) {
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-    }
-
-    if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-    }
-    if (let Some(a) = opt && (let Some(b) = a)) && true {
-    //~^ ERROR expected expression, found `let` statement
-    //~| ERROR expected expression, found `let` statement
-    }
-    if (let Some(a) = opt && (true)) && true {
-    //~^ ERROR expected expression, found `let` statement
-    }
-
-    #[cfg(FALSE)]
-    let x = (true && let y = 1);
-    //~^ ERROR expected expression, found `let` statement
-
-    #[cfg(FALSE)]
-    {
-        ([1, 2, 3][let _ = ()])
-        //~^ ERROR expected expression, found `let` statement
-    }
-}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr
index 31f389512ed..db32b8c1de4 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions-without-feature-gate.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr
@@ -1,239 +1,239 @@
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:11:9
+  --> $DIR/disallowed-positions.rs:33:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:11:9
+  --> $DIR/disallowed-positions.rs:33:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:14:11
+  --> $DIR/disallowed-positions.rs:36:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:14:11
+  --> $DIR/disallowed-positions.rs:36:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:17:9
+  --> $DIR/disallowed-positions.rs:39:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:17:9
+  --> $DIR/disallowed-positions.rs:39:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:20:17
+  --> $DIR/disallowed-positions.rs:42:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:20:17
+  --> $DIR/disallowed-positions.rs:42:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:23:9
+  --> $DIR/disallowed-positions.rs:45:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:23:9
+  --> $DIR/disallowed-positions.rs:45:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:23:24
+  --> $DIR/disallowed-positions.rs:45:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:23:24
+  --> $DIR/disallowed-positions.rs:45:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:27:9
+  --> $DIR/disallowed-positions.rs:49:35
    |
-LL |     if (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |         ^^^^^^^^^
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:27:9
+  --> $DIR/disallowed-positions.rs:49:35
    |
-LL |     if (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:27:22
+  --> $DIR/disallowed-positions.rs:49:48
    |
-LL |     if (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                      ^^^^^^^^^
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:27:9
+  --> $DIR/disallowed-positions.rs:49:35
    |
-LL |     if (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:27:35
+  --> $DIR/disallowed-positions.rs:49:61
    |
-LL |     if (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                                   ^^^^^^^^^
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:27:9
+  --> $DIR/disallowed-positions.rs:49:35
    |
-LL |     if (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:34:12
+  --> $DIR/disallowed-positions.rs:59:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:34:12
+  --> $DIR/disallowed-positions.rs:59:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:37:14
+  --> $DIR/disallowed-positions.rs:62:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:37:14
+  --> $DIR/disallowed-positions.rs:62:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:40:12
+  --> $DIR/disallowed-positions.rs:65:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:40:12
+  --> $DIR/disallowed-positions.rs:65:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:43:20
+  --> $DIR/disallowed-positions.rs:68:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:43:20
+  --> $DIR/disallowed-positions.rs:68:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:46:12
+  --> $DIR/disallowed-positions.rs:71:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:46:12
+  --> $DIR/disallowed-positions.rs:71:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:46:27
+  --> $DIR/disallowed-positions.rs:71:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:46:27
+  --> $DIR/disallowed-positions.rs:71:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:50:12
+  --> $DIR/disallowed-positions.rs:75:38
    |
-LL |     while (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |            ^^^^^^^^^
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:50:12
+  --> $DIR/disallowed-positions.rs:75:38
    |
-LL |     while (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:50:25
+  --> $DIR/disallowed-positions.rs:75:51
    |
-LL |     while (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                         ^^^^^^^^^
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:50:12
+  --> $DIR/disallowed-positions.rs:75:38
    |
-LL |     while (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:50:38
+  --> $DIR/disallowed-positions.rs:75:64
    |
-LL |     while (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                                      ^^^^^^^^^
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:50:12
+  --> $DIR/disallowed-positions.rs:75:38
    |
-LL |     while (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:70:9
+  --> $DIR/disallowed-positions.rs:99:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -241,7 +241,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:73:9
+  --> $DIR/disallowed-positions.rs:102:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -249,7 +249,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:75:9
+  --> $DIR/disallowed-positions.rs:104:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -257,7 +257,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:77:9
+  --> $DIR/disallowed-positions.rs:106:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -265,7 +265,7 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:85:9
+  --> $DIR/disallowed-positions.rs:114:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
@@ -273,20 +273,20 @@ LL |     if (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:88:16
+  --> $DIR/disallowed-positions.rs:117:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions-without-feature-gate.rs:88:13
+  --> $DIR/disallowed-positions.rs:117:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:90:17
+  --> $DIR/disallowed-positions.rs:119:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
@@ -294,7 +294,7 @@ LL |     if (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:92:25
+  --> $DIR/disallowed-positions.rs:121:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -302,7 +302,7 @@ LL |     if true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:94:25
+  --> $DIR/disallowed-positions.rs:123:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -310,7 +310,7 @@ LL |     if true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:98:12
+  --> $DIR/disallowed-positions.rs:127:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^
@@ -318,7 +318,7 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:101:15
+  --> $DIR/disallowed-positions.rs:130:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
@@ -326,7 +326,7 @@ LL |     if true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:104:11
+  --> $DIR/disallowed-positions.rs:133:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
@@ -334,7 +334,7 @@ LL |     if ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:106:9
+  --> $DIR/disallowed-positions.rs:135:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
@@ -342,7 +342,7 @@ LL |     if (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:110:8
+  --> $DIR/disallowed-positions.rs:139:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -350,7 +350,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:113:8
+  --> $DIR/disallowed-positions.rs:142:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -358,7 +358,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:119:8
+  --> $DIR/disallowed-positions.rs:148:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -366,7 +366,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:125:8
+  --> $DIR/disallowed-positions.rs:154:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -374,7 +374,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:129:19
+  --> $DIR/disallowed-positions.rs:158:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^
@@ -382,7 +382,71 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:134:12
+  --> $DIR/disallowed-positions.rs:161:15
+   |
+LL |     if return let 0 = 0 {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:164:21
+   |
+LL |     loop { if break let 0 = 0 {} }
+   |                     ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:167:15
+   |
+LL |     if (match let 0 = 0 { _ => { false } }) {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:170:9
+   |
+LL |     if (let 0 = 0, false).1 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:173:9
+   |
+LL |     if (let 0 = 0,) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:177:13
+   |
+LL |         if (let 0 = 0).await {}
+   |             ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:181:12
+   |
+LL |     if (|| let 0 = 0) {}
+   |            ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:184:9
+   |
+LL |     if (let 0 = 0)() {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:190:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -390,7 +454,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:137:12
+  --> $DIR/disallowed-positions.rs:193:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -398,7 +462,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:139:12
+  --> $DIR/disallowed-positions.rs:195:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -406,7 +470,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:141:12
+  --> $DIR/disallowed-positions.rs:197:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -414,7 +478,7 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:149:12
+  --> $DIR/disallowed-positions.rs:205:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
@@ -422,20 +486,20 @@ LL |     while (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:152:19
+  --> $DIR/disallowed-positions.rs:208:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions-without-feature-gate.rs:152:16
+  --> $DIR/disallowed-positions.rs:208:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:154:20
+  --> $DIR/disallowed-positions.rs:210:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
@@ -443,7 +507,7 @@ LL |     while (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:156:28
+  --> $DIR/disallowed-positions.rs:212:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -451,7 +515,7 @@ LL |     while true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:158:28
+  --> $DIR/disallowed-positions.rs:214:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -459,7 +523,7 @@ LL |     while true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:162:15
+  --> $DIR/disallowed-positions.rs:218:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^
@@ -467,7 +531,7 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:165:18
+  --> $DIR/disallowed-positions.rs:221:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
@@ -475,7 +539,7 @@ LL |     while true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:168:14
+  --> $DIR/disallowed-positions.rs:224:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
@@ -483,7 +547,7 @@ LL |     while ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:170:12
+  --> $DIR/disallowed-positions.rs:226:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
@@ -491,7 +555,7 @@ LL |     while (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:174:11
+  --> $DIR/disallowed-positions.rs:230:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -499,7 +563,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:177:11
+  --> $DIR/disallowed-positions.rs:233:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -507,7 +571,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:183:11
+  --> $DIR/disallowed-positions.rs:239:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -515,7 +579,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:189:11
+  --> $DIR/disallowed-positions.rs:245:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -523,7 +587,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:193:22
+  --> $DIR/disallowed-positions.rs:249:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^
@@ -531,7 +595,71 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:208:6
+  --> $DIR/disallowed-positions.rs:252:18
+   |
+LL |     while return let 0 = 0 {}
+   |                  ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:255:39
+   |
+LL |     'outer: loop { while break 'outer let 0 = 0 {} }
+   |                                       ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:258:18
+   |
+LL |     while (match let 0 = 0 { _ => { false } }) {}
+   |                  ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:261:12
+   |
+LL |     while (let 0 = 0, false).1 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:264:12
+   |
+LL |     while (let 0 = 0,) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:268:16
+   |
+LL |         while (let 0 = 0).await {}
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:272:15
+   |
+LL |     while (|| let 0 = 0) {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:275:12
+   |
+LL |     while (let 0 = 0)() {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:292:6
    |
 LL |     &let 0 = 0;
    |      ^^^
@@ -539,7 +667,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:211:6
+  --> $DIR/disallowed-positions.rs:295:6
    |
 LL |     !let 0 = 0;
    |      ^^^
@@ -547,7 +675,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:213:6
+  --> $DIR/disallowed-positions.rs:297:6
    |
 LL |     *let 0 = 0;
    |      ^^^
@@ -555,7 +683,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:215:6
+  --> $DIR/disallowed-positions.rs:299:6
    |
 LL |     -let 0 = 0;
    |      ^^^
@@ -563,7 +691,7 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:217:13
+  --> $DIR/disallowed-positions.rs:301:13
    |
 LL |     let _ = let _ = 3;
    |             ^^^
@@ -571,7 +699,7 @@ LL |     let _ = let _ = 3;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:225:6
+  --> $DIR/disallowed-positions.rs:309:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^
@@ -579,7 +707,7 @@ LL |     (let 0 = 0)?;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:228:13
+  --> $DIR/disallowed-positions.rs:312:13
    |
 LL |     true || let 0 = 0;
    |             ^^^
@@ -587,7 +715,7 @@ LL |     true || let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:230:14
+  --> $DIR/disallowed-positions.rs:314:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^
@@ -595,7 +723,7 @@ LL |     (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:232:22
+  --> $DIR/disallowed-positions.rs:316:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^
@@ -603,7 +731,7 @@ LL |     true && (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:236:9
+  --> $DIR/disallowed-positions.rs:320:9
    |
 LL |     x = let 0 = 0;
    |         ^^^
@@ -611,7 +739,7 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:239:12
+  --> $DIR/disallowed-positions.rs:323:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^
@@ -619,7 +747,7 @@ LL |     true..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:241:8
+  --> $DIR/disallowed-positions.rs:325:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^
@@ -627,7 +755,7 @@ LL |     ..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:243:6
+  --> $DIR/disallowed-positions.rs:327:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^
@@ -635,7 +763,7 @@ LL |     (let 0 = 0)..;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:246:6
+  --> $DIR/disallowed-positions.rs:330:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^
@@ -643,7 +771,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:250:6
+  --> $DIR/disallowed-positions.rs:334:6
    |
 LL |     (let true = let true = true);
    |      ^^^
@@ -651,7 +779,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:250:17
+  --> $DIR/disallowed-positions.rs:334:17
    |
 LL |     (let true = let true = true);
    |                 ^^^
@@ -659,7 +787,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:256:25
+  --> $DIR/disallowed-positions.rs:340:25
    |
 LL |         let x = true && let y = 1;
    |                         ^^^
@@ -667,7 +795,7 @@ LL |         let x = true && let y = 1;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:262:19
+  --> $DIR/disallowed-positions.rs:346:19
    |
 LL |         [1, 2, 3][let _ = ()]
    |                   ^^^
@@ -675,7 +803,7 @@ LL |         [1, 2, 3][let _ = ()]
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:267:6
+  --> $DIR/disallowed-positions.rs:351:6
    |
 LL |     &let 0 = 0
    |      ^^^
@@ -683,7 +811,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:277:17
+  --> $DIR/disallowed-positions.rs:362:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -691,7 +819,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:282:17
+  --> $DIR/disallowed-positions.rs:367:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -699,7 +827,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:287:17
+  --> $DIR/disallowed-positions.rs:372:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -707,7 +835,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:298:17
+  --> $DIR/disallowed-positions.rs:383:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -715,7 +843,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions-without-feature-gate.rs:298:9
+  --> $DIR/disallowed-positions.rs:383:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -726,124 +854,124 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:307:9
+  --> $DIR/disallowed-positions.rs:393:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:307:9
+  --> $DIR/disallowed-positions.rs:393:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:311:9
+  --> $DIR/disallowed-positions.rs:397:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:311:9
+  --> $DIR/disallowed-positions.rs:397:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:314:9
+  --> $DIR/disallowed-positions.rs:400:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:314:9
+  --> $DIR/disallowed-positions.rs:400:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:314:32
+  --> $DIR/disallowed-positions.rs:400:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:314:32
+  --> $DIR/disallowed-positions.rs:400:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:319:9
+  --> $DIR/disallowed-positions.rs:408:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:319:9
+  --> $DIR/disallowed-positions.rs:408:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:319:31
+  --> $DIR/disallowed-positions.rs:408:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:319:31
+  --> $DIR/disallowed-positions.rs:408:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:323:9
+  --> $DIR/disallowed-positions.rs:412:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:323:9
+  --> $DIR/disallowed-positions.rs:412:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:323:31
+  --> $DIR/disallowed-positions.rs:412:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:323:31
+  --> $DIR/disallowed-positions.rs:412:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:327:9
+  --> $DIR/disallowed-positions.rs:416:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions-without-feature-gate.rs:327:9
+  --> $DIR/disallowed-positions.rs:416:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:332:22
+  --> $DIR/disallowed-positions.rs:436:22
    |
 LL |     let x = (true && let y = 1);
    |                      ^^^
@@ -851,7 +979,7 @@ LL |     let x = (true && let y = 1);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:337:20
+  --> $DIR/disallowed-positions.rs:441:20
    |
 LL |         ([1, 2, 3][let _ = ()])
    |                    ^^^
@@ -859,7 +987,7 @@ LL |         ([1, 2, 3][let _ = ()])
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:63:16
+  --> $DIR/disallowed-positions.rs:91:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -867,7 +995,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions-without-feature-gate.rs:65:16
+  --> $DIR/disallowed-positions.rs:93:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
@@ -875,7 +1003,7 @@ LL |     use_expr!((let 0 = 1));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:101:8
+  --> $DIR/disallowed-positions.rs:130:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
@@ -884,7 +1012,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:110:12
+  --> $DIR/disallowed-positions.rs:139:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -895,7 +1023,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:113:12
+  --> $DIR/disallowed-positions.rs:142:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -906,7 +1034,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:119:12
+  --> $DIR/disallowed-positions.rs:148:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -917,7 +1045,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:125:12
+  --> $DIR/disallowed-positions.rs:154:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -928,7 +1056,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions-without-feature-gate.rs:81:20
+  --> $DIR/disallowed-positions.rs:110:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -936,7 +1064,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:165:11
+  --> $DIR/disallowed-positions.rs:221:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
@@ -945,7 +1073,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:174:15
+  --> $DIR/disallowed-positions.rs:230:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -956,7 +1084,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:177:15
+  --> $DIR/disallowed-positions.rs:233:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -967,7 +1095,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:183:15
+  --> $DIR/disallowed-positions.rs:239:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -978,7 +1106,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:189:15
+  --> $DIR/disallowed-positions.rs:245:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -989,7 +1117,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions-without-feature-gate.rs:145:23
+  --> $DIR/disallowed-positions.rs:201:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -997,7 +1125,7 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions-without-feature-gate.rs:246:10
+  --> $DIR/disallowed-positions.rs:330:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1008,14 +1136,14 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions-without-feature-gate.rs:221:17
+  --> $DIR/disallowed-positions.rs:305:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 105 previous errors
+error: aborting due to 121 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr
new file mode 100644
index 00000000000..ad16a0f8ed8
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr
@@ -0,0 +1,1239 @@
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:33:9
+   |
+LL |     if (let 0 = 1) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:33:9
+   |
+LL |     if (let 0 = 1) {}
+   |         ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:36:11
+   |
+LL |     if (((let 0 = 1))) {}
+   |           ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:36:11
+   |
+LL |     if (((let 0 = 1))) {}
+   |           ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:39:9
+   |
+LL |     if (let 0 = 1) && true {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:39:9
+   |
+LL |     if (let 0 = 1) && true {}
+   |         ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:42:17
+   |
+LL |     if true && (let 0 = 1) {}
+   |                 ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:42:17
+   |
+LL |     if true && (let 0 = 1) {}
+   |                 ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:45:9
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:45:9
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |         ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:45:24
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |                        ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:45:24
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |                        ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:49:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:49:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:49:48
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:49:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:49:61
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                             ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:49:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:59:12
+   |
+LL |     while (let 0 = 1) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:59:12
+   |
+LL |     while (let 0 = 1) {}
+   |            ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:62:14
+   |
+LL |     while (((let 0 = 1))) {}
+   |              ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:62:14
+   |
+LL |     while (((let 0 = 1))) {}
+   |              ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:65:12
+   |
+LL |     while (let 0 = 1) && true {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:65:12
+   |
+LL |     while (let 0 = 1) && true {}
+   |            ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:68:20
+   |
+LL |     while true && (let 0 = 1) {}
+   |                    ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:68:20
+   |
+LL |     while true && (let 0 = 1) {}
+   |                    ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:71:12
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:71:12
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |            ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:71:27
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |                           ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:71:27
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |                           ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:75:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:75:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:75:51
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                   ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:75:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:75:64
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:75:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:99:9
+   |
+LL |     if &let 0 = 0 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:102:9
+   |
+LL |     if !let 0 = 0 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:104:9
+   |
+LL |     if *let 0 = 0 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:106:9
+   |
+LL |     if -let 0 = 0 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:114:9
+   |
+LL |     if (let 0 = 0)? {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:117:16
+   |
+LL |     if true || let 0 = 0 {}
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:117:13
+   |
+LL |     if true || let 0 = 0 {}
+   |             ^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:119:17
+   |
+LL |     if (true || let 0 = 0) {}
+   |                 ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:121:25
+   |
+LL |     if true && (true || let 0 = 0) {}
+   |                         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:123:25
+   |
+LL |     if true || (true && let 0 = 0) {}
+   |                         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:127:12
+   |
+LL |     if x = let 0 = 0 {}
+   |            ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:130:15
+   |
+LL |     if true..(let 0 = 0) {}
+   |               ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:133:11
+   |
+LL |     if ..(let 0 = 0) {}
+   |           ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:135:9
+   |
+LL |     if (let 0 = 0).. {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:139:8
+   |
+LL |     if let Range { start: _, end: _ } = true..true && false {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:142:8
+   |
+LL |     if let Range { start: _, end: _ } = true..true || false {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:148:8
+   |
+LL |     if let Range { start: F, end } = F..|| true {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:154:8
+   |
+LL |     if let Range { start: true, end } = t..&&false {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:158:19
+   |
+LL |     if let true = let true = true {}
+   |                   ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:161:15
+   |
+LL |     if return let 0 = 0 {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:164:21
+   |
+LL |     loop { if break let 0 = 0 {} }
+   |                     ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:167:15
+   |
+LL |     if (match let 0 = 0 { _ => { false } }) {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:170:9
+   |
+LL |     if (let 0 = 0, false).1 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:173:9
+   |
+LL |     if (let 0 = 0,) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:177:13
+   |
+LL |         if (let 0 = 0).await {}
+   |             ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:181:12
+   |
+LL |     if (|| let 0 = 0) {}
+   |            ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:184:9
+   |
+LL |     if (let 0 = 0)() {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:190:12
+   |
+LL |     while &let 0 = 0 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:193:12
+   |
+LL |     while !let 0 = 0 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:195:12
+   |
+LL |     while *let 0 = 0 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:197:12
+   |
+LL |     while -let 0 = 0 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:205:12
+   |
+LL |     while (let 0 = 0)? {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:208:19
+   |
+LL |     while true || let 0 = 0 {}
+   |                   ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:208:16
+   |
+LL |     while true || let 0 = 0 {}
+   |                ^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:210:20
+   |
+LL |     while (true || let 0 = 0) {}
+   |                    ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:212:28
+   |
+LL |     while true && (true || let 0 = 0) {}
+   |                            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:214:28
+   |
+LL |     while true || (true && let 0 = 0) {}
+   |                            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:218:15
+   |
+LL |     while x = let 0 = 0 {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:221:18
+   |
+LL |     while true..(let 0 = 0) {}
+   |                  ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:224:14
+   |
+LL |     while ..(let 0 = 0) {}
+   |              ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:226:12
+   |
+LL |     while (let 0 = 0).. {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:230:11
+   |
+LL |     while let Range { start: _, end: _ } = true..true && false {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:233:11
+   |
+LL |     while let Range { start: _, end: _ } = true..true || false {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:239:11
+   |
+LL |     while let Range { start: F, end } = F..|| true {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:245:11
+   |
+LL |     while let Range { start: true, end } = t..&&false {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:249:22
+   |
+LL |     while let true = let true = true {}
+   |                      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:252:18
+   |
+LL |     while return let 0 = 0 {}
+   |                  ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:255:39
+   |
+LL |     'outer: loop { while break 'outer let 0 = 0 {} }
+   |                                       ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:258:18
+   |
+LL |     while (match let 0 = 0 { _ => { false } }) {}
+   |                  ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:261:12
+   |
+LL |     while (let 0 = 0, false).1 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:264:12
+   |
+LL |     while (let 0 = 0,) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:268:16
+   |
+LL |         while (let 0 = 0).await {}
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:272:15
+   |
+LL |     while (|| let 0 = 0) {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:275:12
+   |
+LL |     while (let 0 = 0)() {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:292:6
+   |
+LL |     &let 0 = 0;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:295:6
+   |
+LL |     !let 0 = 0;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:297:6
+   |
+LL |     *let 0 = 0;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:299:6
+   |
+LL |     -let 0 = 0;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:301:13
+   |
+LL |     let _ = let _ = 3;
+   |             ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:309:6
+   |
+LL |     (let 0 = 0)?;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:312:13
+   |
+LL |     true || let 0 = 0;
+   |             ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:314:14
+   |
+LL |     (true || let 0 = 0);
+   |              ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:316:22
+   |
+LL |     true && (true || let 0 = 0);
+   |                      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:320:9
+   |
+LL |     x = let 0 = 0;
+   |         ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:323:12
+   |
+LL |     true..(let 0 = 0);
+   |            ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:325:8
+   |
+LL |     ..(let 0 = 0);
+   |        ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:327:6
+   |
+LL |     (let 0 = 0)..;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:330:6
+   |
+LL |     (let Range { start: _, end: _ } = true..true || false);
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:334:6
+   |
+LL |     (let true = let true = true);
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:334:17
+   |
+LL |     (let true = let true = true);
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:340:25
+   |
+LL |         let x = true && let y = 1;
+   |                         ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:346:19
+   |
+LL |         [1, 2, 3][let _ = ()]
+   |                   ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:351:6
+   |
+LL |     &let 0 = 0
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:362:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:367:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:372:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:383:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/disallowed-positions.rs:383:9
+   |
+LL |         true && let 1 = 1
+   |         ^^^^^^^^^^^^^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |         { true && let 1 = 1 }
+   |         +                   +
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:393:9
+   |
+LL |     if (let Some(a) = opt && true) {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:393:9
+   |
+LL |     if (let Some(a) = opt && true) {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:397:9
+   |
+LL |     if (let Some(a) = opt) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:397:9
+   |
+LL |     if (let Some(a) = opt) && true {
+   |         ^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:400:9
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:400:9
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |         ^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:400:32
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |                                ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:400:32
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |                                ^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:408:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:408:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:408:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:408:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |                               ^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:412:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:412:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:412:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:412:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |                               ^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:416:9
+   |
+LL |     if (let Some(a) = opt && (true)) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:416:9
+   |
+LL |     if (let Some(a) = opt && (true)) && true {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:436:22
+   |
+LL |     let x = (true && let y = 1);
+   |                      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:441:20
+   |
+LL |         ([1, 2, 3][let _ = ()])
+   |                    ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:91:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:93:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:49:8
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |        ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:49:21
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                     ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:75:11
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |           ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:75:24
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                        ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:404:8
+   |
+LL |     if let Some(a) = opt && (true && true) {
+   |        ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:420:28
+   |
+LL |     if (true && (true)) && let Some(a) = opt {
+   |                            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:423:18
+   |
+LL |     if (true) && let Some(a) = opt {
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:426:16
+   |
+LL |     if true && let Some(a) = opt {
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:431:8
+   |
+LL |     if let true = (true && fun()) && (true) {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:130:8
+   |
+LL |     if true..(let 0 = 0) {}
+   |        ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:139:12
+   |
+LL |     if let Range { start: _, end: _ } = true..true && false {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
+   |            |
+   |            expected `bool`, found `Range<_>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:142:12
+   |
+LL |     if let Range { start: _, end: _ } = true..true || false {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
+   |            |
+   |            expected `bool`, found `Range<_>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:148:12
+   |
+LL |     if let Range { start: F, end } = F..|| true {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
+   |            |
+   |            expected fn pointer, found `Range<_>`
+   |
+   = note: expected fn pointer `fn() -> bool`
+                  found struct `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:154:12
+   |
+LL |     if let Range { start: true, end } = t..&&false {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
+   |            |
+   |            expected `bool`, found `Range<_>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<_>`
+
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/disallowed-positions.rs:110:20
+   |
+LL |         if let 0 = 0? {}
+   |                    ^^ the `?` operator cannot be applied to type `{integer}`
+   |
+   = help: the trait `Try` is not implemented for `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:221:11
+   |
+LL |     while true..(let 0 = 0) {}
+   |           ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<bool>`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:230:15
+   |
+LL |     while let Range { start: _, end: _ } = true..true && false {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
+   |               |
+   |               expected `bool`, found `Range<_>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:233:15
+   |
+LL |     while let Range { start: _, end: _ } = true..true || false {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
+   |               |
+   |               expected `bool`, found `Range<_>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:239:15
+   |
+LL |     while let Range { start: F, end } = F..|| true {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
+   |               |
+   |               expected fn pointer, found `Range<_>`
+   |
+   = note: expected fn pointer `fn() -> bool`
+                  found struct `std::ops::Range<_>`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:245:15
+   |
+LL |     while let Range { start: true, end } = t..&&false {}
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
+   |               |
+   |               expected `bool`, found `Range<_>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<_>`
+
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/disallowed-positions.rs:201:23
+   |
+LL |         while let 0 = 0? {}
+   |                       ^^ the `?` operator cannot be applied to type `{integer}`
+   |
+   = help: the trait `Try` is not implemented for `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/disallowed-positions.rs:330:10
+   |
+LL |     (let Range { start: _, end: _ } = true..true || false);
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
+   |          |
+   |          expected `bool`, found `Range<_>`
+   |
+   = note: expected type `bool`
+            found struct `std::ops::Range<_>`
+
+error[E0277]: the `?` operator can only be applied to values that implement `Try`
+  --> $DIR/disallowed-positions.rs:305:17
+   |
+LL |         let 0 = 0?;
+   |                 ^^ the `?` operator cannot be applied to type `{integer}`
+   |
+   = help: the trait `Try` is not implemented for `{integer}`
+
+error: aborting due to 130 previous errors
+
+Some errors have detailed explanations: E0277, E0308, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nofeature.stderr
index ab58abf4d46..f556ecf7f91 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nofeature.stderr
@@ -1,239 +1,239 @@
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:29:9
+  --> $DIR/disallowed-positions.rs:31:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:29:9
+  --> $DIR/disallowed-positions.rs:31:9
    |
 LL |     if (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:32:11
+  --> $DIR/disallowed-positions.rs:34:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:32:11
+  --> $DIR/disallowed-positions.rs:34:11
    |
 LL |     if (((let 0 = 1))) {}
    |           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:35:9
+  --> $DIR/disallowed-positions.rs:37:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:35:9
+  --> $DIR/disallowed-positions.rs:37:9
    |
 LL |     if (let 0 = 1) && true {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:38:17
+  --> $DIR/disallowed-positions.rs:40:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:38:17
+  --> $DIR/disallowed-positions.rs:40:17
    |
 LL |     if true && (let 0 = 1) {}
    |                 ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:41:9
+  --> $DIR/disallowed-positions.rs:43:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:41:9
+  --> $DIR/disallowed-positions.rs:43:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |         ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:41:24
+  --> $DIR/disallowed-positions.rs:43:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:41:24
+  --> $DIR/disallowed-positions.rs:43:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
    |                        ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:35
+  --> $DIR/disallowed-positions.rs:47:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:35
+  --> $DIR/disallowed-positions.rs:47:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:48
+  --> $DIR/disallowed-positions.rs:47:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:35
+  --> $DIR/disallowed-positions.rs:47:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:45:61
+  --> $DIR/disallowed-positions.rs:47:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:45:35
+  --> $DIR/disallowed-positions.rs:47:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:52:12
+  --> $DIR/disallowed-positions.rs:56:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:52:12
+  --> $DIR/disallowed-positions.rs:56:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:55:14
+  --> $DIR/disallowed-positions.rs:59:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:55:14
+  --> $DIR/disallowed-positions.rs:59:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:58:12
+  --> $DIR/disallowed-positions.rs:62:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:58:12
+  --> $DIR/disallowed-positions.rs:62:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:61:20
+  --> $DIR/disallowed-positions.rs:65:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:61:20
+  --> $DIR/disallowed-positions.rs:65:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:64:12
+  --> $DIR/disallowed-positions.rs:68:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:64:12
+  --> $DIR/disallowed-positions.rs:68:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:64:27
+  --> $DIR/disallowed-positions.rs:68:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:64:27
+  --> $DIR/disallowed-positions.rs:68:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:68:38
+  --> $DIR/disallowed-positions.rs:72:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:68:38
+  --> $DIR/disallowed-positions.rs:72:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:68:51
+  --> $DIR/disallowed-positions.rs:72:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:68:38
+  --> $DIR/disallowed-positions.rs:72:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:68:64
+  --> $DIR/disallowed-positions.rs:72:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:68:38
+  --> $DIR/disallowed-positions.rs:72:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:88:9
+  --> $DIR/disallowed-positions.rs:95:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -241,7 +241,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:91:9
+  --> $DIR/disallowed-positions.rs:98:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -249,7 +249,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:93:9
+  --> $DIR/disallowed-positions.rs:100:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -257,7 +257,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:95:9
+  --> $DIR/disallowed-positions.rs:102:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -265,7 +265,7 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:103:9
+  --> $DIR/disallowed-positions.rs:110:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
@@ -273,20 +273,20 @@ LL |     if (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:106:16
+  --> $DIR/disallowed-positions.rs:113:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:106:13
+  --> $DIR/disallowed-positions.rs:113:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:108:17
+  --> $DIR/disallowed-positions.rs:115:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
@@ -294,7 +294,7 @@ LL |     if (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:110:25
+  --> $DIR/disallowed-positions.rs:117:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -302,7 +302,7 @@ LL |     if true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:112:25
+  --> $DIR/disallowed-positions.rs:119:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -310,7 +310,7 @@ LL |     if true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:116:12
+  --> $DIR/disallowed-positions.rs:123:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^
@@ -318,7 +318,7 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:119:15
+  --> $DIR/disallowed-positions.rs:126:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
@@ -326,7 +326,7 @@ LL |     if true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:122:11
+  --> $DIR/disallowed-positions.rs:129:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
@@ -334,7 +334,7 @@ LL |     if ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:124:9
+  --> $DIR/disallowed-positions.rs:131:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
@@ -342,7 +342,7 @@ LL |     if (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:128:8
+  --> $DIR/disallowed-positions.rs:135:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -350,7 +350,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:131:8
+  --> $DIR/disallowed-positions.rs:138:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -358,7 +358,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:137:8
+  --> $DIR/disallowed-positions.rs:144:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -366,7 +366,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:143:8
+  --> $DIR/disallowed-positions.rs:150:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -374,7 +374,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:147:19
+  --> $DIR/disallowed-positions.rs:154:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^
@@ -382,7 +382,7 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:152:12
+  --> $DIR/disallowed-positions.rs:160:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -390,7 +390,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:155:12
+  --> $DIR/disallowed-positions.rs:163:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -398,7 +398,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:157:12
+  --> $DIR/disallowed-positions.rs:165:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -406,7 +406,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:159:12
+  --> $DIR/disallowed-positions.rs:167:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -414,7 +414,7 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:167:12
+  --> $DIR/disallowed-positions.rs:175:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
@@ -422,20 +422,20 @@ LL |     while (let 0 = 0)? {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:170:19
+  --> $DIR/disallowed-positions.rs:178:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:170:16
+  --> $DIR/disallowed-positions.rs:178:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:172:20
+  --> $DIR/disallowed-positions.rs:180:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
@@ -443,7 +443,7 @@ LL |     while (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:174:28
+  --> $DIR/disallowed-positions.rs:182:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -451,7 +451,7 @@ LL |     while true && (true || let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:176:28
+  --> $DIR/disallowed-positions.rs:184:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -459,7 +459,7 @@ LL |     while true || (true && let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:180:15
+  --> $DIR/disallowed-positions.rs:188:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^
@@ -467,7 +467,7 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:183:18
+  --> $DIR/disallowed-positions.rs:191:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
@@ -475,7 +475,7 @@ LL |     while true..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:186:14
+  --> $DIR/disallowed-positions.rs:194:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
@@ -483,7 +483,7 @@ LL |     while ..(let 0 = 0) {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:188:12
+  --> $DIR/disallowed-positions.rs:196:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
@@ -491,7 +491,7 @@ LL |     while (let 0 = 0).. {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:192:11
+  --> $DIR/disallowed-positions.rs:200:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -499,7 +499,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:195:11
+  --> $DIR/disallowed-positions.rs:203:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -507,7 +507,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:201:11
+  --> $DIR/disallowed-positions.rs:209:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -515,7 +515,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:207:11
+  --> $DIR/disallowed-positions.rs:215:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -523,7 +523,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:211:22
+  --> $DIR/disallowed-positions.rs:219:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^
@@ -531,7 +531,7 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:226:6
+  --> $DIR/disallowed-positions.rs:236:6
    |
 LL |     &let 0 = 0;
    |      ^^^
@@ -539,7 +539,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:229:6
+  --> $DIR/disallowed-positions.rs:239:6
    |
 LL |     !let 0 = 0;
    |      ^^^
@@ -547,7 +547,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:231:6
+  --> $DIR/disallowed-positions.rs:241:6
    |
 LL |     *let 0 = 0;
    |      ^^^
@@ -555,7 +555,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:233:6
+  --> $DIR/disallowed-positions.rs:243:6
    |
 LL |     -let 0 = 0;
    |      ^^^
@@ -563,7 +563,15 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:241:6
+  --> $DIR/disallowed-positions.rs:245:13
+   |
+LL |     let _ = let _ = 3;
+   |             ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:253:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^
@@ -571,7 +579,7 @@ LL |     (let 0 = 0)?;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:244:13
+  --> $DIR/disallowed-positions.rs:256:13
    |
 LL |     true || let 0 = 0;
    |             ^^^
@@ -579,7 +587,7 @@ LL |     true || let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:246:14
+  --> $DIR/disallowed-positions.rs:258:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^
@@ -587,7 +595,7 @@ LL |     (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:248:22
+  --> $DIR/disallowed-positions.rs:260:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^
@@ -595,7 +603,7 @@ LL |     true && (true || let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:252:9
+  --> $DIR/disallowed-positions.rs:264:9
    |
 LL |     x = let 0 = 0;
    |         ^^^
@@ -603,7 +611,7 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:255:12
+  --> $DIR/disallowed-positions.rs:267:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^
@@ -611,7 +619,7 @@ LL |     true..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:257:8
+  --> $DIR/disallowed-positions.rs:269:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^
@@ -619,7 +627,7 @@ LL |     ..(let 0 = 0);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:259:6
+  --> $DIR/disallowed-positions.rs:271:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^
@@ -627,7 +635,7 @@ LL |     (let 0 = 0)..;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:262:6
+  --> $DIR/disallowed-positions.rs:274:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^
@@ -635,7 +643,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:266:6
+  --> $DIR/disallowed-positions.rs:278:6
    |
 LL |     (let true = let true = true);
    |      ^^^
@@ -643,7 +651,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:266:17
+  --> $DIR/disallowed-positions.rs:278:17
    |
 LL |     (let true = let true = true);
    |                 ^^^
@@ -651,7 +659,7 @@ LL |     (let true = let true = true);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:272:25
+  --> $DIR/disallowed-positions.rs:284:25
    |
 LL |         let x = true && let y = 1;
    |                         ^^^
@@ -659,7 +667,7 @@ LL |         let x = true && let y = 1;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:278:19
+  --> $DIR/disallowed-positions.rs:290:19
    |
 LL |         [1, 2, 3][let _ = ()]
    |                   ^^^
@@ -667,7 +675,7 @@ LL |         [1, 2, 3][let _ = ()]
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:283:6
+  --> $DIR/disallowed-positions.rs:295:6
    |
 LL |     &let 0 = 0
    |      ^^^
@@ -675,7 +683,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:293:17
+  --> $DIR/disallowed-positions.rs:306:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -683,7 +691,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:298:17
+  --> $DIR/disallowed-positions.rs:311:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -691,7 +699,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:303:17
+  --> $DIR/disallowed-positions.rs:316:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -699,7 +707,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:314:17
+  --> $DIR/disallowed-positions.rs:327:17
    |
 LL |         true && let 1 = 1
    |                 ^^^
@@ -707,7 +715,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:314:9
+  --> $DIR/disallowed-positions.rs:327:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -718,124 +726,124 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:323:9
+  --> $DIR/disallowed-positions.rs:337:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:323:9
+  --> $DIR/disallowed-positions.rs:337:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:327:9
+  --> $DIR/disallowed-positions.rs:341:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:327:9
+  --> $DIR/disallowed-positions.rs:341:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:330:9
+  --> $DIR/disallowed-positions.rs:344:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:330:9
+  --> $DIR/disallowed-positions.rs:344:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:330:32
+  --> $DIR/disallowed-positions.rs:344:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:330:32
+  --> $DIR/disallowed-positions.rs:344:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:337:9
+  --> $DIR/disallowed-positions.rs:351:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:337:9
+  --> $DIR/disallowed-positions.rs:351:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:337:31
+  --> $DIR/disallowed-positions.rs:351:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:337:31
+  --> $DIR/disallowed-positions.rs:351:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:341:9
+  --> $DIR/disallowed-positions.rs:355:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:341:9
+  --> $DIR/disallowed-positions.rs:355:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:341:31
+  --> $DIR/disallowed-positions.rs:355:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:341:31
+  --> $DIR/disallowed-positions.rs:355:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:345:9
+  --> $DIR/disallowed-positions.rs:359:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:345:9
+  --> $DIR/disallowed-positions.rs:359:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:361:22
+  --> $DIR/disallowed-positions.rs:375:22
    |
 LL |     let x = (true && let y = 1);
    |                      ^^^
@@ -843,7 +851,7 @@ LL |     let x = (true && let y = 1);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:366:20
+  --> $DIR/disallowed-positions.rs:380:20
    |
 LL |         ([1, 2, 3][let _ = ()])
    |                    ^^^
@@ -851,7 +859,7 @@ LL |         ([1, 2, 3][let _ = ()])
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:81:16
+  --> $DIR/disallowed-positions.rs:87:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
@@ -859,15 +867,105 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:83:16
+  --> $DIR/disallowed-positions.rs:89:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:47:8
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |        ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:47:21
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                     ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:72:11
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |           ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:72:24
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                        ^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:348:8
+   |
+LL |     if let Some(a) = opt && (true && true) {
+   |        ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:363:28
+   |
+LL |     if (true && (true)) && let Some(a) = opt {
+   |                            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:365:18
+   |
+LL |     if (true) && let Some(a) = opt {
+   |                  ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:367:16
+   |
+LL |     if true && let Some(a) = opt {
+   |                ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/disallowed-positions.rs:371:8
+   |
+LL |     if let true = (true && fun()) && (true) {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:119:8
+  --> $DIR/disallowed-positions.rs:126:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
@@ -876,7 +974,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:128:12
+  --> $DIR/disallowed-positions.rs:135:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -887,7 +985,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:131:12
+  --> $DIR/disallowed-positions.rs:138:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -898,7 +996,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:137:12
+  --> $DIR/disallowed-positions.rs:144:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -909,7 +1007,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:143:12
+  --> $DIR/disallowed-positions.rs:150:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -920,7 +1018,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:99:20
+  --> $DIR/disallowed-positions.rs:106:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -928,7 +1026,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:183:11
+  --> $DIR/disallowed-positions.rs:191:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found `Range<bool>`
@@ -937,7 +1035,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:192:15
+  --> $DIR/disallowed-positions.rs:200:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -948,7 +1046,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:195:15
+  --> $DIR/disallowed-positions.rs:203:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -959,7 +1057,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:201:15
+  --> $DIR/disallowed-positions.rs:209:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -970,7 +1068,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:207:15
+  --> $DIR/disallowed-positions.rs:215:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -981,7 +1079,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:163:23
+  --> $DIR/disallowed-positions.rs:171:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -989,7 +1087,7 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:262:10
+  --> $DIR/disallowed-positions.rs:274:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1000,14 +1098,14 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:237:17
+  --> $DIR/disallowed-positions.rs:249:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 104 previous errors
+error: aborting due to 114 previous errors
 
-Some errors have detailed explanations: E0277, E0308.
+Some errors have detailed explanations: E0277, E0308, E0658.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr
new file mode 100644
index 00000000000..2d5fd1144ad
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr
@@ -0,0 +1,990 @@
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:33:9
+   |
+LL |     if (let 0 = 1) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:33:9
+   |
+LL |     if (let 0 = 1) {}
+   |         ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:36:11
+   |
+LL |     if (((let 0 = 1))) {}
+   |           ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:36:11
+   |
+LL |     if (((let 0 = 1))) {}
+   |           ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:39:9
+   |
+LL |     if (let 0 = 1) && true {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:39:9
+   |
+LL |     if (let 0 = 1) && true {}
+   |         ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:42:17
+   |
+LL |     if true && (let 0 = 1) {}
+   |                 ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:42:17
+   |
+LL |     if true && (let 0 = 1) {}
+   |                 ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:45:9
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:45:9
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |         ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:45:24
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |                        ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:45:24
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |                        ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:49:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:49:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:49:48
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:49:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:49:61
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                             ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:49:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:59:12
+   |
+LL |     while (let 0 = 1) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:59:12
+   |
+LL |     while (let 0 = 1) {}
+   |            ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:62:14
+   |
+LL |     while (((let 0 = 1))) {}
+   |              ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:62:14
+   |
+LL |     while (((let 0 = 1))) {}
+   |              ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:65:12
+   |
+LL |     while (let 0 = 1) && true {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:65:12
+   |
+LL |     while (let 0 = 1) && true {}
+   |            ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:68:20
+   |
+LL |     while true && (let 0 = 1) {}
+   |                    ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:68:20
+   |
+LL |     while true && (let 0 = 1) {}
+   |                    ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:71:12
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:71:12
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |            ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:71:27
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |                           ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:71:27
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |                           ^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:75:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:75:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:75:51
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                   ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:75:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:75:64
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:75:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:99:9
+   |
+LL |     if &let 0 = 0 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:102:9
+   |
+LL |     if !let 0 = 0 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:104:9
+   |
+LL |     if *let 0 = 0 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:106:9
+   |
+LL |     if -let 0 = 0 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:114:9
+   |
+LL |     if (let 0 = 0)? {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:117:16
+   |
+LL |     if true || let 0 = 0 {}
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:117:13
+   |
+LL |     if true || let 0 = 0 {}
+   |             ^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:119:17
+   |
+LL |     if (true || let 0 = 0) {}
+   |                 ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:121:25
+   |
+LL |     if true && (true || let 0 = 0) {}
+   |                         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:123:25
+   |
+LL |     if true || (true && let 0 = 0) {}
+   |                         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:127:12
+   |
+LL |     if x = let 0 = 0 {}
+   |            ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:130:15
+   |
+LL |     if true..(let 0 = 0) {}
+   |               ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:133:11
+   |
+LL |     if ..(let 0 = 0) {}
+   |           ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:135:9
+   |
+LL |     if (let 0 = 0).. {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:139:8
+   |
+LL |     if let Range { start: _, end: _ } = true..true && false {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:142:8
+   |
+LL |     if let Range { start: _, end: _ } = true..true || false {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:148:8
+   |
+LL |     if let Range { start: F, end } = F..|| true {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:154:8
+   |
+LL |     if let Range { start: true, end } = t..&&false {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:158:19
+   |
+LL |     if let true = let true = true {}
+   |                   ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:161:15
+   |
+LL |     if return let 0 = 0 {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:164:21
+   |
+LL |     loop { if break let 0 = 0 {} }
+   |                     ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:167:15
+   |
+LL |     if (match let 0 = 0 { _ => { false } }) {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:170:9
+   |
+LL |     if (let 0 = 0, false).1 {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:173:9
+   |
+LL |     if (let 0 = 0,) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:177:13
+   |
+LL |         if (let 0 = 0).await {}
+   |             ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:181:12
+   |
+LL |     if (|| let 0 = 0) {}
+   |            ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:184:9
+   |
+LL |     if (let 0 = 0)() {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:190:12
+   |
+LL |     while &let 0 = 0 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:193:12
+   |
+LL |     while !let 0 = 0 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:195:12
+   |
+LL |     while *let 0 = 0 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:197:12
+   |
+LL |     while -let 0 = 0 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:205:12
+   |
+LL |     while (let 0 = 0)? {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:208:19
+   |
+LL |     while true || let 0 = 0 {}
+   |                   ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:208:16
+   |
+LL |     while true || let 0 = 0 {}
+   |                ^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:210:20
+   |
+LL |     while (true || let 0 = 0) {}
+   |                    ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:212:28
+   |
+LL |     while true && (true || let 0 = 0) {}
+   |                            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:214:28
+   |
+LL |     while true || (true && let 0 = 0) {}
+   |                            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:218:15
+   |
+LL |     while x = let 0 = 0 {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:221:18
+   |
+LL |     while true..(let 0 = 0) {}
+   |                  ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:224:14
+   |
+LL |     while ..(let 0 = 0) {}
+   |              ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:226:12
+   |
+LL |     while (let 0 = 0).. {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:230:11
+   |
+LL |     while let Range { start: _, end: _ } = true..true && false {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:233:11
+   |
+LL |     while let Range { start: _, end: _ } = true..true || false {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:239:11
+   |
+LL |     while let Range { start: F, end } = F..|| true {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:245:11
+   |
+LL |     while let Range { start: true, end } = t..&&false {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:249:22
+   |
+LL |     while let true = let true = true {}
+   |                      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:252:18
+   |
+LL |     while return let 0 = 0 {}
+   |                  ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:255:39
+   |
+LL |     'outer: loop { while break 'outer let 0 = 0 {} }
+   |                                       ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:258:18
+   |
+LL |     while (match let 0 = 0 { _ => { false } }) {}
+   |                  ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:261:12
+   |
+LL |     while (let 0 = 0, false).1 {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:264:12
+   |
+LL |     while (let 0 = 0,) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:268:16
+   |
+LL |         while (let 0 = 0).await {}
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:272:15
+   |
+LL |     while (|| let 0 = 0) {}
+   |               ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:275:12
+   |
+LL |     while (let 0 = 0)() {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:292:6
+   |
+LL |     &let 0 = 0;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:295:6
+   |
+LL |     !let 0 = 0;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:297:6
+   |
+LL |     *let 0 = 0;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:299:6
+   |
+LL |     -let 0 = 0;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:301:13
+   |
+LL |     let _ = let _ = 3;
+   |             ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:309:6
+   |
+LL |     (let 0 = 0)?;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:312:13
+   |
+LL |     true || let 0 = 0;
+   |             ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:314:14
+   |
+LL |     (true || let 0 = 0);
+   |              ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:316:22
+   |
+LL |     true && (true || let 0 = 0);
+   |                      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:320:9
+   |
+LL |     x = let 0 = 0;
+   |         ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:323:12
+   |
+LL |     true..(let 0 = 0);
+   |            ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:325:8
+   |
+LL |     ..(let 0 = 0);
+   |        ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:327:6
+   |
+LL |     (let 0 = 0)..;
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:330:6
+   |
+LL |     (let Range { start: _, end: _ } = true..true || false);
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:334:6
+   |
+LL |     (let true = let true = true);
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:334:17
+   |
+LL |     (let true = let true = true);
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:340:25
+   |
+LL |         let x = true && let y = 1;
+   |                         ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:346:19
+   |
+LL |         [1, 2, 3][let _ = ()]
+   |                   ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:351:6
+   |
+LL |     &let 0 = 0
+   |      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:362:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:367:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:372:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:383:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expressions must be enclosed in braces to be used as const generic arguments
+  --> $DIR/disallowed-positions.rs:383:9
+   |
+LL |         true && let 1 = 1
+   |         ^^^^^^^^^^^^^^^^^
+   |
+help: enclose the `const` expression in braces
+   |
+LL |         { true && let 1 = 1 }
+   |         +                   +
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:393:9
+   |
+LL |     if (let Some(a) = opt && true) {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:393:9
+   |
+LL |     if (let Some(a) = opt && true) {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:397:9
+   |
+LL |     if (let Some(a) = opt) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:397:9
+   |
+LL |     if (let Some(a) = opt) && true {
+   |         ^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:400:9
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:400:9
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |         ^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:400:32
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |                                ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:400:32
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |                                ^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:408:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:408:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:408:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:408:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |                               ^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:412:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:412:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:412:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:412:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |                               ^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:416:9
+   |
+LL |     if (let Some(a) = opt && (true)) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:416:9
+   |
+LL |     if (let Some(a) = opt && (true)) && true {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:436:22
+   |
+LL |     let x = (true && let y = 1);
+   |                      ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:441:20
+   |
+LL |         ([1, 2, 3][let _ = ()])
+   |                    ^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: aborting due to 105 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
index 4ac3ea53a08..8eb8d617d58 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -1,3 +1,5 @@
+//@ revisions: no_feature feature nothing
+//@ edition: 2021
 // Here we test that `lowering` behaves correctly wrt. `let $pats = $expr` expressions.
 //
 // We want to make sure that `let` is banned in situations other than:
@@ -17,7 +19,8 @@
 //
 // To that end, we check some positions which is not part of the language above.
 
-#![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
+// Avoid inflating `.stderr` with overzealous gates (or test what happens if you disable the gate)
+#![cfg_attr(not(no_feature), feature(let_chains))]
 
 #![allow(irrefutable_let_patterns)]
 
@@ -25,6 +28,7 @@ use std::ops::Range;
 
 fn main() {}
 
+#[cfg(not(nothing))]
 fn _if() {
     if (let 0 = 1) {}
     //~^ ERROR expected expression, found `let` statement
@@ -46,8 +50,11 @@ fn _if() {
     //~^ ERROR expected expression, found `let` statement
     //~| ERROR expected expression, found `let` statement
     //~| ERROR expected expression, found `let` statement
+    //[no_feature]~| ERROR `let` expressions in this position are unstable
+    //[no_feature]~| ERROR `let` expressions in this position are unstable
 }
 
+#[cfg(not(nothing))]
 fn _while() {
     while (let 0 = 1) {}
     //~^ ERROR expected expression, found `let` statement
@@ -69,8 +76,11 @@ fn _while() {
     //~^ ERROR expected expression, found `let` statement
     //~| ERROR expected expression, found `let` statement
     //~| ERROR expected expression, found `let` statement
+    //[no_feature]~| ERROR `let` expressions in this position are unstable
+    //[no_feature]~| ERROR `let` expressions in this position are unstable
 }
 
+#[cfg(not(nothing))]
 fn _macros() {
     macro_rules! use_expr {
         ($e:expr) => {
@@ -79,11 +89,12 @@ fn _macros() {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR expected expression, found `let` statement
+    //[feature,no_feature]~^ ERROR expected expression, found `let` statement
     use_expr!((let 0 = 1));
-    //~^ ERROR expected expression, found `let` statement
+    //[feature,no_feature]~^ ERROR expected expression, found `let` statement
 }
 
+#[cfg(not(nothing))]
 fn nested_within_if_expr() {
     if &let 0 = 0 {}
     //~^ ERROR expected expression, found `let` statement
@@ -97,7 +108,7 @@ fn nested_within_if_expr() {
 
     fn _check_try_binds_tighter() -> Result<(), ()> {
         if let 0 = 0? {}
-        //~^ ERROR the `?` operator can only be applied to values that implement `Try`
+        //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try`
         Ok(())
     }
     if (let 0 = 0)? {}
@@ -118,7 +129,7 @@ fn nested_within_if_expr() {
 
     if true..(let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
     if ..(let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
     if (let 0 = 0).. {}
@@ -127,27 +138,54 @@ fn nested_within_if_expr() {
     // Binds as `(let ... = true)..true &&/|| false`.
     if let Range { start: _, end: _ } = true..true && false {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
     if let Range { start: _, end: _ } = true..true || false {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
 
     // Binds as `(let Range { start: F, end } = F)..(|| true)`.
     const F: fn() -> bool = || true;
     if let Range { start: F, end } = F..|| true {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
 
     // Binds as `(let Range { start: true, end } = t)..(&&false)`.
     let t = &&true;
     if let Range { start: true, end } = t..&&false {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
 
     if let true = let true = true {}
     //~^ ERROR expected expression, found `let` statement
+
+    if return let 0 = 0 {}
+    //~^ ERROR expected expression, found `let` statement
+
+    loop { if break let 0 = 0 {} }
+    //~^ ERROR expected expression, found `let` statement
+
+    if (match let 0 = 0 { _ => { false } }) {}
+    //~^ ERROR expected expression, found `let` statement
+
+    if (let 0 = 0, false).1 {}
+    //~^ ERROR expected expression, found `let` statement
+
+    if (let 0 = 0,) {}
+    //~^ ERROR expected expression, found `let` statement
+
+    async fn foo() {
+        if (let 0 = 0).await {}
+        //~^ ERROR expected expression, found `let` statement
+    }
+
+    if (|| let 0 = 0) {}
+    //~^ ERROR expected expression, found `let` statement
+
+    if (let 0 = 0)() {}
+    //~^ ERROR expected expression, found `let` statement
 }
 
+#[cfg(not(nothing))]
 fn nested_within_while_expr() {
     while &let 0 = 0 {}
     //~^ ERROR expected expression, found `let` statement
@@ -161,7 +199,7 @@ fn nested_within_while_expr() {
 
     fn _check_try_binds_tighter() -> Result<(), ()> {
         while let 0 = 0? {}
-        //~^ ERROR the `?` operator can only be applied to values that implement `Try`
+        //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try`
         Ok(())
     }
     while (let 0 = 0)? {}
@@ -182,7 +220,7 @@ fn nested_within_while_expr() {
 
     while true..(let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
     while ..(let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
     while (let 0 = 0).. {}
@@ -191,27 +229,54 @@ fn nested_within_while_expr() {
     // Binds as `(let ... = true)..true &&/|| false`.
     while let Range { start: _, end: _ } = true..true && false {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
     while let Range { start: _, end: _ } = true..true || false {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
 
     // Binds as `(let Range { start: F, end } = F)..(|| true)`.
     const F: fn() -> bool = || true;
     while let Range { start: F, end } = F..|| true {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
 
     // Binds as `(let Range { start: true, end } = t)..(&&false)`.
     let t = &&true;
     while let Range { start: true, end } = t..&&false {}
     //~^ ERROR expected expression, found `let` statement
-    //~| ERROR mismatched types
+    //[feature,no_feature]~| ERROR mismatched types
 
     while let true = let true = true {}
     //~^ ERROR expected expression, found `let` statement
+
+    while return let 0 = 0 {}
+    //~^ ERROR expected expression, found `let` statement
+
+    'outer: loop { while break 'outer let 0 = 0 {} }
+    //~^ ERROR expected expression, found `let` statement
+
+    while (match let 0 = 0 { _ => { false } }) {}
+    //~^ ERROR expected expression, found `let` statement
+
+    while (let 0 = 0, false).1 {}
+    //~^ ERROR expected expression, found `let` statement
+
+    while (let 0 = 0,) {}
+    //~^ ERROR expected expression, found `let` statement
+
+    async fn foo() {
+        while (let 0 = 0).await {}
+        //~^ ERROR expected expression, found `let` statement
+    }
+
+    while (|| let 0 = 0) {}
+    //~^ ERROR expected expression, found `let` statement
+
+    while (let 0 = 0)() {}
+    //~^ ERROR expected expression, found `let` statement
 }
 
+#[cfg(not(nothing))]
 fn not_error_because_clarified_intent() {
     if let Range { start: _, end: _ } = (true..true || false) { }
 
@@ -222,6 +287,7 @@ fn not_error_because_clarified_intent() {
     while let Range { start: _, end: _ } = (true..true && false) { }
 }
 
+#[cfg(not(nothing))]
 fn outside_if_and_while_expr() {
     &let 0 = 0;
     //~^ ERROR expected expression, found `let` statement
@@ -232,10 +298,12 @@ fn outside_if_and_while_expr() {
     //~^ ERROR expected expression, found `let` statement
     -let 0 = 0;
     //~^ ERROR expected expression, found `let` statement
+    let _ = let _ = 3;
+    //~^ ERROR expected expression, found `let` statement
 
     fn _check_try_binds_tighter() -> Result<(), ()> {
         let 0 = 0?;
-        //~^ ERROR the `?` operator can only be applied to values that implement `Try`
+        //[feature,no_feature]~^ ERROR the `?` operator can only be applied to values that implement `Try`
         Ok(())
     }
     (let 0 = 0)?;
@@ -260,8 +328,8 @@ fn outside_if_and_while_expr() {
     //~^ ERROR expected expression, found `let` statement
 
     (let Range { start: _, end: _ } = true..true || false);
-    //~^ ERROR mismatched types
-    //~| ERROR expected expression, found `let` statement
+    //~^ ERROR expected expression, found `let` statement
+    //[feature,no_feature]~| ERROR mismatched types
 
     (let true = let true = true);
     //~^ ERROR expected expression, found `let` statement
@@ -285,6 +353,7 @@ fn outside_if_and_while_expr() {
 }
 
 // Let's make sure that `let` inside const generic arguments are considered.
+#[cfg(not(nothing))]
 fn inside_const_generic_arguments() {
     struct A<const B: bool>;
     impl<const B: bool> A<{B}> { const O: u32 = 5; }
@@ -317,6 +386,7 @@ fn inside_const_generic_arguments() {
     >::O == 5 {}
 }
 
+#[cfg(not(nothing))]
 fn with_parenthesis() {
     let opt = Some(Some(1i32));
 
@@ -332,6 +402,7 @@ fn with_parenthesis() {
     //~| ERROR expected expression, found `let` statement
     }
     if let Some(a) = opt && (true && true) {
+    //[no_feature]~^ ERROR `let` expressions in this position are unstable
     }
 
     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
@@ -347,14 +418,18 @@ fn with_parenthesis() {
     }
 
     if (true && (true)) && let Some(a) = opt {
+    //[no_feature]~^ ERROR `let` expressions in this position are unstable
     }
     if (true) && let Some(a) = opt {
+    //[no_feature]~^ ERROR `let` expressions in this position are unstable
     }
     if true && let Some(a) = opt {
+    //[no_feature]~^ ERROR `let` expressions in this position are unstable
     }
 
     let fun = || true;
     if let true = (true && fun()) && (true) {
+    //[no_feature]~^ ERROR `let` expressions in this position are unstable
     }
 
     #[cfg(FALSE)]
diff --git a/tests/ui/suggestions/assoc-const-as-field.stderr b/tests/ui/suggestions/assoc-const-as-field.stderr
index 0f58ce65049..6c095e52ac9 100644
--- a/tests/ui/suggestions/assoc-const-as-field.stderr
+++ b/tests/ui/suggestions/assoc-const-as-field.stderr
@@ -2,7 +2,12 @@ error[E0423]: expected value, found struct `Mod::Foo`
   --> $DIR/assoc-const-as-field.rs:11:9
    |
 LL |     foo(Mod::Foo.Bar);
-   |         ^^^^^^^^- help: use the path separator to refer to an item: `::`
+   |         ^^^^^^^^
+   |
+help: use the path separator to refer to an item
+   |
+LL |     foo(Mod::Foo::Bar);
+   |                 ~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs
index 5c4fb847932..f35fbd11155 100644
--- a/tests/ui/target-feature/gate.rs
+++ b/tests/ui/target-feature/gate.rs
@@ -23,6 +23,7 @@
 // gate-test-lahfsahf_target_feature
 // gate-test-prfchw_target_feature
 // gate-test-s390x_target_feature
+// gate-test-sparc_target_feature
 
 #[target_feature(enable = "avx512bw")]
 //~^ ERROR: currently unstable
diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr
index 37c5ed01688..b84bab370be 100644
--- a/tests/ui/target-feature/gate.stderr
+++ b/tests/ui/target-feature/gate.stderr
@@ -1,5 +1,5 @@
 error[E0658]: the target feature `avx512bw` is currently unstable
-  --> $DIR/gate.rs:27:18
+  --> $DIR/gate.rs:28:18
    |
 LL | #[target_feature(enable = "avx512bw")]
    |                  ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/const-traits/cross-crate.rs b/tests/ui/traits/const-traits/cross-crate.rs
index 9558ec6164e..b07aa8944c0 100644
--- a/tests/ui/traits/const-traits/cross-crate.rs
+++ b/tests/ui/traits/const-traits/cross-crate.rs
@@ -18,11 +18,9 @@ const fn const_context() {
     #[cfg(any(stocknc, gatednc))]
     NonConst.func();
     //[stocknc]~^ ERROR: cannot call
-    //[stocknc]~| ERROR: cannot call
-    //[gatednc]~^^^ ERROR: the trait bound
+    //[gatednc]~^^ ERROR: the trait bound
     Const.func();
     //[stock,stocknc]~^ ERROR: cannot call
-    //[stock,stocknc]~| ERROR: cannot call
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/cross-crate.stock.stderr b/tests/ui/traits/const-traits/cross-crate.stock.stderr
index b35891071b0..09bf9c023c8 100644
--- a/tests/ui/traits/const-traits/cross-crate.stock.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.stock.stderr
@@ -1,28 +1,13 @@
-error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:23:11
+error[E0658]: cannot call conditionally-const method `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:22:5
    |
 LL |     Const.func();
-   |           ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:23:11
-   |
-LL |     Const.func();
-   |           ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
+   |     ^^^^^^^^^^^^
    |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
index 89de89159db..e52e5609b01 100644
--- a/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
+++ b/tests/ui/traits/const-traits/cross-crate.stocknc.stderr
@@ -1,53 +1,23 @@
-error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:19:14
+error[E0658]: cannot call conditionally-const method `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:19:5
    |
 LL |     NonConst.func();
-   |              ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:19:14
-   |
-LL |     NonConst.func();
-   |              ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
+   |     ^^^^^^^^^^^^^^^
    |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:23:11
+error[E0658]: cannot call conditionally-const method `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:22:5
    |
 LL |     Const.func();
-   |           ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
-  --> $DIR/cross-crate.rs:23:11
-   |
-LL |     Const.func();
-   |           ^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
+   |     ^^^^^^^^^^^^
    |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-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 E0658`.
diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.rs b/tests/ui/traits/const-traits/staged-api-user-crate.rs
index c820d1ff47c..7587042cf27 100644
--- a/tests/ui/traits/const-traits/staged-api-user-crate.rs
+++ b/tests/ui/traits/const-traits/staged-api-user-crate.rs
@@ -10,8 +10,7 @@ fn non_const_context() {
 
 const fn stable_const_context() {
     Unstable::func();
-    //~^ ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
-    //~| ERROR cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
+    //~^ ERROR cannot call conditionally-const associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/staged-api-user-crate.stderr b/tests/ui/traits/const-traits/staged-api-user-crate.stderr
index 24cdb1d3d5a..bf7466b8e16 100644
--- a/tests/ui/traits/const-traits/staged-api-user-crate.stderr
+++ b/tests/ui/traits/const-traits/staged-api-user-crate.stderr
@@ -1,28 +1,13 @@
-error[E0015]: cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
+error[E0658]: cannot call conditionally-const associated function `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
   --> $DIR/staged-api-user-crate.rs:12:5
    |
 LL |     Unstable::func();
    |     ^^^^^^^^^^^^^^^^
    |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
-
-error[E0015]: cannot call non-const fn `<staged_api::Unstable as staged_api::MyTrait>::func` in constant functions
-  --> $DIR/staged-api-user-crate.rs:12:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
-   |
-LL + #![feature(const_trait_impl)]
-   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/const-traits/staged-api.rs b/tests/ui/traits/const-traits/staged-api.rs
index 401a81d8142..755a4e456bc 100644
--- a/tests/ui/traits/const-traits/staged-api.rs
+++ b/tests/ui/traits/const-traits/staged-api.rs
@@ -1,10 +1,11 @@
-//@ revisions: stable unstable
+//! Checks whether we are properly enforcing recursive const stability for trait calls.
 //@ compile-flags: -Znext-solver
 
-#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
-#![cfg_attr(unstable, feature(local_feature))]
+#![feature(unstable)] // The feature from the ./auxiliary/staged-api.rs file.
+#![feature(local_feature)]
 #![feature(const_trait_impl)]
 #![feature(staged_api)]
+#![feature(rustc_allow_const_fn_unstable)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
 //@ aux-build: staged-api.rs
@@ -16,13 +17,16 @@ use staged_api::*;
 pub struct Foo;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
-#[cfg_attr(stable, rustc_const_stable(feature = "local_feature", since = "1.0.0"))]
+#[rustc_const_unstable(feature = "local_feature", issue = "none")]
 impl const MyTrait for Foo {
-    //[stable]~^ ERROR trait implementations cannot be const stable yet
     fn func() {}
 }
 
+#[rustc_allow_const_fn_unstable(const_trait_impl)]
+const fn conditionally_const<T: ~const MyTrait>() {
+    T::func();
+}
+
 // Const stability has no impact on usage in non-const contexts.
 fn non_const_context() {
     Unstable::func();
@@ -32,43 +36,35 @@ fn non_const_context() {
 #[unstable(feature = "none", issue = "none")]
 const fn const_context() {
     Unstable::func();
-    //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
-    //[stable]~^^ ERROR not yet stable as a const fn
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
     Foo::func();
-    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
-    //[stable]~^^ cannot be (indirectly) exposed to stable
-    // We get the error on `stable` since this is a trait function.
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
     Unstable2::func();
-    //~^ ERROR not yet stable as a const fn
-    // ^ fails, because the `unstable2` feature is not active
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
+    conditionally_const::<Foo>();
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(unstable, rustc_const_unstable(feature = "local_feature", issue = "none"))]
+#[rustc_const_unstable(feature = "local_feature", issue = "none")]
 pub const fn const_context_not_const_stable() {
-    //[stable]~^ ERROR function has missing const stability attribute
     Unstable::func();
-    //[stable]~^ ERROR not yet stable as a const fn
     Foo::func();
-    //[stable]~^ cannot be (indirectly) exposed to stable
-    // We get the error on `stable` since this is a trait function.
     Unstable2::func();
-    //~^ ERROR not yet stable as a const fn
-    // ^ fails, because the `unstable2` feature is not active
+    conditionally_const::<Foo>();
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "cheese", since = "1.0.0")]
 const fn stable_const_context() {
     Unstable::func();
-    //[unstable]~^ ERROR cannot use `#[feature(unstable)]`
-    //[stable]~^^ ERROR not yet stable as a const fn
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
     Foo::func();
-    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
-    //[stable]~^^ cannot be (indirectly) exposed to stable
-    // We get the error on `stable` since this is a trait function.
-    const_context_not_const_stable()
-    //[unstable]~^ ERROR cannot use `#[feature(local_feature)]`
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
+    const_context_not_const_stable();
+    //~^ ERROR cannot use `#[feature(local_feature)]`
+    conditionally_const::<Foo>();
+    //~^ ERROR cannot use `#[feature(const_trait_impl)]`
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/staged-api.stable.stderr b/tests/ui/traits/const-traits/staged-api.stable.stderr
deleted file mode 100644
index 8f491b2f182..00000000000
--- a/tests/ui/traits/const-traits/staged-api.stable.stderr
+++ /dev/null
@@ -1,89 +0,0 @@
-error: trait implementations cannot be const stable yet
-  --> $DIR/staged-api.rs:21:1
-   |
-LL | / impl const MyTrait for Foo {
-LL | |
-LL | |     fn func() {}
-LL | | }
-   | |_^
-   |
-   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
-
-error: function has missing const stability attribute
-  --> $DIR/staged-api.rs:48:1
-   |
-LL | / pub const fn const_context_not_const_stable() {
-LL | |
-LL | |     Unstable::func();
-LL | |
-...  |
-LL | |     // ^ fails, because the `unstable2` feature is not active
-LL | | }
-   | |_^
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:34:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-
-error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
-  --> $DIR/staged-api.rs:37:5
-   |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
-   |
-   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
-
-error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:41:5
-   |
-LL |     Unstable2::func();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable2)]` to the crate attributes to enable
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:50:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-
-error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
-  --> $DIR/staged-api.rs:52:5
-   |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
-   |
-   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
-
-error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:55:5
-   |
-LL |     Unstable2::func();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable2)]` to the crate attributes to enable
-
-error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:63:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable)]` to the crate attributes to enable
-
-error: `<Foo as staged_api::MyTrait>::func` cannot be (indirectly) exposed to stable
-  --> $DIR/staged-api.rs:66:5
-   |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
-   |
-   = help: either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]`
-
-error: aborting due to 10 previous errors
-
diff --git a/tests/ui/traits/const-traits/staged-api.stderr b/tests/ui/traits/const-traits/staged-api.stderr
new file mode 100644
index 00000000000..29aafa4e0f3
--- /dev/null
+++ b/tests/ui/traits/const-traits/staged-api.stderr
@@ -0,0 +1,139 @@
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:38:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:40:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:42:5
+   |
+LL |     Unstable2::func();
+   |     ^^^^^^^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:44:5
+   |
+LL |     conditionally_const::<Foo>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
+LL | const fn const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:60:5
+   |
+LL |     Unstable::func();
+   |     ^^^^^^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
+LL | const fn stable_const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:62:5
+   |
+LL |     Foo::func();
+   |     ^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
+LL | const fn stable_const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
+  --> $DIR/staged-api.rs:64:5
+   |
+LL |     const_context_not_const_stable();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
+help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(local_feature)]
+LL | const fn stable_const_context() {
+   |
+
+error: const function that might be (indirectly) exposed to stable cannot use `#[feature(const_trait_impl)]`
+  --> $DIR/staged-api.rs:66:5
+   |
+LL |     conditionally_const::<Foo>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
+   |
+LL + #[rustc_const_unstable(feature = "...", issue = "...")]
+LL | const fn stable_const_context() {
+   |
+help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
+   |
+LL + #[rustc_allow_const_fn_unstable(const_trait_impl)]
+LL | const fn stable_const_context() {
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/traits/const-traits/staged-api.unstable.stderr b/tests/ui/traits/const-traits/staged-api.unstable.stderr
deleted file mode 100644
index 76275452e90..00000000000
--- a/tests/ui/traits/const-traits/staged-api.unstable.stderr
+++ /dev/null
@@ -1,108 +0,0 @@
-error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
-  --> $DIR/staged-api.rs:34:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
-help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
-   |
-LL + #[rustc_const_unstable(feature = "...", issue = "...")]
-LL | const fn const_context() {
-   |
-help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
-   |
-LL + #[rustc_allow_const_fn_unstable(unstable)]
-LL | const fn const_context() {
-   |
-
-error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
-  --> $DIR/staged-api.rs:37:5
-   |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
-   |
-   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
-help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
-   |
-LL + #[rustc_const_unstable(feature = "...", issue = "...")]
-LL | const fn const_context() {
-   |
-help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
-   |
-LL + #[rustc_allow_const_fn_unstable(local_feature)]
-LL | const fn const_context() {
-   |
-
-error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:41:5
-   |
-LL |     Unstable2::func();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable2)]` to the crate attributes to enable
-
-error: `<staged_api::Unstable2 as staged_api::MyTrait>::func` is not yet stable as a const fn
-  --> $DIR/staged-api.rs:55:5
-   |
-LL |     Unstable2::func();
-   |     ^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(unstable2)]` to the crate attributes to enable
-
-error: const function that might be (indirectly) exposed to stable cannot use `#[feature(unstable)]`
-  --> $DIR/staged-api.rs:63:5
-   |
-LL |     Unstable::func();
-   |     ^^^^^^^^^^^^^^^^
-   |
-   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
-help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
-   |
-LL + #[rustc_const_unstable(feature = "...", issue = "...")]
-LL | const fn stable_const_context() {
-   |
-help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
-   |
-LL + #[rustc_allow_const_fn_unstable(unstable)]
-LL | const fn stable_const_context() {
-   |
-
-error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
-  --> $DIR/staged-api.rs:66:5
-   |
-LL |     Foo::func();
-   |     ^^^^^^^^^^^
-   |
-   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
-help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
-   |
-LL + #[rustc_const_unstable(feature = "...", issue = "...")]
-LL | const fn stable_const_context() {
-   |
-help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
-   |
-LL + #[rustc_allow_const_fn_unstable(local_feature)]
-LL | const fn stable_const_context() {
-   |
-
-error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local_feature)]`
-  --> $DIR/staged-api.rs:70:5
-   |
-LL |     const_context_not_const_stable()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: mark the callee as `#[rustc_const_stable_indirect]` if it does not itself require any unsafe features
-help: if the caller is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do)
-   |
-LL + #[rustc_const_unstable(feature = "...", issue = "...")]
-LL | const fn stable_const_context() {
-   |
-help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval)
-   |
-LL + #[rustc_allow_const_fn_unstable(local_feature)]
-LL | const fn stable_const_context() {
-   |
-
-error: aborting due to 7 previous errors
-
diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr b/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
index 0c937f92253..8f887a6ac68 100644
--- a/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
+++ b/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr
@@ -4,6 +4,16 @@ error[E0277]: the trait bound `T: Clone` is not satisfied
 LL |         t
    |         ^ the trait `Clone` is not implemented for `T`
    |
+note: required by a bound in an opaque type
+  --> $DIR/bounds-are-checked-2.rs:7:26
+   |
+LL |     pub type X<T> = impl Clone;
+   |                          ^^^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/bounds-are-checked-2.rs:9:5
+   |
+LL |     fn f<T: Clone>(t: T) -> X<T> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `T`
    |
 LL |     pub type X<T: std::clone::Clone> = impl Clone;
diff --git a/tests/ui/type-alias-impl-trait/closure_wf_outlives.rs b/tests/ui/type-alias-impl-trait/closure_wf_outlives.rs
index 430b444aae1..caa9b6d979a 100644
--- a/tests/ui/type-alias-impl-trait/closure_wf_outlives.rs
+++ b/tests/ui/type-alias-impl-trait/closure_wf_outlives.rs
@@ -12,20 +12,19 @@
 // requires `'a: 'b` bound
 mod test1 {
     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
-    //~^ ERROR lifetime bound not satisfied
 
     fn define<'a, 'b>() -> Opaque<'a, 'b>
     where
         'a: 'b,
     {
         || {}
+        //~^ ERROR lifetime bound not satisfied
     }
 }
 
 // Same as the above but through indirection `'x`
 mod test2 {
     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
-    //~^ ERROR cannot infer an appropriate lifetime
 
     fn define<'a, 'b, 'x>() -> Opaque<'a, 'b>
     where
@@ -33,6 +32,7 @@ mod test2 {
         'x: 'b,
     {
         || {}
+        //~^ ERROR cannot infer an appropriate lifetime
     }
 }
 
@@ -52,13 +52,13 @@ mod test2_fixed {
 // requires `T: 'static`
 mod test3 {
     type Opaque<T> = impl Sized;
-    //~^ ERROR the parameter type `T` may not live long enough
 
     fn define<T>() -> Opaque<T>
     where
         T: 'static,
     {
         || {}
+        //~^ ERROR the parameter type `T` may not live long enough
     }
 }
 
diff --git a/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr b/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
index 3484485e3fd..04288112fa8 100644
--- a/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
+++ b/tests/ui/type-alias-impl-trait/closure_wf_outlives.stderr
@@ -1,8 +1,8 @@
 error[E0478]: lifetime bound not satisfied
-  --> $DIR/closure_wf_outlives.rs:14:27
+  --> $DIR/closure_wf_outlives.rs:20:9
    |
-LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
-   |                           ^^^^^^^^^^^^^^^^^^^^
+LL |         || {}
+   |         ^^^^^
    |
 note: lifetime parameter instantiated with the lifetime `'a` as defined here
   --> $DIR/closure_wf_outlives.rs:14:17
@@ -16,10 +16,10 @@ LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
    |                     ^^
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/closure_wf_outlives.rs:27:27
+  --> $DIR/closure_wf_outlives.rs:34:9
    |
-LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
-   |                           ^^^^^^^^^^^^^^^^^^^^
+LL |         || {}
+   |         ^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
   --> $DIR/closure_wf_outlives.rs:27:17
@@ -27,32 +27,32 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
 LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
    |                 ^^
 note: ...so that the declared lifetime parameter bounds are satisfied
-  --> $DIR/closure_wf_outlives.rs:27:27
+  --> $DIR/closure_wf_outlives.rs:34:9
    |
-LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
-   |                           ^^^^^^^^^^^^^^^^^^^^
+LL |         || {}
+   |         ^^^^^
 note: but, the lifetime must be valid for the lifetime `'b` as defined here...
   --> $DIR/closure_wf_outlives.rs:27:21
    |
 LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
    |                     ^^
 note: ...so that the declared lifetime parameter bounds are satisfied
-  --> $DIR/closure_wf_outlives.rs:27:27
+  --> $DIR/closure_wf_outlives.rs:34:9
    |
-LL |     type Opaque<'a, 'b> = impl Sized + 'a + 'b;
-   |                           ^^^^^^^^^^^^^^^^^^^^
+LL |         || {}
+   |         ^^^^^
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/closure_wf_outlives.rs:54:22
+  --> $DIR/closure_wf_outlives.rs:60:9
    |
-LL |     type Opaque<T> = impl Sized;
-   |                      ^^^^^^^^^^
-   |                      |
-   |                      the parameter type `T` must be valid for the static lifetime...
-   |                      ...so that the type `T` will meet its required lifetime bounds...
+LL |         || {}
+   |         ^^^^^
+   |         |
+   |         the parameter type `T` must be valid for the static lifetime...
+   |         ...so that the type `T` will meet its required lifetime bounds...
    |
 note: ...that is required by this bound
-  --> $DIR/closure_wf_outlives.rs:59:12
+  --> $DIR/closure_wf_outlives.rs:58:12
    |
 LL |         T: 'static,
    |            ^^^^^^^
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
index d2d6380b65a..af6e6e1e66e 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr
@@ -4,6 +4,16 @@ error[E0277]: `T` doesn't implement `Debug`
 LL |     t
    |     ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
+note: required by a bound in an opaque type
+  --> $DIR/generic_duplicate_param_use2.rs:8:23
+   |
+LL | type Two<T, U> = impl Debug;
+   |                       ^^^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/generic_duplicate_param_use2.rs:10:1
+   |
+LL | fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `T`
    |
 LL | type Two<T: std::fmt::Debug, U> = impl Debug;
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
index e7a25fc7240..2074f12750f 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs
@@ -9,10 +9,9 @@ type Two<T, U> = impl Debug;
 
 fn two<T: Debug, U>(t: T, _: U) -> Two<T, U> {
     t
-    //~^ ERROR `T` doesn't implement `Debug`
 }
 
 fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
     u
-    //~^ ERROR `U` doesn't implement `Debug`
+    //~^ ERROR concrete type differs
 }
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
index 7bec3822071..9a10a4980d8 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr
@@ -1,25 +1,14 @@
-error[E0277]: `T` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use3.rs:11:5
-   |
-LL |     t
-   |     ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | type Two<T: std::fmt::Debug, U> = impl Debug;
-   |           +++++++++++++++++
-
-error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use3.rs:16:5
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/generic_duplicate_param_use3.rs:15:5
    |
 LL |     u
-   |     ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |     ^ expected `T`, got `U`
    |
-help: consider restricting type parameter `U`
+note: previous use here
+  --> $DIR/generic_duplicate_param_use3.rs:11:5
    |
-LL | type Two<T, U: std::fmt::Debug> = impl Debug;
-   |              +++++++++++++++++
+LL |     t
+   |     ^
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
index 2338dbd522b..a847bed93da 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr
@@ -4,6 +4,16 @@ error[E0277]: `U` doesn't implement `Debug`
 LL |     u
    |     ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
    |
+note: required by a bound in an opaque type
+  --> $DIR/generic_duplicate_param_use4.rs:8:23
+   |
+LL | type Two<T, U> = impl Debug;
+   |                       ^^^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/generic_duplicate_param_use4.rs:10:1
+   |
+LL | fn three<T, U: Debug>(_: T, u: U) -> Two<T, U> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `U`
    |
 LL | type Two<T, U: std::fmt::Debug> = impl Debug;
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
index 3bd1dda6331..b3d6beaf848 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.rs
@@ -9,12 +9,9 @@ type Two<T, U> = impl Debug;
 
 fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
     (t, u)
-    //~^ ERROR `T` doesn't implement `Debug`
-    //~| ERROR `U` doesn't implement `Debug`
 }
 
 fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
     (u, t)
-    //~^ ERROR `T` doesn't implement `Debug`
-    //~| ERROR `U` doesn't implement `Debug`
+    //~^ ERROR concrete type differs
 }
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
index 586ea82342a..b0027f8fa57 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use5.stderr
@@ -1,51 +1,14 @@
-error[E0277]: `T` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use5.rs:11:5
-   |
-LL |     (t, u)
-   |     ^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/generic_duplicate_param_use5.rs:15:5
    |
-   = note: required for `(T, U)` to implement `Debug`
-help: consider restricting type parameter `T`
+LL |     (u, t)
+   |     ^^^^^^ expected `(T, U)`, got `(U, T)`
    |
-LL | type Two<T: std::fmt::Debug, U> = impl Debug;
-   |           +++++++++++++++++
-
-error[E0277]: `U` doesn't implement `Debug`
+note: previous use here
   --> $DIR/generic_duplicate_param_use5.rs:11:5
    |
 LL |     (t, u)
-   |     ^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(T, U)` to implement `Debug`
-help: consider restricting type parameter `U`
-   |
-LL | type Two<T, U: std::fmt::Debug> = impl Debug;
-   |              +++++++++++++++++
-
-error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use5.rs:17:5
-   |
-LL |     (u, t)
-   |     ^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(U, T)` to implement `Debug`
-help: consider restricting type parameter `U`
-   |
-LL | type Two<T, U: std::fmt::Debug> = impl Debug;
-   |              +++++++++++++++++
-
-error[E0277]: `T` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use5.rs:17:5
-   |
-LL |     (u, t)
-   |     ^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(U, T)` to implement `Debug`
-help: consider restricting type parameter `T`
-   |
-LL | type Two<T: std::fmt::Debug, U> = impl Debug;
-   |           +++++++++++++++++
+   |     ^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
index 5120925e5a4..fa8b2a290b9 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs
@@ -9,11 +9,9 @@ type Two<T, U> = impl Debug;
 
 fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
     (t, t)
-    //~^ ERROR `T` doesn't implement `Debug`
 }
 
 fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
     (u, t)
-    //~^ ERROR `T` doesn't implement `Debug`
-    //~| ERROR `U` doesn't implement `Debug`
+    //~^ ERROR concrete type differs
 }
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
index cb162d382b6..09c01932cef 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr
@@ -1,39 +1,14 @@
-error[E0277]: `T` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use6.rs:11:5
-   |
-LL |     (t, t)
-   |     ^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(T, T)` to implement `Debug`
-help: consider restricting type parameter `T`
-   |
-LL | type Two<T: std::fmt::Debug, U> = impl Debug;
-   |           +++++++++++++++++
-
-error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use6.rs:16:5
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/generic_duplicate_param_use6.rs:15:5
    |
 LL |     (u, t)
-   |     ^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(U, T)` to implement `Debug`
-help: consider restricting type parameter `U`
+   |     ^^^^^^ expected `(T, T)`, got `(U, T)`
    |
-LL | type Two<T, U: std::fmt::Debug> = impl Debug;
-   |              +++++++++++++++++
-
-error[E0277]: `T` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use6.rs:16:5
-   |
-LL |     (u, t)
-   |     ^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(U, T)` to implement `Debug`
-help: consider restricting type parameter `T`
+note: previous use here
+  --> $DIR/generic_duplicate_param_use6.rs:11:5
    |
-LL | type Two<T: std::fmt::Debug, U> = impl Debug;
-   |           +++++++++++++++++
+LL |     (t, t)
+   |     ^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
index 3a4b5047b41..76c13bb027b 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.rs
@@ -8,10 +8,9 @@ type Two<T, U> = impl Debug;
 
 fn two<T: Debug, U: Debug>(t: T, _: U) -> Two<T, U> {
     (t, 4u32)
-    //~^ ERROR `T` doesn't implement `Debug`
 }
 
 fn three<T: Debug, U: Debug>(_: T, u: U) -> Two<T, U> {
     (u, 4u32)
-    //~^ ERROR `U` doesn't implement `Debug`
+    //~^ concrete type differs
 }
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
index 14cbfb3806f..09d2abe3663 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use8.stderr
@@ -1,27 +1,14 @@
-error[E0277]: `T` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use8.rs:10:5
-   |
-LL |     (t, 4u32)
-   |     ^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(T, u32)` to implement `Debug`
-help: consider restricting type parameter `T`
-   |
-LL | type Two<T: std::fmt::Debug, U> = impl Debug;
-   |           +++++++++++++++++
-
-error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use8.rs:15:5
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/generic_duplicate_param_use8.rs:14:5
    |
 LL |     (u, 4u32)
-   |     ^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |     ^^^^^^^^^ expected `(T, u32)`, got `(U, u32)`
    |
-   = note: required for `(U, u32)` to implement `Debug`
-help: consider restricting type parameter `U`
+note: previous use here
+  --> $DIR/generic_duplicate_param_use8.rs:10:5
    |
-LL | type Two<T, U: std::fmt::Debug> = impl Debug;
-   |              +++++++++++++++++
+LL |     (t, 4u32)
+   |     ^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
index 6afcdfe4d1c..5da7aab0da7 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.rs
@@ -13,13 +13,9 @@ trait Foo {
 
 fn two<T: Debug + Foo, U: Debug>(t: T, u: U) -> Two<T, U> {
     (t, u, T::BAR)
-    //~^ ERROR the trait bound `A: Foo` is not satisfied
-    //~| ERROR `A` doesn't implement `Debug`
-    //~| ERROR `B` doesn't implement `Debug`
 }
 
 fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
     (t, u, 42)
-    //~^ ERROR `A` doesn't implement `Debug`
-    //~| ERROR `B` doesn't implement `Debug`
+    //~^ ERROR concrete type differs
 }
diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
index 722693e4266..6e1bb3dfa17 100644
--- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr
@@ -1,62 +1,14 @@
-error[E0277]: the trait bound `A: Foo` is not satisfied
-  --> $DIR/generic_duplicate_param_use9.rs:15:5
-   |
-LL |     (t, u, T::BAR)
-   |     ^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A`
-   |
-help: consider restricting type parameter `A`
-   |
-LL | type Two<A: Foo, B> = impl Debug;
-   |           +++++
-
-error[E0277]: `A` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use9.rs:15:5
-   |
-LL |     (t, u, T::BAR)
-   |     ^^^^^^^^^^^^^^ `A` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/generic_duplicate_param_use9.rs:19:5
    |
-   = note: required for `(A, B, _)` to implement `Debug`
-help: consider restricting type parameter `A`
+LL |     (t, u, 42)
+   |     ^^^^^^^^^^ expected `(A, B, <A as Foo>::Bar)`, got `(A, B, i32)`
    |
-LL | type Two<A: std::fmt::Debug, B> = impl Debug;
-   |           +++++++++++++++++
-
-error[E0277]: `B` doesn't implement `Debug`
+note: previous use here
   --> $DIR/generic_duplicate_param_use9.rs:15:5
    |
 LL |     (t, u, T::BAR)
-   |     ^^^^^^^^^^^^^^ `B` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(A, B, _)` to implement `Debug`
-help: consider restricting type parameter `B`
-   |
-LL | type Two<A, B: std::fmt::Debug> = impl Debug;
-   |              +++++++++++++++++
-
-error[E0277]: `A` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use9.rs:22:5
-   |
-LL |     (t, u, 42)
-   |     ^^^^^^^^^^ `A` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(A, B, i32)` to implement `Debug`
-help: consider restricting type parameter `A`
-   |
-LL | type Two<A: std::fmt::Debug, B> = impl Debug;
-   |           +++++++++++++++++
-
-error[E0277]: `B` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use9.rs:22:5
-   |
-LL |     (t, u, 42)
-   |     ^^^^^^^^^^ `B` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(A, B, i32)` to implement `Debug`
-help: consider restricting type parameter `B`
-   |
-LL | type Two<A, B: std::fmt::Debug> = impl Debug;
-   |              +++++++++++++++++
+   |     ^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr b/tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr
index b05121a489e..be68bac5575 100644
--- a/tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr
+++ b/tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr
@@ -21,6 +21,20 @@ LL |     impl<T: Proj<Assoc = i32> + Copy> Copy for Bar<T> {}
    |                  -----------          ^^^^     ^^^^^^
    |                  |
    |                  unsatisfied trait bound introduced here
+note: required by a bound in an opaque type
+  --> $DIR/hidden_type_mismatch.rs:36:26
+   |
+LL |     pub type Tait = impl Copy + From<Bar<()>> + Into<Bar<()>>;
+   |                          ^^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/hidden_type_mismatch.rs:37:5
+   |
+LL | /     pub fn define_tait() -> Tait
+LL | |     where
+LL | |         // this proves `Bar<()>: Copy`, but `define_tait` is
+LL | |         // now uncallable
+LL | |         (): Proj<Assoc = i32>,
+   | |______________________________^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs
index f8b09814caa..7b2bbc99530 100644
--- a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs
+++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.rs
@@ -2,9 +2,9 @@
 
 mod test_type_param_static {
     pub type Ty<A> = impl Sized + 'static;
-    //~^ ERROR: the parameter type `A` may not live long enough
     fn defining<A: 'static>(s: A) -> Ty<A> {
         s
+        //~^ ERROR: the parameter type `A` may not live long enough
     }
     pub fn assert_static<A: 'static>() {}
 }
diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
index f2e5e95b96f..f23b978d0b6 100644
--- a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
+++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr
@@ -1,12 +1,17 @@
 error[E0310]: the parameter type `A` may not live long enough
-  --> $DIR/implied_lifetime_wf_check4_static.rs:4:22
+  --> $DIR/implied_lifetime_wf_check4_static.rs:6:9
    |
-LL |     pub type Ty<A> = impl Sized + 'static;
-   |                      ^^^^^^^^^^^^^^^^^^^^
-   |                      |
-   |                      the parameter type `A` must be valid for the static lifetime...
-   |                      ...so that the type `A` will meet its required lifetime bounds
+LL |         s
+   |         ^
+   |         |
+   |         the parameter type `A` must be valid for the static lifetime...
+   |         ...so that the type `A` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/implied_lifetime_wf_check4_static.rs:4:35
    |
+LL |     pub type Ty<A> = impl Sized + 'static;
+   |                                   ^^^^^^^
 help: consider adding an explicit lifetime bound
    |
 LL |     pub type Ty<A: 'static> = impl Sized + 'static;
diff --git a/tests/ui/type-alias-impl-trait/issue-52843.stderr b/tests/ui/type-alias-impl-trait/issue-52843.stderr
index ea4c5297ad5..a6bdddbc98c 100644
--- a/tests/ui/type-alias-impl-trait/issue-52843.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-52843.stderr
@@ -4,6 +4,16 @@ error[E0277]: the trait bound `T: Default` is not satisfied
 LL |     t
    |     ^ the trait `Default` is not implemented for `T`
    |
+note: required by a bound in an opaque type
+  --> $DIR/issue-52843.rs:3:20
+   |
+LL | type Foo<T> = impl Default;
+   |                    ^^^^^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/issue-52843.rs:6:1
+   |
+LL | fn foo<T: Default>(t: T) -> Foo<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `T`
    |
 LL | type Foo<T: std::default::Default> = impl Default;
diff --git a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr
index b4b78f8175f..4a6a62bdf96 100644
--- a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr
@@ -4,11 +4,23 @@ error[E0277]: the trait bound `B: Bar` is not satisfied
 LL |         MyBaz(bar)
    |         ^^^^^^^^^^ the trait `Bar` is not implemented for `B`
    |
-note: required by a bound in `MyBaz`
-  --> $DIR/issue-90400-2.rs:29:17
+note: required for `MyBaz<B>` to implement `Baz`
+  --> $DIR/issue-90400-2.rs:30:14
    |
-LL | struct MyBaz<B: Bar>(B);
-   |                 ^^^ required by this bound in `MyBaz`
+LL | impl<B: Bar> Baz for MyBaz<B> {
+   |         ---  ^^^     ^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in an opaque type
+  --> $DIR/issue-90400-2.rs:22:26
+   |
+LL |     type FooFn<B> = impl Baz;
+   |                          ^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/issue-90400-2.rs:24:5
+   |
+LL |     fn foo<B: Bar>(&self, bar: B) -> Self::FooFn<B> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `B`
    |
 LL |     type FooFn<B: Bar> = impl Baz;
diff --git a/tests/ui/type-alias-impl-trait/not_a_defining_use.rs b/tests/ui/type-alias-impl-trait/not_a_defining_use.rs
index fa47d13f516..b5ef1470629 100644
--- a/tests/ui/type-alias-impl-trait/not_a_defining_use.rs
+++ b/tests/ui/type-alias-impl-trait/not_a_defining_use.rs
@@ -8,7 +8,6 @@ type Two<T, U> = impl Debug;
 
 fn three<T: Debug, U>(t: T) -> Two<T, U> {
     (t, 5i8)
-    //~^ ERROR `T` doesn't implement `Debug`
 }
 
 trait Bar {
@@ -23,8 +22,7 @@ impl Bar for u32 {
 
 fn four<T: Debug, U: Bar>(t: T) -> Two<T, U> {
     (t, <U as Bar>::FOO)
-    //~^ ERROR `U: Bar` is not satisfied
-    //~| ERROR `T` doesn't implement `Debug`
+    //~^ ERROR concrete type differs
 }
 
 fn is_sync<T: Sync>() {}
diff --git a/tests/ui/type-alias-impl-trait/not_a_defining_use.stderr b/tests/ui/type-alias-impl-trait/not_a_defining_use.stderr
index b11198c584c..b59f9c49b07 100644
--- a/tests/ui/type-alias-impl-trait/not_a_defining_use.stderr
+++ b/tests/ui/type-alias-impl-trait/not_a_defining_use.stderr
@@ -1,38 +1,14 @@
-error[E0277]: `T` doesn't implement `Debug`
-  --> $DIR/not_a_defining_use.rs:10:5
-   |
-LL |     (t, 5i8)
-   |     ^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(T, i8)` to implement `Debug`
-help: consider restricting type parameter `T`
-   |
-LL | type Two<T: std::fmt::Debug, U> = impl Debug;
-   |           +++++++++++++++++
-
-error[E0277]: the trait bound `U: Bar` is not satisfied
-  --> $DIR/not_a_defining_use.rs:25:5
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/not_a_defining_use.rs:24:5
    |
 LL |     (t, <U as Bar>::FOO)
-   |     ^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `U`
-   |
-help: consider restricting type parameter `U`
+   |     ^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, <U as Bar>::Blub)`
    |
-LL | type Two<T, U: Bar> = impl Debug;
-   |              +++++
-
-error[E0277]: `T` doesn't implement `Debug`
-  --> $DIR/not_a_defining_use.rs:25:5
-   |
-LL |     (t, <U as Bar>::FOO)
-   |     ^^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-   = note: required for `(T, _)` to implement `Debug`
-help: consider restricting type parameter `T`
+note: previous use here
+  --> $DIR/not_a_defining_use.rs:10:5
    |
-LL | type Two<T: std::fmt::Debug, U> = impl Debug;
-   |           +++++++++++++++++
+LL |     (t, 5i8)
+   |     ^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
index e4de9245951..48cef847fbb 100644
--- a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
+++ b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
@@ -11,6 +11,16 @@ LL | impl<X: Trait> ProofForConversion<X> for () {
    |         -----  ^^^^^^^^^^^^^^^^^^^^^     ^^
    |         |
    |         unsatisfied trait bound introduced here
+note: required by a bound in an opaque type
+  --> $DIR/underconstrained_generic.rs:19:26
+   |
+LL | type Converter<T> = impl ProofForConversion<T>;
+   |                          ^^^^^^^^^^^^^^^^^^^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/underconstrained_generic.rs:21:1
+   |
+LL | fn _defining_use<T: Trait>() -> Converter<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `T`
    |
 LL | type Converter<T: Trait> = impl ProofForConversion<T>;
diff --git a/tests/ui/type-alias-impl-trait/underconstrained_lifetime.rs b/tests/ui/type-alias-impl-trait/underconstrained_lifetime.rs
index c5b2e8a1c5e..e8e7dd0ea08 100644
--- a/tests/ui/type-alias-impl-trait/underconstrained_lifetime.rs
+++ b/tests/ui/type-alias-impl-trait/underconstrained_lifetime.rs
@@ -13,11 +13,11 @@ impl<'a, 'b> ProofForConversion<'a, 'b> for &'b &'a () {
 }
 
 type Converter<'a, 'b> = impl ProofForConversion<'a, 'b>;
-//~^ ERROR reference has a longer lifetime than the data it references
 
 // Even _defining_use with an explicit `'a: 'b` compiles fine, too.
 fn _defining_use<'a, 'b>(x: &'b &'a ()) -> Converter<'a, 'b> {
     x
+    //~^ ERROR reference has a longer lifetime than the data it references
 }
 
 fn extend_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
diff --git a/tests/ui/type-alias-impl-trait/underconstrained_lifetime.stderr b/tests/ui/type-alias-impl-trait/underconstrained_lifetime.stderr
index 34b50fb1f05..7c07578d887 100644
--- a/tests/ui/type-alias-impl-trait/underconstrained_lifetime.stderr
+++ b/tests/ui/type-alias-impl-trait/underconstrained_lifetime.stderr
@@ -1,8 +1,8 @@
 error[E0491]: in type `&'b &'a ()`, reference has a longer lifetime than the data it references
-  --> $DIR/underconstrained_lifetime.rs:15:26
+  --> $DIR/underconstrained_lifetime.rs:19:5
    |
-LL | type Converter<'a, 'b> = impl ProofForConversion<'a, 'b>;
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     x
+   |     ^
    |
 note: the pointer is valid for the lifetime `'b` as defined here
   --> $DIR/underconstrained_lifetime.rs:15:20
diff --git a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr
index c4ad8434ed1..34648a420ac 100644
--- a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr
+++ b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr
@@ -1,23 +1,30 @@
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/wf-in-associated-type.rs:38:23
+  --> $DIR/wf-in-associated-type.rs:40:13
    |
 LL |     impl<'a, T> Trait<'a, T> for () {
    |          -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
-LL |         type Opaque = impl Sized + 'a;
-   |                       ^^^^^^^^^^^^^^^ ...so that the type `&'a T` will meet its required lifetime bounds
+...
+LL |             req
+   |             ^^^ ...so that the type `&'a T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/wf-in-associated-type.rs:38:36
    |
+LL |         type Opaque = impl Sized + 'a;
+   |                                    ^^
 help: consider adding an explicit lifetime bound
    |
 LL |     impl<'a, T: 'a> Trait<'a, T> for () {
    |               ++++
 
 error[E0309]: the parameter type `T` may not live long enough
-  --> $DIR/wf-in-associated-type.rs:38:23
+  --> $DIR/wf-in-associated-type.rs:40:13
    |
 LL |     impl<'a, T> Trait<'a, T> for () {
    |          -- the parameter type `T` must be valid for the lifetime `'a` as defined here...
-LL |         type Opaque = impl Sized + 'a;
-   |                       ^^^^^^^^^^^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at
+...
+LL |             req
+   |             ^^^ ...so that the reference type `&'a T` does not outlive the data it points at
    |
 help: consider adding an explicit lifetime bound
    |
diff --git a/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs b/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs
index c20be3125bc..e548609e89a 100644
--- a/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs
+++ b/tests/ui/type-alias-impl-trait/wf-in-associated-type.rs
@@ -36,10 +36,10 @@ mod fail {
 
     impl<'a, T> Trait<'a, T> for () {
         type Opaque = impl Sized + 'a;
-        //[fail]~^ ERROR the parameter type `T` may not live long enough
-        //[fail]~| ERROR the parameter type `T` may not live long enough
         fn constrain_opaque(req: &'a T) -> Self::Opaque {
             req
+            //[fail]~^ ERROR the parameter type `T` may not live long enough
+            //[fail]~| ERROR the parameter type `T` may not live long enough
         }
     }
 }
diff --git a/triagebot.toml b/triagebot.toml
index 45b580787d1..95538dd7ee3 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -432,6 +432,7 @@ new_issue = true
 exclude_labels = [
     "C-tracking-issue",
     "A-diagnostics",
+    "relnotes-tracking-issue",
 ]
 
 [autolabel."WG-trait-system-refactor"]