about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bootstrap.example.toml8
-rw-r--r--compiler/rustc/Cargo.toml1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/crate_level.rs9
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs4
-rw-r--r--compiler/rustc_borrowck/src/lib.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs6
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml5
-rw-r--r--compiler/rustc_builtin_macros/src/autodiff.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs9
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/autodiff.rs44
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs73
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs91
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/meth.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs2
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs35
-rw-r--r--compiler/rustc_data_structures/src/sorted_map/tests.rs10
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/attrs/data_structures.rs6
-rw-r--r--compiler/rustc_hir/src/attrs/encode_cross_crate.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/dump.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs (renamed from compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs)558
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs533
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs19
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs4
-rw-r--r--compiler/rustc_lint/src/types.rs2
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp38
-rw-r--r--compiler/rustc_middle/src/hir/map.rs2
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs9
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs9
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs111
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs17
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs24
-rw-r--r--compiler/rustc_middle/src/ty/significant_drop_order.rs2
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs14
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs14
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs28
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lint.rs44
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs234
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs12
-rw-r--r--compiler/rustc_passes/src/check_attr.rs2
-rw-r--r--compiler/rustc_passes/src/check_export.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs2
-rw-r--r--compiler/rustc_public/src/ty.rs11
-rw-r--r--compiler/rustc_public/src/unstable/convert/internal.rs19
-rw-r--r--compiler/rustc_public/src/unstable/convert/stable/ty.rs27
-rw-r--r--compiler/rustc_public/src/visitor.rs2
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs6
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs8
-rw-r--r--compiler/rustc_symbol_mangling/src/export.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs12
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs2
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs4
-rw-r--r--compiler/rustc_type_ir/src/flags.rs2
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs9
-rw-r--r--compiler/rustc_type_ir/src/lib.rs1
-rw-r--r--compiler/rustc_type_ir/src/outlives.rs2
-rw-r--r--compiler/rustc_type_ir/src/relate.rs15
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs22
-rw-r--r--compiler/rustc_type_ir/src/walk.rs2
-rw-r--r--library/alloc/src/boxed.rs2
-rw-r--r--library/std/src/sys/args/zkvm.rs103
-rw-r--r--src/bootstrap/bootstrap.py6
-rwxr-xr-xsrc/bootstrap/configure.py5
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs4
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs6
-rw-r--r--src/bootstrap/src/core/config/config.rs5
-rw-r--r--src/bootstrap/src/core/config/toml/rust.rs2
-rw-r--r--src/bootstrap/src/lib.rs6
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/display.rs6
-rw-r--r--src/librustdoc/html/format.rs107
-rw-r--r--src/librustdoc/html/render/mod.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs4
-rw-r--r--tests/codegen-llvm/autodiff/abi_handling.rs210
-rw-r--r--tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-abort.diff (renamed from tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-abort.diff)31
-rw-r--r--tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-unwind.diff (renamed from tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff)31
-rw-r--r--tests/mir-opt/dest-prop/nrvo_borrowed.rs (renamed from tests/mir-opt/nrvo_simple.rs)4
-rw-r--r--tests/mir-opt/dest-prop/nrvo_miscompile_111005.rs (renamed from tests/mir-opt/nrvo_miscompile_111005.rs)7
-rw-r--r--tests/mir-opt/dest-prop/nrvo_miscompile_111005.wrong.DestinationPropagation.diff (renamed from tests/mir-opt/nrvo_miscompile_111005.wrong.RenameReturnPlace.diff)7
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.rs3
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir35
-rw-r--r--tests/mir-opt/pre-codegen/derived_ord.rs5
-rw-r--r--tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir32
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir68
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir68
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir240
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir70
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir182
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir182
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir54
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir54
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir72
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir72
-rw-r--r--tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir18
-rw-r--r--tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir18
-rw-r--r--tests/ui/autodiff/zst.rs17
-rw-r--r--tests/ui/issues/issue-18088.rs8
-rw-r--r--tests/ui/issues/issue-21950.rs12
-rw-r--r--tests/ui/issues/issue-2284.rs13
-rw-r--r--tests/ui/mir/lint/assignment-overlap.rs2
-rw-r--r--tests/ui/traits/associated_type_bound/assoc-type-via-another-trait-issue-19479.rs (renamed from tests/ui/issues/issue-19479.rs)6
-rw-r--r--tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs19
-rw-r--r--tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.stderr (renamed from tests/ui/issues/issue-21950.stderr)2
-rw-r--r--tests/ui/traits/core-marker-name-shadowing-issue-2284.rs21
-rw-r--r--tests/ui/traits/inheritance/supertrait-operator-issue-18088.rs13
162 files changed, 2066 insertions, 2180 deletions
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index eac93957797..51529751dd5 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -859,6 +859,14 @@
 # Trigger a `DebugBreak` after an internal compiler error during bootstrap on Windows
 #rust.break-on-ice = true
 
+# Set the number of threads for the compiler frontend used during compilation of Rust code (passed to `-Zthreads`).
+# The valid options are:
+# 0 - Set the number of threads according to the detected number of threads of the host system
+# 1 - Use a single thread for compilation of Rust code (the default)
+# N - Number of threads used for compilation of Rust code
+#
+#rust.parallel-frontend-threads = 1
+
 # =============================================================================
 # Distribution options
 #
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index e3214d1ab9c..9ef8fa75062 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -30,6 +30,7 @@ features = ['unprefixed_malloc_on_supported_platforms']
 check_only = ['rustc_driver_impl/check_only']
 jemalloc = ['dep:tikv-jemalloc-sys']
 llvm = ['rustc_driver_impl/llvm']
+llvm_enzyme = ['rustc_driver_impl/llvm_enzyme']
 max_level_info = ['rustc_driver_impl/max_level_info']
 rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
 # tidy-alphabetical-end
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 4611de44459..0a340cd5e93 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -174,3 +174,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
 }
+
+pub(crate) struct RustcCoherenceIsCoreParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
+    const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index c756bce96e2..ced3bcad229 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -149,14 +149,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
 }
 
-pub(crate) struct CoherenceIsCoreParser;
-impl<S: Stage> NoArgsAttributeParser<S> for CoherenceIsCoreParser {
-    const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
-    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
-    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore;
-}
-
 pub(crate) struct FundamentalParser;
 impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
     const PATH: &[Symbol] = &[sym::fundamental];
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 58b13292484..ee5b7322b02 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -26,7 +26,7 @@ use crate::attributes::codegen_attrs::{
 use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::crate_level::{
     CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
-    RecursionLimitParser, TypeLengthLimitParser,
+    RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
 };
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::dummy::DummyParser;
@@ -61,10 +61,10 @@ use crate::attributes::stability::{
 };
 use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
 use crate::attributes::traits::{
-    AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser,
-    DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser,
-    ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser,
-    TypeConstParser, UnsafeSpecializationMarkerParser,
+    AllowIncoherentImplParser, CoinductiveParser, ConstTraitParser, DenyExplicitImplParser,
+    DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
+    PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
+    UnsafeSpecializationMarkerParser,
 };
 use crate::attributes::transparency::TransparencyParser;
 use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
@@ -206,7 +206,6 @@ attribute_parsers!(
         Single<WithoutArgs<AllowInternalUnsafeParser>>,
         Single<WithoutArgs<AsPtrParser>>,
         Single<WithoutArgs<AutomaticallyDerivedParser>>,
-        Single<WithoutArgs<CoherenceIsCoreParser>>,
         Single<WithoutArgs<CoinductiveParser>>,
         Single<WithoutArgs<ColdParser>>,
         Single<WithoutArgs<ConstContinueParser>>,
@@ -234,6 +233,7 @@ attribute_parsers!(
         Single<WithoutArgs<ProcMacroAttributeParser>>,
         Single<WithoutArgs<ProcMacroParser>>,
         Single<WithoutArgs<PubTransparentParser>>,
+        Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
         Single<WithoutArgs<SpecializationTraitParser>>,
         Single<WithoutArgs<StdInternalSymbolParser>>,
         Single<WithoutArgs<TrackCallerParser>>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index fda96dde826..7ca07bb9b43 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -438,7 +438,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
 
             let elaborated_args =
                 std::iter::zip(*args, &generics.own_params).map(|(arg, param)| {
-                    if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
+                    if let Some(ty::Dynamic(obj, _)) = arg.as_type().map(Ty::kind) {
                         let default = tcx.object_lifetime_default(param.def_id);
 
                         let re_static = tcx.lifetimes.re_static;
@@ -464,7 +464,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
 
                         has_dyn = true;
 
-                        Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
+                        Ty::new_dynamic(tcx, obj, implied_region).into()
                     } else {
                         arg
                     }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index f196bd04d0e..4c380ddcf70 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1903,7 +1903,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     | ty::Slice(_)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(..)
-                    | ty::Dynamic(_, _, _)
+                    | ty::Dynamic(_, _)
                     | ty::Closure(_, _)
                     | ty::CoroutineClosure(_, _)
                     | ty::Coroutine(_, _)
@@ -1949,7 +1949,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     | ty::Ref(_, _, _)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(..)
-                    | ty::Dynamic(_, _, _)
+                    | ty::Dynamic(_, _)
                     | ty::CoroutineWitness(..)
                     | ty::Never
                     | ty::UnsafeBinder(_)
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index dcedf0b1532..19cbcd139aa 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1487,9 +1487,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                                     unsize_to: None,
                                 },
                             );
-                        } else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) =
+                        } else if let ty::Dynamic(src_tty, _src_lt) =
                             *self.struct_tail(src.ty, location).kind()
-                            && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) =
+                            && let ty::Dynamic(dst_tty, dst_lt) =
                                 *self.struct_tail(dst.ty, location).kind()
                             && src_tty.principal().is_some()
                             && dst_tty.principal().is_some()
@@ -1511,7 +1511,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                                 // FIXME: Once we disallow casting `*const dyn Trait + 'short`
                                 // to `*const dyn Trait + 'long`, then this can just be `src_lt`.
                                 dst_lt,
-                                ty::Dyn,
                             );
                             let dst_obj = Ty::new_dynamic(
                                 tcx,
@@ -1519,7 +1518,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                                     &dst_tty.without_auto_traits().collect::<Vec<_>>(),
                                 ),
                                 dst_lt,
-                                ty::Dyn,
                             );
 
                             debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index e56b9e641a1..ce9a3ce3f24 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -33,3 +33,8 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 thin-vec = "0.2.12"
 tracing = "0.1"
 # tidy-alphabetical-end
+
+[features]
+# tidy-alphabetical-start
+llvm_enzyme = []
+# tidy-alphabetical-end
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index 48d0795af5e..f4a923797e2 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -209,7 +209,8 @@ mod llvm_enzyme {
         mut item: Annotatable,
         mode: DiffMode,
     ) -> Vec<Annotatable> {
-        if cfg!(not(llvm_enzyme)) {
+        // FIXME(bjorn3) maybe have the backend directly tell if autodiff is supported?
+        if cfg!(not(feature = "llvm_enzyme")) {
             ecx.sess.dcx().emit_err(errors::AutoDiffSupportNotBuild { span: meta_item.span });
             return vec![item];
         }
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 7d0731c77bd..29ee46194de 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -715,7 +715,7 @@ pub(crate) fn codegen_drop<'tcx>(
         fx.bcx.ins().jump(ret_block, &[]);
     } else {
         match ty.kind() {
-            ty::Dynamic(_, _, ty::Dyn) => {
+            ty::Dynamic(_, _) => {
                 // IN THIS ARM, WE HAVE:
                 // ty = *mut (dyn Trait)
                 // which is: exists<T> ( *mut T,    Vtable<T: Trait> )
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 2aee0b2e974..643c7feb89a 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -30,9 +30,7 @@ pub(crate) fn unsized_info<'tcx>(
             fx.pointer_type,
             len.try_to_target_usize(fx.tcx).expect("expected monomorphic const in codegen") as i64,
         ),
-        (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
-            if src_dyn_kind == target_dyn_kind =>
-        {
+        (&ty::Dynamic(data_a, _), &ty::Dynamic(data_b, _)) => {
             let old_info =
                 old_info.expect("unsized_info: missing old info for trait upcasting coercion");
             let b_principal_def_id = data_b.principal_def_id();
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 9d73f200afe..4519fa1a270 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -909,8 +909,7 @@ pub(crate) fn assert_assignable<'tcx>(
             );
             // fn(&T) -> for<'l> fn(&'l T) is allowed
         }
-        (&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => {
-            // FIXME(dyn-star): Do the right thing with DynKinds
+        (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => {
             for (from, to) in from_traits.iter().zip(to_traits) {
                 let from = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), from);
                 let to = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to);
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index eb0a5336a1f..84fa56cf903 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -730,7 +730,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
         if self.is_sized_indirect() {
             OperandValue::Ref(PlaceValue::new_sized(val, self.layout.align.abi)).store(bx, dst)
         } else if self.is_unsized_indirect() {
-            bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
+            bug!("unsized `ArgAbi` cannot be stored");
         } else if let PassMode::Cast { ref cast, .. } = self.mode {
             // FIXME(eddyb): Figure out when the simpler Store is safe, clang
             // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
@@ -797,12 +797,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 OperandValue::Pair(next(), next()).store(bx, dst);
             }
             PassMode::Indirect { meta_attrs: Some(_), .. } => {
-                let place_val = PlaceValue {
-                    llval: next(),
-                    llextra: Some(next()),
-                    align: self.layout.align.abi,
-                };
-                OperandValue::Ref(place_val).store(bx, dst);
+                bug!("unsized `ArgAbi` cannot be stored");
             }
             PassMode::Direct(_)
             | PassMode::Indirect { meta_attrs: None, .. }
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 2d11628250c..67bd1e59bb0 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -46,5 +46,6 @@ tracing = "0.1"
 [features]
 # tidy-alphabetical-start
 check_only = ["rustc_llvm/check_only"]
+llvm_enzyme = []
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index ac7583f5666..11be7041167 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -215,9 +215,9 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 let align = attrs.pointee_align.unwrap_or(self.layout.align.abi);
                 OperandValue::Ref(PlaceValue::new_sized(val, align)).store(bx, dst);
             }
-            // Unsized indirect qrguments
+            // Unsized indirect arguments cannot be stored
             PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
-                bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
+                bug!("unsized `ArgAbi` cannot be stored");
             }
             PassMode::Cast { cast, pad_i32: _ } => {
                 // The ABI mandates that the value is passed as a different struct representation.
@@ -272,12 +272,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 OperandValue::Pair(next(), next()).store(bx, dst);
             }
             PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
-                let place_val = PlaceValue {
-                    llval: next(),
-                    llextra: Some(next()),
-                    align: self.layout.align.abi,
-                };
-                OperandValue::Ref(place_val).store(bx, dst);
+                bug!("unsized `ArgAbi` cannot be stored");
             }
             PassMode::Direct(_)
             | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index f571716d9dd..78107d95e5a 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -617,7 +617,7 @@ pub(crate) fn run_pass_manager(
         crate::builder::gpu_offload::handle_gpu_code(cgcx, &cx);
     }
 
-    if cfg!(llvm_enzyme) && enable_ad && !thin {
+    if cfg!(feature = "llvm_enzyme") && enable_ad && !thin {
         let opt_stage = llvm::OptStage::FatLTO;
         let stage = write::AutodiffStage::PostAD;
         if !config.autodiff.contains(&config::AutoDiff::NoPostopt) {
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 423f0da4878..bda81fbd19e 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -574,7 +574,8 @@ pub(crate) unsafe fn llvm_optimize(
     // FIXME(ZuseZ4): In a future update we could figure out how to only optimize individual functions getting
     // differentiated.
 
-    let consider_ad = cfg!(llvm_enzyme) && config.autodiff.contains(&config::AutoDiff::Enable);
+    let consider_ad =
+        cfg!(feature = "llvm_enzyme") && config.autodiff.contains(&config::AutoDiff::Enable);
     let run_enzyme = autodiff_stage == AutodiffStage::DuringAD;
     let print_before_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModBefore);
     let print_after_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModAfter);
@@ -740,7 +741,8 @@ pub(crate) fn optimize(
 
         // If we know that we will later run AD, then we disable vectorization and loop unrolling.
         // Otherwise we pretend AD is already done and run the normal opt pipeline (=PostAD).
-        let consider_ad = cfg!(llvm_enzyme) && config.autodiff.contains(&config::AutoDiff::Enable);
+        let consider_ad =
+            cfg!(feature = "llvm_enzyme") && config.autodiff.contains(&config::AutoDiff::Enable);
         let autodiff_stage = if consider_ad { AutodiffStage::PreAD } else { AutodiffStage::PostAD };
         // The embedded bitcode is used to run LTO/ThinLTO.
         // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO.
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 6ddf53cdc87..b66e3dfdeec 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -3,8 +3,9 @@ use std::ptr;
 use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
 use rustc_codegen_ssa::common::TypeKind;
 use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
-use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt, TypingEnv};
+use rustc_middle::ty::{Instance, PseudoCanonicalInput, TyCtxt, TypingEnv};
 use rustc_middle::{bug, ty};
+use rustc_target::callconv::PassMode;
 use tracing::debug;
 
 use crate::builder::{Builder, PlaceRef, UNNAMED};
@@ -16,9 +17,12 @@ use crate::value::Value;
 
 pub(crate) fn adjust_activity_to_abi<'tcx>(
     tcx: TyCtxt<'tcx>,
-    fn_ty: Ty<'tcx>,
+    instance: Instance<'tcx>,
+    typing_env: TypingEnv<'tcx>,
     da: &mut Vec<DiffActivity>,
 ) {
+    let fn_ty = instance.ty(tcx, typing_env);
+
     if !matches!(fn_ty.kind(), ty::FnDef(..)) {
         bug!("expected fn def for autodiff, got {:?}", fn_ty);
     }
@@ -27,8 +31,16 @@ pub(crate) fn adjust_activity_to_abi<'tcx>(
     // All we do is decide how to handle the arguments.
     let sig = fn_ty.fn_sig(tcx).skip_binder();
 
+    // FIXME(Sa4dUs): pass proper varargs once we have support for differentiating variadic functions
+    let Ok(fn_abi) =
+        tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
+    else {
+        bug!("failed to get fn_abi of instance with empty varargs");
+    };
+
     let mut new_activities = vec![];
     let mut new_positions = vec![];
+    let mut del_activities = 0;
     for (i, ty) in sig.inputs().iter().enumerate() {
         if let Some(inner_ty) = ty.builtin_deref(true) {
             if inner_ty.is_slice() {
@@ -80,6 +92,34 @@ pub(crate) fn adjust_activity_to_abi<'tcx>(
                 continue;
             }
         }
+
+        let pci = PseudoCanonicalInput { typing_env: TypingEnv::fully_monomorphized(), value: *ty };
+
+        let layout = match tcx.layout_of(pci) {
+            Ok(layout) => layout.layout,
+            Err(_) => {
+                bug!("failed to compute layout for type {:?}", ty);
+            }
+        };
+
+        let pass_mode = &fn_abi.args[i].mode;
+
+        // For ZST, just ignore and don't add its activity, as this arg won't be present
+        // in the LLVM passed to Enzyme.
+        // Some targets pass ZST indirectly in the C ABI, in that case, handle it as a normal arg
+        // FIXME(Sa4dUs): Enforce ZST corresponding diff activity be `Const`
+        if *pass_mode == PassMode::Ignore {
+            del_activities += 1;
+            da.remove(i);
+        }
+
+        // If the argument is lowered as a `ScalarPair`, we need to duplicate its activity.
+        // Otherwise, the number of activities won't match the number of LLVM arguments and
+        // this will lead to errors when verifying the Enzyme call.
+        if let rustc_abi::BackendRepr::ScalarPair(_, _) = layout.backend_repr() {
+            new_activities.push(da[i].clone());
+            new_positions.push(i + 1 - del_activities);
+        }
     }
     // now add the extra activities coming from slices
     // Reverse order to not invalidate the indices
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 0903ddab285..aa8b8bd152d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -821,14 +821,15 @@ fn build_basic_type_di_node<'ll, 'tcx>(
     };
 
     let typedef_di_node = unsafe {
-        llvm::LLVMRustDIBuilderCreateTypedef(
+        llvm::LLVMDIBuilderCreateTypedef(
             DIB(cx),
             ty_di_node,
-            typedef_name.as_c_char_ptr(),
+            typedef_name.as_ptr(),
             typedef_name.len(),
             unknown_file_metadata(cx),
-            0,
-            None,
+            0,    // (no line number)
+            None, // (no scope)
+            0u32, // (no alignment specified)
         )
     };
 
@@ -1034,10 +1035,10 @@ fn create_member_type<'ll, 'tcx>(
     type_di_node: &'ll DIType,
 ) -> &'ll DIType {
     unsafe {
-        llvm::LLVMRustDIBuilderCreateMemberType(
+        llvm::LLVMDIBuilderCreateMemberType(
             DIB(cx),
             owner,
-            name.as_c_char_ptr(),
+            name.as_ptr(),
             name.len(),
             file_metadata,
             line_number,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index a5c80895741..4ecc3086e1b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
 use smallvec::smallvec;
 
-use crate::common::{AsCCharPtr, CodegenCx};
+use crate::common::CodegenCx;
 use crate::debuginfo::dwarf_const::DW_TAG_const_type;
 use crate::debuginfo::metadata::enums::DiscrResult;
 use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
@@ -378,20 +378,17 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
             variant_struct_type_wrapper_di_node,
             None,
         ),
-        unsafe {
-            llvm::LLVMRustDIBuilderCreateStaticMemberType(
-                DIB(cx),
-                enum_type_di_node,
-                TAG_FIELD_NAME.as_c_char_ptr(),
-                TAG_FIELD_NAME.len(),
-                unknown_file_metadata(cx),
-                UNKNOWN_LINE_NUMBER,
-                variant_names_type_di_node,
-                visibility_flags,
-                Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)),
-                tag_base_type_align.bits() as u32,
-            )
-        }
+        create_static_member_type(
+            cx,
+            enum_type_di_node,
+            TAG_FIELD_NAME,
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER,
+            variant_names_type_di_node,
+            visibility_flags,
+            Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)),
+            tag_base_type_align,
+        ),
     ]
 }
 
@@ -570,27 +567,28 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
             let build_assoc_const = |name: &str,
                                      type_di_node_: &'ll DIType,
                                      value: u64,
-                                     align: Align| unsafe {
+                                     align: Align|
+             -> &'ll llvm::Metadata {
                 // FIXME: Currently we force all DISCR_* values to be u64's as LLDB seems to have
                 // problems inspecting other value types. Since DISCR_* is typically only going to be
                 // directly inspected via the debugger visualizer - which compares it to the `tag` value
                 // (whose type is not modified at all) it shouldn't cause any real problems.
                 let (t_di, align) = if name == ASSOC_CONST_DISCR_NAME {
-                    (type_di_node_, align.bits() as u32)
+                    (type_di_node_, align)
                 } else {
                     let ty_u64 = Ty::new_uint(cx.tcx, ty::UintTy::U64);
-                    (type_di_node(cx, ty_u64), Align::EIGHT.bits() as u32)
+                    (type_di_node(cx, ty_u64), Align::EIGHT)
                 };
 
                 // must wrap type in a `const` modifier for LLDB to be able to inspect the value of the member
-                let field_type =
-                    llvm::LLVMRustDIBuilderCreateQualifiedType(DIB(cx), DW_TAG_const_type, t_di);
+                let field_type = unsafe {
+                    llvm::LLVMDIBuilderCreateQualifiedType(DIB(cx), DW_TAG_const_type, t_di)
+                };
 
-                llvm::LLVMRustDIBuilderCreateStaticMemberType(
-                    DIB(cx),
+                create_static_member_type(
+                    cx,
                     wrapper_struct_type_di_node,
-                    name.as_c_char_ptr(),
-                    name.len(),
+                    name,
                     unknown_file_metadata(cx),
                     UNKNOWN_LINE_NUMBER,
                     field_type,
@@ -975,3 +973,30 @@ fn variant_struct_wrapper_type_name(variant_index: VariantIdx) -> Cow<'static, s
         .map(|&s| Cow::from(s))
         .unwrap_or_else(|| format!("Variant{}", variant_index.as_usize()).into())
 }
+
+fn create_static_member_type<'ll>(
+    cx: &CodegenCx<'ll, '_>,
+    scope: &'ll llvm::Metadata,
+    name: &str,
+    file: &'ll llvm::Metadata,
+    line_number: c_uint,
+    ty: &'ll llvm::Metadata,
+    flags: DIFlags,
+    value: Option<&'ll llvm::Value>,
+    align: Align,
+) -> &'ll llvm::Metadata {
+    unsafe {
+        llvm::LLVMDIBuilderCreateStaticMemberType(
+            DIB(cx),
+            scope,
+            name.as_ptr(),
+            name.len(),
+            file,
+            line_number,
+            ty,
+            flags,
+            value,
+            align.bits() as c_uint,
+        )
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 85f71f331a4..e7f4a357048 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1208,7 +1208,8 @@ fn codegen_autodiff<'ll, 'tcx>(
 
     adjust_activity_to_abi(
         tcx,
-        fn_source.ty(tcx, TypingEnv::fully_monomorphized()),
+        fn_source,
+        TypingEnv::fully_monomorphized(),
         &mut diff_attrs.input_activity,
     );
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
index 56d756e52cc..695435eb6da 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs
@@ -59,10 +59,10 @@ pub(crate) enum LLVMRustVerifierFailureAction {
     LLVMReturnStatusAction = 2,
 }
 
-#[cfg(llvm_enzyme)]
+#[cfg(feature = "llvm_enzyme")]
 pub(crate) use self::Enzyme_AD::*;
 
-#[cfg(llvm_enzyme)]
+#[cfg(feature = "llvm_enzyme")]
 pub(crate) mod Enzyme_AD {
     use std::ffi::{CString, c_char};
 
@@ -134,10 +134,10 @@ pub(crate) mod Enzyme_AD {
     }
 }
 
-#[cfg(not(llvm_enzyme))]
+#[cfg(not(feature = "llvm_enzyme"))]
 pub(crate) use self::Fallback_AD::*;
 
-#[cfg(not(llvm_enzyme))]
+#[cfg(not(feature = "llvm_enzyme"))]
 pub(crate) mod Fallback_AD {
     #![allow(unused_variables)]
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 71d8b7d25fe..1124ebc3d44 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -24,7 +24,7 @@ use rustc_target::spec::SymbolVisibility;
 
 use super::RustString;
 use super::debuginfo::{
-    DIArray, DIBasicType, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags,
+    DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags,
     DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, DISubrange,
     DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind,
 };
@@ -1943,6 +1943,52 @@ unsafe extern "C" {
         UniqueId: *const c_uchar, // See "PTR_LEN_STR".
         UniqueIdLen: size_t,
     ) -> &'ll Metadata;
+
+    pub(crate) fn LLVMDIBuilderCreateMemberType<'ll>(
+        Builder: &DIBuilder<'ll>,
+        Scope: &'ll Metadata,
+        Name: *const c_uchar, // See "PTR_LEN_STR".
+        NameLen: size_t,
+        File: &'ll Metadata,
+        LineNo: c_uint,
+        SizeInBits: u64,
+        AlignInBits: u32,
+        OffsetInBits: u64,
+        Flags: DIFlags,
+        Ty: &'ll Metadata,
+    ) -> &'ll Metadata;
+
+    pub(crate) fn LLVMDIBuilderCreateStaticMemberType<'ll>(
+        Builder: &DIBuilder<'ll>,
+        Scope: &'ll Metadata,
+        Name: *const c_uchar, // See "PTR_LEN_STR".
+        NameLen: size_t,
+        File: &'ll Metadata,
+        LineNumber: c_uint,
+        Type: &'ll Metadata,
+        Flags: DIFlags,
+        ConstantVal: Option<&'ll Value>,
+        AlignInBits: u32,
+    ) -> &'ll Metadata;
+
+    /// Creates a "qualified type" in the C/C++ sense, by adding modifiers
+    /// like `const` or `volatile`.
+    pub(crate) fn LLVMDIBuilderCreateQualifiedType<'ll>(
+        Builder: &DIBuilder<'ll>,
+        Tag: c_uint, // (DWARF tag, e.g. `DW_TAG_const_type`)
+        Type: &'ll Metadata,
+    ) -> &'ll Metadata;
+
+    pub(crate) fn LLVMDIBuilderCreateTypedef<'ll>(
+        Builder: &DIBuilder<'ll>,
+        Type: &'ll Metadata,
+        Name: *const c_uchar, // See "PTR_LEN_STR".
+        NameLen: size_t,
+        File: &'ll Metadata,
+        LineNo: c_uint,
+        Scope: Option<&'ll Metadata>,
+        AlignInBits: u32, // (optional; default is 0)
+    ) -> &'ll Metadata;
 }
 
 #[link(name = "llvm-wrapper", kind = "static")]
@@ -2278,30 +2324,6 @@ unsafe extern "C" {
         TParam: &'a DIArray,
     ) -> &'a DISubprogram;
 
-    pub(crate) fn LLVMRustDIBuilderCreateTypedef<'a>(
-        Builder: &DIBuilder<'a>,
-        Type: &'a DIBasicType,
-        Name: *const c_char,
-        NameLen: size_t,
-        File: &'a DIFile,
-        LineNo: c_uint,
-        Scope: Option<&'a DIScope>,
-    ) -> &'a DIDerivedType;
-
-    pub(crate) fn LLVMRustDIBuilderCreateMemberType<'a>(
-        Builder: &DIBuilder<'a>,
-        Scope: &'a DIDescriptor,
-        Name: *const c_char,
-        NameLen: size_t,
-        File: &'a DIFile,
-        LineNo: c_uint,
-        SizeInBits: u64,
-        AlignInBits: u32,
-        OffsetInBits: u64,
-        Flags: DIFlags,
-        Ty: &'a DIType,
-    ) -> &'a DIDerivedType;
-
     pub(crate) fn LLVMRustDIBuilderCreateVariantMemberType<'a>(
         Builder: &DIBuilder<'a>,
         Scope: &'a DIScope,
@@ -2317,25 +2339,6 @@ unsafe extern "C" {
         Ty: &'a DIType,
     ) -> &'a DIType;
 
-    pub(crate) fn LLVMRustDIBuilderCreateStaticMemberType<'a>(
-        Builder: &DIBuilder<'a>,
-        Scope: &'a DIDescriptor,
-        Name: *const c_char,
-        NameLen: size_t,
-        File: &'a DIFile,
-        LineNo: c_uint,
-        Ty: &'a DIType,
-        Flags: DIFlags,
-        val: Option<&'a Value>,
-        AlignInBits: u32,
-    ) -> &'a DIDerivedType;
-
-    pub(crate) fn LLVMRustDIBuilderCreateQualifiedType<'a>(
-        Builder: &DIBuilder<'a>,
-        Tag: c_uint,
-        Type: &'a DIType,
-    ) -> &'a DIDerivedType;
-
     pub(crate) fn LLVMRustDIBuilderCreateStaticVariable<'a>(
         Builder: &DIBuilder<'a>,
         Context: Option<&'a DIScope>,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 45b028aa8ef..68a2f43ec67 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -168,9 +168,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         (&ty::Array(_, len), &ty::Slice(_)) => cx.const_usize(
             len.try_to_target_usize(cx.tcx()).expect("expected monomorphic const in codegen"),
         ),
-        (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
-            if src_dyn_kind == target_dyn_kind =>
-        {
+        (&ty::Dynamic(data_a, _), &ty::Dynamic(data_b, _)) => {
             let old_info =
                 old_info.expect("unsized_info: missing old info for trait upcasting coercion");
             let b_principal_def_id = data_b.principal_def_id();
@@ -208,7 +206,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                 old_info
             }
         }
-        (_, ty::Dynamic(data, _, _)) => meth::get_vtable(
+        (_, ty::Dynamic(data, _)) => meth::get_vtable(
             cx,
             source,
             data.principal()
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index 34ad35a729b..2fa466b5001 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -78,7 +78,7 @@ fn dyn_trait_in_self<'tcx>(
 ) -> Option<ty::ExistentialTraitRef<'tcx>> {
     for arg in ty.peel_refs().walk() {
         if let GenericArgKind::Type(ty) = arg.kind()
-            && let ty::Dynamic(data, _, _) = ty.kind()
+            && let ty::Dynamic(data, _) = ty.kind()
         {
             // FIXME(arbitrary_self_types): This is likely broken for receivers which
             // have a "non-self" trait objects as a generic argument.
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 6492ef73956..1b218a0d339 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -614,7 +614,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let (maybe_null, drop_fn, fn_abi, drop_instance) = match ty.kind() {
             // FIXME(eddyb) perhaps move some of this logic into
             // `Instance::resolve_drop_in_place`?
-            ty::Dynamic(_, _, ty::Dyn) => {
+            ty::Dynamic(_, _) => {
                 // IN THIS ARM, WE HAVE:
                 // ty = *mut (dyn Trait)
                 // which is: exists<T> ( *mut T,    Vtable<T: Trait> )
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 4cb88d44e1b..23e4a2921ea 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -658,7 +658,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                             let val = self.read_immediate(&receiver)?;
                             break self.ref_to_mplace(&val)?;
                         }
-                        ty::Dynamic(.., ty::Dyn) => break receiver.assert_mem_place(), // no immediate unsized values
+                        ty::Dynamic(..) => break receiver.assert_mem_place(), // no immediate unsized values
                         _ => {
                             // Not there yet, search for the only non-ZST field.
                             // (The rules for `DispatchFromDyn` ensure there's exactly one such field.)
@@ -675,7 +675,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // (For that reason we also cannot use `unpack_dyn_trait`.)
                 let receiver_tail =
                     self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env);
-                let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
+                let ty::Dynamic(receiver_trait, _) = receiver_tail.kind() else {
                     span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail)
                 };
                 assert!(receiver_place.layout.is_unsized());
@@ -822,7 +822,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // instead we do the virtual call stuff ourselves. It's easier here than in `eval_fn_call`
         // since we can just get a place of the underlying type and use `mplace_to_ref`.
         let place = match place.layout.ty.kind() {
-            ty::Dynamic(data, _, ty::Dyn) => {
+            ty::Dynamic(data, _) => {
                 // Dropping a trait object. Need to find actual drop fn.
                 self.unpack_dyn_trait(&place, data)?
             }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index e3afeda5b7c..0075740e031 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -386,7 +386,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 );
                 self.write_immediate(val, dest)
             }
-            (ty::Dynamic(data_a, _, ty::Dyn), ty::Dynamic(data_b, _, ty::Dyn)) => {
+            (ty::Dynamic(data_a, _), ty::Dynamic(data_b, _)) => {
                 let val = self.read_immediate(src)?;
                 // MIR building generates odd NOP casts, prevent them from causing unexpected trouble.
                 // See <https://github.com/rust-lang/rust/issues/128880>.
@@ -436,7 +436,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let new_vptr = self.get_vtable_ptr(ty, data_b)?;
                 self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
             }
-            (_, &ty::Dynamic(data, _, ty::Dyn)) => {
+            (_, &ty::Dynamic(data, _)) => {
                 // Initial cast from sized to dyn trait
                 let vtable = self.get_vtable_ptr(src_pointee_ty, data)?;
                 let ptr = self.read_pointer(src)?;
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 91ed71ac3e5..0e4a98f0941 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -469,7 +469,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 }
                 interp_ok(Some((full_size, full_align)))
             }
-            ty::Dynamic(expected_trait, _, ty::Dyn) => {
+            ty::Dynamic(expected_trait, _) => {
                 let vtable = metadata.unwrap_meta().to_pointer(self)?;
                 // Read size and align from vtable (already checks size).
                 interp_ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?))
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 5e3d0a15d8b..418dd658121 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -181,7 +181,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     | ty::Ref(_, _, _)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(..)
-                    | ty::Dynamic(_, _, _)
+                    | ty::Dynamic(_, _)
                     | ty::Closure(_, _)
                     | ty::CoroutineClosure(_, _)
                     | ty::Coroutine(_, _)
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index ebcdb9461d0..323e1cefd58 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -1504,7 +1504,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // This will also error if copying partial provenance is not supported.
         let provenance = src_alloc
             .provenance()
-            .prepare_copy(src_range, dest_offset, num_copies, self)
+            .prepare_copy(src_range, self)
             .map_err(|e| e.to_interp_error(src_alloc_id))?;
         // Prepare a copy of the initialization mask.
         let init = src_alloc.init_mask().prepare_copy(src_range);
@@ -1590,7 +1590,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             num_copies,
         );
         // copy the provenance to the destination
-        dest_alloc.provenance_apply_copy(provenance);
+        dest_alloc.provenance_apply_copy(provenance, alloc_range(dest_offset, size), num_copies);
 
         interp_ok(())
     }
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index 7cabfd96121..1c1c59da9d8 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -509,7 +509,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 | ty::Never
                 | ty::Error(_) => true,
 
-                ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
+                ty::Str | ty::Slice(_) | ty::Dynamic(_, _) | ty::Foreign(..) => false,
 
                 ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)),
 
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 870f9a396ae..d982ed96167 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -109,7 +109,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         assert!(
-            matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
+            matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _)),
             "`unpack_dyn_trait` only makes sense on `dyn*` types"
         );
         let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 02e3d90f4af..9adc3fa4631 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -449,7 +449,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
     ) -> InterpResult<'tcx> {
         let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.typing_env);
         match tail.kind() {
-            ty::Dynamic(data, _, ty::Dyn) => {
+            ty::Dynamic(data, _) => {
                 let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
                 // Make sure it is a genuine vtable pointer for the right trait.
                 try_validation!(
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 82c50fac6c0..b5de10c7dcd 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -90,7 +90,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
         // Special treatment for special types, where the (static) layout is not sufficient.
         match *ty.kind() {
             // If it is a trait object, switch to the real type that was used to create it.
-            ty::Dynamic(data, _, ty::Dyn) => {
+            ty::Dynamic(data, _) => {
                 // Dyn types. This is unsized, and the actual dynamic type of the data is given by the
                 // vtable stored in the place metadata.
                 // unsized values are never immediate, so we can assert_mem_place
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 5bcf96abd8c..db651811551 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -41,7 +41,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
             | ty::FnPtr(..)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::UnsafeBinder(_) => self.pretty_print_type(ty),
 
             // Placeholders (all printed as `_` to uniformize them).
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 17da3ea83c8..e4e86bcc41a 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -34,6 +34,7 @@
 #![feature(sized_hierarchy)]
 #![feature(test)]
 #![feature(thread_id_value)]
+#![feature(trusted_len)]
 #![feature(type_alias_impl_trait)]
 #![feature(unwrap_infallible)]
 // tidy-alphabetical-end
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index c002d47815b..15e3e6ea4c3 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -1,6 +1,7 @@
 use std::borrow::Borrow;
 use std::cmp::Ordering;
 use std::fmt::Debug;
+use std::iter::TrustedLen;
 use std::mem;
 use std::ops::{Bound, Index, IndexMut, RangeBounds};
 
@@ -215,36 +216,40 @@ impl<K: Ord, V> SortedMap<K, V> {
     /// It is up to the caller to make sure that the elements are sorted by key
     /// and that there are no duplicates.
     #[inline]
-    pub fn insert_presorted(&mut self, elements: Vec<(K, V)>) {
-        if elements.is_empty() {
+    pub fn insert_presorted(
+        &mut self,
+        // We require `TrustedLen` to ensure that the `splice` below is actually efficient.
+        mut elements: impl Iterator<Item = (K, V)> + DoubleEndedIterator + TrustedLen,
+    ) {
+        let Some(first) = elements.next() else {
             return;
-        }
-
-        debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0));
+        };
 
-        let start_index = self.lookup_index_for(&elements[0].0);
+        let start_index = self.lookup_index_for(&first.0);
 
         let elements = match start_index {
             Ok(index) => {
-                let mut elements = elements.into_iter();
-                self.data[index] = elements.next().unwrap();
-                elements
+                self.data[index] = first; // overwrite first element
+                elements.chain(None) // insert the rest below
             }
             Err(index) => {
-                if index == self.data.len() || elements.last().unwrap().0 < self.data[index].0 {
+                let last = elements.next_back();
+                if index == self.data.len()
+                    || last.as_ref().is_none_or(|l| l.0 < self.data[index].0)
+                {
                     // We can copy the whole range without having to mix with
                     // existing elements.
-                    self.data.splice(index..index, elements);
+                    self.data
+                        .splice(index..index, std::iter::once(first).chain(elements).chain(last));
                     return;
                 }
 
-                let mut elements = elements.into_iter();
-                self.data.insert(index, elements.next().unwrap());
-                elements
+                self.data.insert(index, first);
+                elements.chain(last) // insert the rest below
             }
         };
 
-        // Insert the rest
+        // Insert the rest. This is super inefficicent since each insertion copies the entire tail.
         for (k, v) in elements {
             self.insert(k, v);
         }
diff --git a/compiler/rustc_data_structures/src/sorted_map/tests.rs b/compiler/rustc_data_structures/src/sorted_map/tests.rs
index ea4d2f1feac..17d0d3cb170 100644
--- a/compiler/rustc_data_structures/src/sorted_map/tests.rs
+++ b/compiler/rustc_data_structures/src/sorted_map/tests.rs
@@ -171,7 +171,7 @@ fn test_insert_presorted_non_overlapping() {
     map.insert(2, 0);
     map.insert(8, 0);
 
-    map.insert_presorted(vec![(3, 0), (7, 0)]);
+    map.insert_presorted(vec![(3, 0), (7, 0)].into_iter());
 
     let expected = vec![2, 3, 7, 8];
     assert_eq!(keys(map), expected);
@@ -183,7 +183,7 @@ fn test_insert_presorted_first_elem_equal() {
     map.insert(2, 2);
     map.insert(8, 8);
 
-    map.insert_presorted(vec![(2, 0), (7, 7)]);
+    map.insert_presorted(vec![(2, 0), (7, 7)].into_iter());
 
     let expected = vec![(2, 0), (7, 7), (8, 8)];
     assert_eq!(elements(map), expected);
@@ -195,7 +195,7 @@ fn test_insert_presorted_last_elem_equal() {
     map.insert(2, 2);
     map.insert(8, 8);
 
-    map.insert_presorted(vec![(3, 3), (8, 0)]);
+    map.insert_presorted(vec![(3, 3), (8, 0)].into_iter());
 
     let expected = vec![(2, 2), (3, 3), (8, 0)];
     assert_eq!(elements(map), expected);
@@ -207,7 +207,7 @@ fn test_insert_presorted_shuffle() {
     map.insert(2, 2);
     map.insert(7, 7);
 
-    map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]);
+    map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)].into_iter());
 
     let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)];
     assert_eq!(elements(map), expected);
@@ -219,7 +219,7 @@ fn test_insert_presorted_at_end() {
     map.insert(1, 1);
     map.insert(2, 2);
 
-    map.insert_presorted(vec![(3, 3), (8, 8)]);
+    map.insert_presorted(vec![(3, 3), (8, 8)].into_iter());
 
     let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)];
     assert_eq!(elements(map), expected);
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index ae1dbd2cf51..46efa50cff3 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -74,6 +74,7 @@ ctrlc = "3.4.4"
 # tidy-alphabetical-start
 check_only = ['rustc_interface/check_only']
 llvm = ['rustc_interface/llvm']
+llvm_enzyme = ['rustc_interface/llvm_enzyme']
 max_level_info = ['rustc_log/max_level_info']
 rustc_randomized_layouts = [
     'rustc_index/rustc_randomized_layouts',
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index 04b144abd03..0784675b177 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -444,9 +444,6 @@ pub enum AttributeKind {
         span: Span,
     },
 
-    /// Represents `#[rustc_coherence_is_core]`.
-    CoherenceIsCore,
-
     /// Represents `#[rustc_coinductive]`.
     Coinductive(Span),
 
@@ -639,6 +636,9 @@ pub enum AttributeKind {
     /// Represents `#[rustc_builtin_macro]`.
     RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
 
+    /// Represents `#[rustc_coherence_is_core]`
+    RustcCoherenceIsCore(Span),
+
     /// Represents `#[rustc_layout_scalar_valid_range_end]`.
     RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
 
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index cb4feeb05f1..563e7a58c6d 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -26,7 +26,6 @@ impl AttributeKind {
             AsPtr(..) => Yes,
             AutomaticallyDerived(..) => Yes,
             BodyStability { .. } => No,
-            CoherenceIsCore => No,
             Coinductive(..) => No,
             Cold(..) => No,
             Confusables { .. } => Yes,
@@ -84,6 +83,7 @@ impl AttributeKind {
             RecursionLimit { .. } => No,
             Repr { .. } => No,
             RustcBuiltinMacro { .. } => Yes,
+            RustcCoherenceIsCore(..) => No,
             RustcLayoutScalarValidRangeEnd(..) => Yes,
             RustcLayoutScalarValidRangeStart(..) => Yes,
             RustcObjectLifetimeDefault => No,
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index c3f965d8456..44cc2dec1cb 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -152,7 +152,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
                     );
                     continue;
                 };
-                let ty::Dynamic(data, _, _) = *ty.kind() else {
+                let ty::Dynamic(data, _) = *ty.kind() else {
                     tcx.dcx()
                         .span_err(attr.span(), "`rustc_dump_vtable` to type alias of dyn type");
                     continue;
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs
index 76bb59e3f09..c248cd7fec2 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs
@@ -1,16 +1,22 @@
+use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
-use rustc_errors::struct_span_code_err;
+use rustc_errors::{
+    Applicability, Diag, EmissionGuarantee, StashKey, Suggestions, struct_span_code_err,
+};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
+use rustc_hir::def_id::DefId;
+use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS};
 use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
 use rustc_middle::ty::{
-    self, BottomUpFolder, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
+    self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
     TypeVisitableExt, Upcast,
 };
+use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
+use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
 use rustc_trait_selection::traits;
 use smallvec::{SmallVec, smallvec};
 use tracing::{debug, instrument};
@@ -28,11 +34,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         hir_id: hir::HirId,
         hir_bounds: &[hir::PolyTraitRef<'tcx>],
         lifetime: &hir::Lifetime,
-        representation: DynKind,
+        syntax: TraitObjectSyntax,
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
         let dummy_self = tcx.types.trait_object_dummy_self;
 
+        match syntax {
+            TraitObjectSyntax::Dyn => {}
+            TraitObjectSyntax::None => {
+                match self.prohibit_or_lint_bare_trait_object_ty(span, hir_id, hir_bounds) {
+                    // Don't continue with type analysis if the `dyn` keyword is missing.
+                    // It generates confusing errors, especially if the user meant to use
+                    // another keyword like `impl`.
+                    Some(guar) => return Ty::new_error(tcx, guar),
+                    None => {}
+                }
+            }
+        }
+
         let mut user_written_bounds = Vec::new();
         let mut potential_assoc_types = Vec::new();
         for poly_trait_ref in hir_bounds.iter() {
@@ -47,10 +66,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        let ast_bounds: Vec<_> =
-            hir_bounds.iter().map(|&trait_ref| hir::GenericBound::Trait(trait_ref)).collect();
-
-        self.add_default_traits(&mut user_written_bounds, dummy_self, &ast_bounds, None, span);
+        self.add_default_traits(
+            &mut user_written_bounds,
+            dummy_self,
+            &hir_bounds
+                .iter()
+                .map(|&trait_ref| hir::GenericBound::Trait(trait_ref))
+                .collect::<Vec<_>>(),
+            None,
+            span,
+        );
 
         let (elaborated_trait_bounds, elaborated_projection_bounds) =
             traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
@@ -431,7 +456,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         };
         debug!(?region_bound);
 
-        Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
+        Ty::new_dynamic(tcx, existential_predicates, region_bound)
     }
 
     /// Check that elaborating the principal of a trait ref doesn't lead to projections
@@ -483,6 +508,521 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             },
         );
     }
+
+    /// Prohibit or lint against *bare* trait object types depending on the edition.
+    ///
+    /// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
+    /// In edition 2021 and onward we emit a hard error for them.
+    fn prohibit_or_lint_bare_trait_object_ty(
+        &self,
+        span: Span,
+        hir_id: hir::HirId,
+        hir_bounds: &[hir::PolyTraitRef<'tcx>],
+    ) -> Option<ErrorGuaranteed> {
+        let tcx = self.tcx();
+        let [poly_trait_ref, ..] = hir_bounds else { return None };
+
+        let in_path = match tcx.parent_hir_node(hir_id) {
+            hir::Node::Ty(hir::Ty {
+                kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
+                ..
+            })
+            | hir::Node::Expr(hir::Expr {
+                kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
+                ..
+            })
+            | hir::Node::PatExpr(hir::PatExpr {
+                kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
+                ..
+            }) if qself.hir_id == hir_id => true,
+            _ => false,
+        };
+        let needs_bracket = in_path
+            && !tcx
+                .sess
+                .source_map()
+                .span_to_prev_source(span)
+                .ok()
+                .is_some_and(|s| s.trim_end().ends_with('<'));
+
+        let is_global = poly_trait_ref.trait_ref.path.is_global();
+
+        let mut sugg = vec![(
+            span.shrink_to_lo(),
+            format!(
+                "{}dyn {}",
+                if needs_bracket { "<" } else { "" },
+                if is_global { "(" } else { "" },
+            ),
+        )];
+
+        if is_global || needs_bracket {
+            sugg.push((
+                span.shrink_to_hi(),
+                format!(
+                    "{}{}",
+                    if is_global { ")" } else { "" },
+                    if needs_bracket { ">" } else { "" },
+                ),
+            ));
+        }
+
+        if span.edition().at_least_rust_2021() {
+            let mut diag = rustc_errors::struct_span_code_err!(
+                self.dcx(),
+                span,
+                E0782,
+                "{}",
+                "expected a type, found a trait"
+            );
+            if span.can_be_used_for_suggestions()
+                && poly_trait_ref.trait_ref.trait_def_id().is_some()
+                && !self.maybe_suggest_impl_trait(span, hir_id, hir_bounds, &mut diag)
+                && !self.maybe_suggest_dyn_trait(hir_id, sugg, &mut diag)
+            {
+                self.maybe_suggest_add_generic_impl_trait(span, hir_id, &mut diag);
+            }
+            // Check if the impl trait that we are considering is an impl of a local trait.
+            self.maybe_suggest_blanket_trait_impl(span, hir_id, &mut diag);
+            self.maybe_suggest_assoc_ty_bound(hir_id, &mut diag);
+            self.maybe_suggest_typoed_method(
+                hir_id,
+                poly_trait_ref.trait_ref.trait_def_id(),
+                &mut diag,
+            );
+            // In case there is an associated type with the same name
+            // Add the suggestion to this error
+            if let Some(mut sugg) =
+                self.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion)
+                && let Suggestions::Enabled(ref mut s1) = diag.suggestions
+                && let Suggestions::Enabled(ref mut s2) = sugg.suggestions
+            {
+                s1.append(s2);
+                sugg.cancel();
+            }
+            Some(diag.emit())
+        } else {
+            tcx.node_span_lint(BARE_TRAIT_OBJECTS, hir_id, span, |lint| {
+                lint.primary_message("trait objects without an explicit `dyn` are deprecated");
+                if span.can_be_used_for_suggestions() {
+                    lint.multipart_suggestion_verbose(
+                        "if this is a dyn-compatible trait, use `dyn`",
+                        sugg,
+                        Applicability::MachineApplicable,
+                    );
+                }
+                self.maybe_suggest_blanket_trait_impl(span, hir_id, lint);
+            });
+            None
+        }
+    }
+
+    /// For a struct or enum with an invalid bare trait object field, suggest turning
+    /// it into a generic type bound.
+    fn maybe_suggest_add_generic_impl_trait(
+        &self,
+        span: Span,
+        hir_id: hir::HirId,
+        diag: &mut Diag<'_>,
+    ) -> bool {
+        let tcx = self.tcx();
+
+        let parent_hir_id = tcx.parent_hir_id(hir_id);
+        let parent_item = tcx.hir_get_parent_item(hir_id).def_id;
+
+        let generics = match tcx.hir_node_by_def_id(parent_item) {
+            hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Struct(_, generics, variant),
+                ..
+            }) => {
+                if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
+                    return false;
+                }
+                generics
+            }
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics, def), .. }) => {
+                if !def
+                    .variants
+                    .iter()
+                    .flat_map(|variant| variant.data.fields().iter())
+                    .any(|field| field.hir_id == parent_hir_id)
+                {
+                    return false;
+                }
+                generics
+            }
+            _ => return false,
+        };
+
+        let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(span) else {
+            return false;
+        };
+
+        let param = "TUV"
+            .chars()
+            .map(|c| c.to_string())
+            .chain((0..).map(|i| format!("P{i}")))
+            .find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
+            .expect("we definitely can find at least one param name to generate");
+        let mut sugg = vec![(span, param.to_string())];
+        if let Some(insertion_span) = generics.span_for_param_suggestion() {
+            sugg.push((insertion_span, format!(", {param}: {}", rendered_ty)));
+        } else {
+            sugg.push((generics.where_clause_span, format!("<{param}: {}>", rendered_ty)));
+        }
+        diag.multipart_suggestion_verbose(
+            "you might be missing a type parameter",
+            sugg,
+            Applicability::MachineApplicable,
+        );
+        true
+    }
+
+    /// Make sure that we are in the condition to suggest the blanket implementation.
+    fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
+        &self,
+        span: Span,
+        hir_id: hir::HirId,
+        diag: &mut Diag<'_, G>,
+    ) {
+        let tcx = self.tcx();
+        let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
+        if let hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
+            ..
+        }) = tcx.hir_node_by_def_id(parent_id)
+            && hir_id == impl_self_ty.hir_id
+        {
+            let Some(of_trait) = of_trait else {
+                diag.span_suggestion_verbose(
+                    impl_self_ty.span.shrink_to_hi(),
+                    "you might have intended to implement this trait for a given type",
+                    format!(" for /* Type */"),
+                    Applicability::HasPlaceholders,
+                );
+                return;
+            };
+            if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
+                return;
+            }
+            let of_trait_span = of_trait.trait_ref.path.span;
+            // make sure that we are not calling unwrap to abort during the compilation
+            let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
+                return;
+            };
+
+            let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(span) else {
+                return;
+            };
+            let sugg = self.add_generic_param_suggestion(generics, span, &impl_trait_name);
+            diag.multipart_suggestion(
+                format!(
+                    "alternatively use a blanket implementation to implement `{of_trait_name}` for \
+                     all types that also implement `{impl_trait_name}`"
+                ),
+                sugg,
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
+    /// Try our best to approximate when adding `dyn` would be helpful for a bare
+    /// trait object.
+    ///
+    /// Right now, this is if the type is either directly nested in another ty,
+    /// or if it's in the tail field within a struct. This approximates what the
+    /// user would've gotten on edition 2015, except for the case where we have
+    /// an *obvious* knock-on `Sized` error.
+    fn maybe_suggest_dyn_trait(
+        &self,
+        hir_id: hir::HirId,
+        sugg: Vec<(Span, String)>,
+        diag: &mut Diag<'_>,
+    ) -> bool {
+        let tcx = self.tcx();
+
+        // Look at the direct HIR parent, since we care about the relationship between
+        // the type and the thing that directly encloses it.
+        match tcx.parent_hir_node(hir_id) {
+            // These are all generally ok. Namely, when a trait object is nested
+            // into another expression or ty, it's either very certain that they
+            // missed the ty (e.g. `&Trait`) or it's not really possible to tell
+            // what their intention is, so let's not give confusing suggestions and
+            // just mention `dyn`. The user can make up their mind what to do here.
+            hir::Node::Ty(_)
+            | hir::Node::Expr(_)
+            | hir::Node::PatExpr(_)
+            | hir::Node::PathSegment(_)
+            | hir::Node::AssocItemConstraint(_)
+            | hir::Node::TraitRef(_)
+            | hir::Node::Item(_)
+            | hir::Node::WherePredicate(_) => {}
+
+            hir::Node::Field(field) => {
+                // Enums can't have unsized fields, fields can only have an unsized tail field.
+                if let hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Struct(_, _, variant), ..
+                }) = tcx.parent_hir_node(field.hir_id)
+                    && variant
+                        .fields()
+                        .last()
+                        .is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
+                {
+                    // Ok
+                } else {
+                    return false;
+                }
+            }
+            _ => return false,
+        }
+
+        // FIXME: Only emit this suggestion if the trait is dyn-compatible.
+        diag.multipart_suggestion_verbose(
+            "you can add the `dyn` keyword if you want a trait object",
+            sugg,
+            Applicability::MachineApplicable,
+        );
+        true
+    }
+
+    fn add_generic_param_suggestion(
+        &self,
+        generics: &hir::Generics<'_>,
+        self_ty_span: Span,
+        impl_trait_name: &str,
+    ) -> Vec<(Span, String)> {
+        // check if the trait has generics, to make a correct suggestion
+        let param_name = generics.params.next_type_param_name(None);
+
+        let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
+            (span, format!(", {param_name}: {impl_trait_name}"))
+        } else {
+            (generics.span, format!("<{param_name}: {impl_trait_name}>"))
+        };
+        vec![(self_ty_span, param_name), add_generic_sugg]
+    }
+
+    /// Make sure that we are in the condition to suggest `impl Trait`.
+    fn maybe_suggest_impl_trait(
+        &self,
+        span: Span,
+        hir_id: hir::HirId,
+        hir_bounds: &[hir::PolyTraitRef<'tcx>],
+        diag: &mut Diag<'_>,
+    ) -> bool {
+        let tcx = self.tcx();
+        let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
+        // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
+        //        and suggest `Trait0<Ty = impl Trait1>`.
+        // Functions are found in three different contexts.
+        // 1. Independent functions
+        // 2. Functions inside trait blocks
+        // 3. Functions inside impl blocks
+        let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
+            hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Fn { sig, generics, .. }, ..
+            }) => (sig, generics),
+            hir::Node::TraitItem(hir::TraitItem {
+                kind: hir::TraitItemKind::Fn(sig, _),
+                generics,
+                ..
+            }) => (sig, generics),
+            hir::Node::ImplItem(hir::ImplItem {
+                kind: hir::ImplItemKind::Fn(sig, _),
+                generics,
+                ..
+            }) => (sig, generics),
+            _ => return false,
+        };
+        let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(span) else {
+            return false;
+        };
+        let impl_sugg = vec![(span.shrink_to_lo(), "impl ".to_string())];
+        // Check if trait object is safe for suggesting dynamic dispatch.
+        let is_dyn_compatible = hir_bounds.iter().all(|bound| match bound.trait_ref.path.res {
+            Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
+            _ => false,
+        });
+
+        let borrowed = matches!(
+            tcx.parent_hir_node(hir_id),
+            hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
+        );
+
+        // Suggestions for function return type.
+        if let hir::FnRetTy::Return(ty) = sig.decl.output
+            && ty.peel_refs().hir_id == hir_id
+        {
+            let pre = if !is_dyn_compatible {
+                format!("`{trait_name}` is dyn-incompatible, ")
+            } else {
+                String::new()
+            };
+            let msg = format!(
+                "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
+                 single underlying type",
+            );
+
+            diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
+
+            // Suggest `Box<dyn Trait>` for return type
+            if is_dyn_compatible {
+                // If the return type is `&Trait`, we don't want
+                // the ampersand to be displayed in the `Box<dyn Trait>`
+                // suggestion.
+                let suggestion = if borrowed {
+                    vec![(ty.span, format!("Box<dyn {trait_name}>"))]
+                } else {
+                    vec![
+                        (ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
+                        (ty.span.shrink_to_hi(), ">".to_string()),
+                    ]
+                };
+
+                diag.multipart_suggestion_verbose(
+                    "alternatively, you can return an owned trait object",
+                    suggestion,
+                    Applicability::MachineApplicable,
+                );
+            }
+            return true;
+        }
+
+        // Suggestions for function parameters.
+        for ty in sig.decl.inputs {
+            if ty.peel_refs().hir_id != hir_id {
+                continue;
+            }
+            let sugg = self.add_generic_param_suggestion(generics, span, &trait_name);
+            diag.multipart_suggestion_verbose(
+                format!("use a new generic type parameter, constrained by `{trait_name}`"),
+                sugg,
+                Applicability::MachineApplicable,
+            );
+            diag.multipart_suggestion_verbose(
+                "you can also use an opaque type, but users won't be able to specify the type \
+                 parameter when calling the `fn`, having to rely exclusively on type inference",
+                impl_sugg,
+                Applicability::MachineApplicable,
+            );
+            if !is_dyn_compatible {
+                diag.note(format!(
+                    "`{trait_name}` is dyn-incompatible, otherwise a trait object could be used"
+                ));
+            } else {
+                // No ampersand in suggestion if it's borrowed already
+                let (dyn_str, paren_dyn_str) =
+                    if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
+
+                let sugg = if let [_, _, ..] = hir_bounds {
+                    // There is more than one trait bound, we need surrounding parentheses.
+                    vec![
+                        (span.shrink_to_lo(), paren_dyn_str.to_string()),
+                        (span.shrink_to_hi(), ")".to_string()),
+                    ]
+                } else {
+                    vec![(span.shrink_to_lo(), dyn_str.to_string())]
+                };
+                diag.multipart_suggestion_verbose(
+                    format!(
+                        "alternatively, use a trait object to accept any type that implements \
+                         `{trait_name}`, accessing its methods at runtime using dynamic dispatch",
+                    ),
+                    sugg,
+                    Applicability::MachineApplicable,
+                );
+            }
+            return true;
+        }
+        false
+    }
+
+    fn maybe_suggest_assoc_ty_bound(&self, hir_id: hir::HirId, diag: &mut Diag<'_>) {
+        let mut parents = self.tcx().hir_parent_iter(hir_id);
+
+        if let Some((c_hir_id, hir::Node::AssocItemConstraint(constraint))) = parents.next()
+            && let Some(obj_ty) = constraint.ty()
+            && let Some((_, hir::Node::TraitRef(trait_ref))) = parents.next()
+        {
+            if let Some((_, hir::Node::Ty(ty))) = parents.next()
+                && let hir::TyKind::TraitObject(..) = ty.kind
+            {
+                // Assoc ty bounds aren't permitted inside trait object types.
+                return;
+            }
+
+            if trait_ref
+                .path
+                .segments
+                .iter()
+                .find_map(|seg| {
+                    seg.args.filter(|args| args.constraints.iter().any(|c| c.hir_id == c_hir_id))
+                })
+                .is_none_or(|args| args.parenthesized != hir::GenericArgsParentheses::No)
+            {
+                // Only consider angle-bracketed args (where we have a `=` to replace with `:`).
+                return;
+            }
+
+            let lo = if constraint.gen_args.span_ext.is_dummy() {
+                constraint.ident.span
+            } else {
+                constraint.gen_args.span_ext
+            };
+            let hi = obj_ty.span;
+
+            if !lo.eq_ctxt(hi) {
+                return;
+            }
+
+            diag.span_suggestion_verbose(
+                lo.between(hi),
+                "you might have meant to write a bound here",
+                ": ",
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
+    fn maybe_suggest_typoed_method(
+        &self,
+        hir_id: hir::HirId,
+        trait_def_id: Option<DefId>,
+        diag: &mut Diag<'_>,
+    ) {
+        let tcx = self.tcx();
+        let Some(trait_def_id) = trait_def_id else {
+            return;
+        };
+        let hir::Node::Expr(hir::Expr {
+            kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
+            ..
+        }) = tcx.parent_hir_node(hir_id)
+        else {
+            return;
+        };
+        if path_ty.hir_id != hir_id {
+            return;
+        }
+        let names: Vec<_> = tcx
+            .associated_items(trait_def_id)
+            .in_definition_order()
+            .filter(|assoc| assoc.namespace() == hir::def::Namespace::ValueNS)
+            .map(|cand| cand.name())
+            .collect();
+        if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
+            diag.span_suggestion_verbose(
+                segment.ident.span,
+                format!(
+                    "you may have misspelled this associated item, causing `{}` \
+                    to be interpreted as a type rather than a trait",
+                    tcx.item_name(trait_def_id),
+                ),
+                typo,
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
 }
 
 fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 0cf9cb7193f..16505174464 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -859,7 +859,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
                 }
                 // Point at the trait object that couldn't satisfy the bound.
-                ty::Dynamic(preds, _, _) => {
+                ty::Dynamic(preds, _) => {
                     for pred in preds.iter() {
                         match pred.skip_binder() {
                             ty::ExistentialPredicate::Trait(tr) => {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
deleted file mode 100644
index 56998b5b53c..00000000000
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ /dev/null
@@ -1,533 +0,0 @@
-use rustc_ast::TraitObjectSyntax;
-use rustc_errors::codes::*;
-use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions};
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace, Res};
-use rustc_hir::def_id::DefId;
-use rustc_lint_defs::Applicability;
-use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS;
-use rustc_span::Span;
-use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
-
-use super::HirTyLowerer;
-
-impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
-    /// Prohibit or lint against *bare* trait object types depending on the edition.
-    ///
-    /// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
-    /// In edition 2021 and onward we emit a hard error for them.
-    pub(super) fn prohibit_or_lint_bare_trait_object_ty(
-        &self,
-        self_ty: &hir::Ty<'_>,
-    ) -> Option<ErrorGuaranteed> {
-        let tcx = self.tcx();
-
-        let poly_trait_ref = if let hir::TyKind::TraitObject([poly_trait_ref, ..], tagged_ptr) =
-            self_ty.kind
-            && let TraitObjectSyntax::None = tagged_ptr.tag()
-        {
-            poly_trait_ref
-        } else {
-            return None;
-        };
-
-        let in_path = match tcx.parent_hir_node(self_ty.hir_id) {
-            hir::Node::Ty(hir::Ty {
-                kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
-                ..
-            })
-            | hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
-                ..
-            })
-            | hir::Node::PatExpr(hir::PatExpr {
-                kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
-                ..
-            }) if qself.hir_id == self_ty.hir_id => true,
-            _ => false,
-        };
-        let needs_bracket = in_path
-            && !tcx
-                .sess
-                .source_map()
-                .span_to_prev_source(self_ty.span)
-                .ok()
-                .is_some_and(|s| s.trim_end().ends_with('<'));
-
-        let is_global = poly_trait_ref.trait_ref.path.is_global();
-
-        let mut sugg = vec![(
-            self_ty.span.shrink_to_lo(),
-            format!(
-                "{}dyn {}",
-                if needs_bracket { "<" } else { "" },
-                if is_global { "(" } else { "" },
-            ),
-        )];
-
-        if is_global || needs_bracket {
-            sugg.push((
-                self_ty.span.shrink_to_hi(),
-                format!(
-                    "{}{}",
-                    if is_global { ")" } else { "" },
-                    if needs_bracket { ">" } else { "" },
-                ),
-            ));
-        }
-
-        if self_ty.span.edition().at_least_rust_2021() {
-            let mut diag = rustc_errors::struct_span_code_err!(
-                self.dcx(),
-                self_ty.span,
-                E0782,
-                "{}",
-                "expected a type, found a trait"
-            );
-            if self_ty.span.can_be_used_for_suggestions()
-                && poly_trait_ref.trait_ref.trait_def_id().is_some()
-                && !self.maybe_suggest_impl_trait(self_ty, &mut diag)
-                && !self.maybe_suggest_dyn_trait(self_ty, sugg, &mut diag)
-            {
-                self.maybe_suggest_add_generic_impl_trait(self_ty, &mut diag);
-            }
-            // Check if the impl trait that we are considering is an impl of a local trait.
-            self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
-            self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
-            self.maybe_suggest_typoed_method(
-                self_ty,
-                poly_trait_ref.trait_ref.trait_def_id(),
-                &mut diag,
-            );
-            // In case there is an associated type with the same name
-            // Add the suggestion to this error
-            if let Some(mut sugg) =
-                self.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
-                && let Suggestions::Enabled(ref mut s1) = diag.suggestions
-                && let Suggestions::Enabled(ref mut s2) = sugg.suggestions
-            {
-                s1.append(s2);
-                sugg.cancel();
-            }
-            Some(diag.emit())
-        } else {
-            tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, |lint| {
-                lint.primary_message("trait objects without an explicit `dyn` are deprecated");
-                if self_ty.span.can_be_used_for_suggestions() {
-                    lint.multipart_suggestion_verbose(
-                        "if this is a dyn-compatible trait, use `dyn`",
-                        sugg,
-                        Applicability::MachineApplicable,
-                    );
-                }
-                self.maybe_suggest_blanket_trait_impl(self_ty, lint);
-            });
-            None
-        }
-    }
-
-    /// For a struct or enum with an invalid bare trait object field, suggest turning
-    /// it into a generic type bound.
-    fn maybe_suggest_add_generic_impl_trait(
-        &self,
-        self_ty: &hir::Ty<'_>,
-        diag: &mut Diag<'_>,
-    ) -> bool {
-        let tcx = self.tcx();
-
-        let parent_hir_id = tcx.parent_hir_id(self_ty.hir_id);
-        let parent_item = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
-
-        let generics = match tcx.hir_node_by_def_id(parent_item) {
-            hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Struct(_, generics, variant),
-                ..
-            }) => {
-                if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
-                    return false;
-                }
-                generics
-            }
-            hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics, def), .. }) => {
-                if !def
-                    .variants
-                    .iter()
-                    .flat_map(|variant| variant.data.fields().iter())
-                    .any(|field| field.hir_id == parent_hir_id)
-                {
-                    return false;
-                }
-                generics
-            }
-            _ => return false,
-        };
-
-        let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
-            return false;
-        };
-
-        let param = "TUV"
-            .chars()
-            .map(|c| c.to_string())
-            .chain((0..).map(|i| format!("P{i}")))
-            .find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
-            .expect("we definitely can find at least one param name to generate");
-        let mut sugg = vec![(self_ty.span, param.to_string())];
-        if let Some(insertion_span) = generics.span_for_param_suggestion() {
-            sugg.push((insertion_span, format!(", {param}: {}", rendered_ty)));
-        } else {
-            sugg.push((generics.where_clause_span, format!("<{param}: {}>", rendered_ty)));
-        }
-        diag.multipart_suggestion_verbose(
-            "you might be missing a type parameter",
-            sugg,
-            Applicability::MachineApplicable,
-        );
-        true
-    }
-    /// Make sure that we are in the condition to suggest the blanket implementation.
-    fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
-        &self,
-        self_ty: &hir::Ty<'_>,
-        diag: &mut Diag<'_, G>,
-    ) {
-        let tcx = self.tcx();
-        let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
-        if let hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
-            ..
-        }) = tcx.hir_node_by_def_id(parent_id)
-            && self_ty.hir_id == impl_self_ty.hir_id
-        {
-            let Some(of_trait) = of_trait else {
-                diag.span_suggestion_verbose(
-                    impl_self_ty.span.shrink_to_hi(),
-                    "you might have intended to implement this trait for a given type",
-                    format!(" for /* Type */"),
-                    Applicability::HasPlaceholders,
-                );
-                return;
-            };
-            if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
-                return;
-            }
-            let of_trait_span = of_trait.trait_ref.path.span;
-            // make sure that we are not calling unwrap to abort during the compilation
-            let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
-                return;
-            };
-
-            let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(self_ty.span)
-            else {
-                return;
-            };
-            let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
-            diag.multipart_suggestion(
-                format!(
-                    "alternatively use a blanket implementation to implement `{of_trait_name}` for \
-                     all types that also implement `{impl_trait_name}`"
-                ),
-                sugg,
-                Applicability::MaybeIncorrect,
-            );
-        }
-    }
-
-    /// Try our best to approximate when adding `dyn` would be helpful for a bare
-    /// trait object.
-    ///
-    /// Right now, this is if the type is either directly nested in another ty,
-    /// or if it's in the tail field within a struct. This approximates what the
-    /// user would've gotten on edition 2015, except for the case where we have
-    /// an *obvious* knock-on `Sized` error.
-    fn maybe_suggest_dyn_trait(
-        &self,
-        self_ty: &hir::Ty<'_>,
-        sugg: Vec<(Span, String)>,
-        diag: &mut Diag<'_>,
-    ) -> bool {
-        let tcx = self.tcx();
-
-        // Look at the direct HIR parent, since we care about the relationship between
-        // the type and the thing that directly encloses it.
-        match tcx.parent_hir_node(self_ty.hir_id) {
-            // These are all generally ok. Namely, when a trait object is nested
-            // into another expression or ty, it's either very certain that they
-            // missed the ty (e.g. `&Trait`) or it's not really possible to tell
-            // what their intention is, so let's not give confusing suggestions and
-            // just mention `dyn`. The user can make up their mind what to do here.
-            hir::Node::Ty(_)
-            | hir::Node::Expr(_)
-            | hir::Node::PatExpr(_)
-            | hir::Node::PathSegment(_)
-            | hir::Node::AssocItemConstraint(_)
-            | hir::Node::TraitRef(_)
-            | hir::Node::Item(_)
-            | hir::Node::WherePredicate(_) => {}
-
-            hir::Node::Field(field) => {
-                // Enums can't have unsized fields, fields can only have an unsized tail field.
-                if let hir::Node::Item(hir::Item {
-                    kind: hir::ItemKind::Struct(_, _, variant), ..
-                }) = tcx.parent_hir_node(field.hir_id)
-                    && variant
-                        .fields()
-                        .last()
-                        .is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
-                {
-                    // Ok
-                } else {
-                    return false;
-                }
-            }
-            _ => return false,
-        }
-
-        // FIXME: Only emit this suggestion if the trait is dyn-compatible.
-        diag.multipart_suggestion_verbose(
-            "you can add the `dyn` keyword if you want a trait object",
-            sugg,
-            Applicability::MachineApplicable,
-        );
-        true
-    }
-
-    fn add_generic_param_suggestion(
-        &self,
-        generics: &hir::Generics<'_>,
-        self_ty_span: Span,
-        impl_trait_name: &str,
-    ) -> Vec<(Span, String)> {
-        // check if the trait has generics, to make a correct suggestion
-        let param_name = generics.params.next_type_param_name(None);
-
-        let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
-            (span, format!(", {param_name}: {impl_trait_name}"))
-        } else {
-            (generics.span, format!("<{param_name}: {impl_trait_name}>"))
-        };
-        vec![(self_ty_span, param_name), add_generic_sugg]
-    }
-
-    /// Make sure that we are in the condition to suggest `impl Trait`.
-    fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool {
-        let tcx = self.tcx();
-        let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
-        // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
-        //        and suggest `Trait0<Ty = impl Trait1>`.
-        // Functions are found in three different contexts.
-        // 1. Independent functions
-        // 2. Functions inside trait blocks
-        // 3. Functions inside impl blocks
-        let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
-            hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Fn { sig, generics, .. }, ..
-            }) => (sig, generics),
-            hir::Node::TraitItem(hir::TraitItem {
-                kind: hir::TraitItemKind::Fn(sig, _),
-                generics,
-                ..
-            }) => (sig, generics),
-            hir::Node::ImplItem(hir::ImplItem {
-                kind: hir::ImplItemKind::Fn(sig, _),
-                generics,
-                ..
-            }) => (sig, generics),
-            _ => return false,
-        };
-        let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
-            return false;
-        };
-        let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
-        // Check if trait object is safe for suggesting dynamic dispatch.
-        let is_dyn_compatible = match self_ty.kind {
-            hir::TyKind::TraitObject(objects, ..) => {
-                objects.iter().all(|o| match o.trait_ref.path.res {
-                    Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
-                    _ => false,
-                })
-            }
-            _ => false,
-        };
-
-        let borrowed = matches!(
-            tcx.parent_hir_node(self_ty.hir_id),
-            hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
-        );
-
-        // Suggestions for function return type.
-        if let hir::FnRetTy::Return(ty) = sig.decl.output
-            && ty.peel_refs().hir_id == self_ty.hir_id
-        {
-            let pre = if !is_dyn_compatible {
-                format!("`{trait_name}` is dyn-incompatible, ")
-            } else {
-                String::new()
-            };
-            let msg = format!(
-                "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
-                 single underlying type",
-            );
-
-            diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
-
-            // Suggest `Box<dyn Trait>` for return type
-            if is_dyn_compatible {
-                // If the return type is `&Trait`, we don't want
-                // the ampersand to be displayed in the `Box<dyn Trait>`
-                // suggestion.
-                let suggestion = if borrowed {
-                    vec![(ty.span, format!("Box<dyn {trait_name}>"))]
-                } else {
-                    vec![
-                        (ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
-                        (ty.span.shrink_to_hi(), ">".to_string()),
-                    ]
-                };
-
-                diag.multipart_suggestion_verbose(
-                    "alternatively, you can return an owned trait object",
-                    suggestion,
-                    Applicability::MachineApplicable,
-                );
-            }
-            return true;
-        }
-
-        // Suggestions for function parameters.
-        for ty in sig.decl.inputs {
-            if ty.peel_refs().hir_id != self_ty.hir_id {
-                continue;
-            }
-            let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
-            diag.multipart_suggestion_verbose(
-                format!("use a new generic type parameter, constrained by `{trait_name}`"),
-                sugg,
-                Applicability::MachineApplicable,
-            );
-            diag.multipart_suggestion_verbose(
-                "you can also use an opaque type, but users won't be able to specify the type \
-                 parameter when calling the `fn`, having to rely exclusively on type inference",
-                impl_sugg,
-                Applicability::MachineApplicable,
-            );
-            if !is_dyn_compatible {
-                diag.note(format!(
-                    "`{trait_name}` is dyn-incompatible, otherwise a trait object could be used"
-                ));
-            } else {
-                // No ampersand in suggestion if it's borrowed already
-                let (dyn_str, paren_dyn_str) =
-                    if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
-
-                let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind {
-                    // There is more than one trait bound, we need surrounding parentheses.
-                    vec![
-                        (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
-                        (self_ty.span.shrink_to_hi(), ")".to_string()),
-                    ]
-                } else {
-                    vec![(self_ty.span.shrink_to_lo(), dyn_str.to_string())]
-                };
-                diag.multipart_suggestion_verbose(
-                    format!(
-                        "alternatively, use a trait object to accept any type that implements \
-                         `{trait_name}`, accessing its methods at runtime using dynamic dispatch",
-                    ),
-                    sugg,
-                    Applicability::MachineApplicable,
-                );
-            }
-            return true;
-        }
-        false
-    }
-
-    fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) {
-        let mut parents = self.tcx().hir_parent_iter(self_ty.hir_id);
-
-        if let Some((c_hir_id, hir::Node::AssocItemConstraint(constraint))) = parents.next()
-            && let Some(obj_ty) = constraint.ty()
-            && let Some((_, hir::Node::TraitRef(trait_ref))) = parents.next()
-        {
-            if let Some((_, hir::Node::Ty(ty))) = parents.next()
-                && let hir::TyKind::TraitObject(..) = ty.kind
-            {
-                // Assoc ty bounds aren't permitted inside trait object types.
-                return;
-            }
-
-            if trait_ref
-                .path
-                .segments
-                .iter()
-                .find_map(|seg| {
-                    seg.args.filter(|args| args.constraints.iter().any(|c| c.hir_id == c_hir_id))
-                })
-                .is_none_or(|args| args.parenthesized != hir::GenericArgsParentheses::No)
-            {
-                // Only consider angle-bracketed args (where we have a `=` to replace with `:`).
-                return;
-            }
-
-            let lo = if constraint.gen_args.span_ext.is_dummy() {
-                constraint.ident.span
-            } else {
-                constraint.gen_args.span_ext
-            };
-            let hi = obj_ty.span;
-
-            if !lo.eq_ctxt(hi) {
-                return;
-            }
-
-            diag.span_suggestion_verbose(
-                lo.between(hi),
-                "you might have meant to write a bound here",
-                ": ",
-                Applicability::MaybeIncorrect,
-            );
-        }
-    }
-
-    fn maybe_suggest_typoed_method(
-        &self,
-        self_ty: &hir::Ty<'_>,
-        trait_def_id: Option<DefId>,
-        diag: &mut Diag<'_>,
-    ) {
-        let tcx = self.tcx();
-        let Some(trait_def_id) = trait_def_id else {
-            return;
-        };
-        let hir::Node::Expr(hir::Expr {
-            kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
-            ..
-        }) = tcx.parent_hir_node(self_ty.hir_id)
-        else {
-            return;
-        };
-        if path_ty.hir_id != self_ty.hir_id {
-            return;
-        }
-        let names: Vec<_> = tcx
-            .associated_items(trait_def_id)
-            .in_definition_order()
-            .filter(|assoc| assoc.namespace() == Namespace::ValueNS)
-            .map(|cand| cand.name())
-            .collect();
-        if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
-            diag.span_suggestion_verbose(
-                segment.ident.span,
-                format!(
-                    "you may have misspelled this associated item, causing `{}` \
-                    to be interpreted as a type rather than a trait",
-                    tcx.item_name(trait_def_id),
-                ),
-                typo,
-                Applicability::MaybeIncorrect,
-            );
-        }
-    }
-}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index c5e079fe89a..9b198d04454 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -15,15 +15,13 @@
 
 mod bounds;
 mod cmse;
-mod dyn_compatibility;
+mod dyn_trait;
 pub mod errors;
 pub mod generics;
-mod lint;
 
 use std::assert_matches::assert_matches;
 use std::slice;
 
-use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{
@@ -2428,19 +2426,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             ),
             hir::TyKind::TraitObject(bounds, tagged_ptr) => {
                 let lifetime = tagged_ptr.pointer();
-                let repr = tagged_ptr.tag();
-
-                if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
-                    // Don't continue with type analysis if the `dyn` keyword is missing
-                    // It generates confusing errors, especially if the user meant to use another
-                    // keyword like `impl`
-                    Ty::new_error(tcx, guar)
-                } else {
-                    let repr = match repr {
-                        TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
-                    };
-                    self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
-                }
+                let syntax = tagged_ptr.tag();
+                self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, syntax)
             }
             // If we encounter a fully qualified path with RTN generics, then it must have
             // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 960ec7f66ab..be841675821 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -281,7 +281,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_args(current, data.def_id, data.args, variance);
             }
 
-            ty::Dynamic(data, r, _) => {
+            ty::Dynamic(data, r) => {
                 // The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
                 self.add_constraints_from_region(current, r, variance);
 
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 27540fd1a43..40b21c45bc5 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -103,7 +103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         Ok(match *t.kind() {
             ty::Slice(_) | ty::Str => Some(PointerKind::Length),
-            ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
+            ty::Dynamic(tty, _) => Some(PointerKind::VTable(tty)),
             ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
                 None => Some(PointerKind::Thin),
                 Some(f) => {
@@ -250,9 +250,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         // cases now. We do a more thorough check at the end, once
         // inference is more completely known.
         match cast_ty.kind() {
-            ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => {
-                Err(check.report_cast_to_unsized_type(fcx))
-            }
+            ty::Dynamic(_, _) | ty::Slice(..) => Err(check.report_cast_to_unsized_type(fcx)),
             _ => Ok(check),
         }
     }
@@ -900,7 +898,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                 &src_tty.without_auto_traits().collect::<Vec<_>>(),
                             ),
                             tcx.lifetimes.re_erased,
-                            ty::Dyn,
                         );
                         let dst_obj = Ty::new_dynamic(
                             tcx,
@@ -908,7 +905,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                                 &dst_tty.without_auto_traits().collect::<Vec<_>>(),
                             ),
                             tcx.lifetimes.re_erased,
-                            ty::Dyn,
                         );
 
                         // `dyn Src = dyn Dst`, this checks for matching traits/generics/projections
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index b99f811db1a..ced2cf2b57b 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -558,7 +558,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             | ty::Slice(_)
             | ty::FnDef(_, _)
             | ty::FnPtr(_, _)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Closure(_, _)
             | ty::CoroutineClosure(_, _)
             | ty::Coroutine(_, _)
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index c8f6c06b720..a39ac0fcb6e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1008,7 +1008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
                     }
                     // Point at the trait object that couldn't satisfy the bound.
-                    ty::Dynamic(preds, _, _) => {
+                    ty::Dynamic(preds, _) => {
                         for pred in preds.iter() {
                             match pred.skip_binder() {
                                 ty::ExistentialPredicate::Trait(tr) => {
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index ad19cdef4e7..70e3d7dc9fe 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -28,7 +28,7 @@
 use relate::lattice::{LatticeOp, LatticeOpKind};
 use rustc_middle::bug;
 use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate;
-use rustc_middle::ty::{Const, ImplSubject, TypingMode};
+use rustc_middle::ty::{Const, TypingMode};
 
 use super::*;
 use crate::infer::relate::type_relating::TypeRelating;
@@ -304,23 +304,6 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     }
 }
 
-impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
-    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
-        match (a, b) {
-            (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
-                ToTrace::to_trace(cause, trait_ref_a, trait_ref_b)
-            }
-            (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
-                ToTrace::to_trace(cause, ty_a, ty_b)
-            }
-            (ImplSubject::Trait(_), ImplSubject::Inherent(_))
-            | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
-                bug!("can not trace TraitRef and Ty");
-            }
-        }
-    }
-}
-
 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
     fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
         TypeTrace {
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 473ac5e0cea..f0836c47740 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -58,4 +58,5 @@ rustc_abi = { path = "../rustc_abi" }
 # tidy-alphabetical-start
 check_only = ['rustc_codegen_llvm?/check_only']
 llvm = ['dep:rustc_codegen_llvm']
+llvm_enzyme = ['rustc_builtin_macros/llvm_enzyme', 'rustc_codegen_llvm/llvm_enzyme']
 # tidy-alphabetical-end
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index e1c51ff8299..703f757abd5 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -66,11 +66,11 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
             && tcx.is_lang_item(did, LangItem::Deref)
             // the self type is `dyn t_principal`
             && let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
-            && let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
+            && let ty::Dynamic(data, _) = self_ty.kind()
             && let Some(self_principal) = data.principal()
             // `<T as Deref>::Target` is `dyn target_principal`
             && let Some(target) = cx.get_associated_type(self_ty, did, sym::Target)
-            && let ty::Dynamic(data, _, ty::Dyn) = target.kind()
+            && let ty::Dynamic(data, _) = target.kind()
             && let Some(target_principal) = data.principal()
             // `target_principal` is a supertrait of `t_principal`
             && let Some(supertrait_principal) = supertraits(tcx, self_principal.with_self_ty(tcx, self_ty))
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 88527fa2e6e..eaec0c9857d 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -320,7 +320,7 @@ fn lint_wide_pointer<'tcx>(
         };
 
         (!ty.is_sized(cx.tcx, cx.typing_env()))
-            .then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn))))
+            .then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _))))
     };
 
     // the left and right operands can have references, remove any explicit references
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index edbbfba4f34..874c4354029 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -312,7 +312,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                         })
                         .map(|inner| MustUsePath::Opaque(Box::new(inner)))
                 }
-                ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
+                ty::Dynamic(binders, _) => binders.iter().find_map(|predicate| {
                     if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
                     {
                         let def_id = trait_ref.def_id;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index b4ca641674f..64151962321 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1064,16 +1064,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
   return wrap(Sub);
 }
 
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type,
-                               const char *Name, size_t NameLen,
-                               LLVMMetadataRef File, unsigned LineNo,
-                               LLVMMetadataRef Scope) {
-  return wrap(unwrap(Builder)->createTypedef(
-      unwrap<DIType>(Type), StringRef(Name, NameLen), unwrap<DIFile>(File),
-      LineNo, unwrapDIPtr<DIScope>(Scope)));
-}
-
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
     LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNumber,
@@ -1088,17 +1078,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart(
       StringRef(UniqueId, UniqueIdLen)));
 }
 
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType(
-    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
-    size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
-    uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags,
-    LLVMMetadataRef Ty) {
-  return wrap(unwrap(Builder)->createMemberType(
-      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
-      unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits,
-      fromRust(Flags), unwrapDI<DIType>(Ty)));
-}
-
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
     LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
     size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits,
@@ -1114,23 +1093,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType(
       fromRust(Flags), unwrapDI<DIType>(Ty)));
 }
 
-extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType(
-    LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
-    size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
-    LLVMDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) {
-  return wrap(unwrap(Builder)->createStaticMemberType(
-      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
-      unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), fromRust(Flags),
-      unwrap<llvm::ConstantInt>(val), llvm::dwarf::DW_TAG_member, AlignInBits));
-}
-
-extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag,
-                                     LLVMMetadataRef Type) {
-  return wrap(
-      unwrap(Builder)->createQualifiedType(Tag, unwrapDI<DIType>(Type)));
-}
-
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
     LLVMDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name,
     size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index 4370816d38e..430cd329408 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -370,7 +370,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn hir_rustc_coherence_is_core(self) -> bool {
-        find_attr!(self.hir_krate_attrs(), AttributeKind::CoherenceIsCore)
+        find_attr!(self.hir_krate_attrs(), AttributeKind::RustcCoherenceIsCore(..))
     }
 
     pub fn hir_get_module(self, module: LocalModDefId) -> (&'tcx Mod<'tcx>, Span, HirId) {
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 67bc89692ff..9e3162785f4 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -18,7 +18,7 @@ use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_span::{ErrorGuaranteed, ExpnId, Span};
 
 use crate::query::Providers;
-use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
+use crate::ty::TyCtxt;
 
 /// Gather the LocalDefId for each item-like within a module, including items contained within
 /// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
@@ -154,13 +154,6 @@ impl<'tcx> TyCtxt<'tcx> {
         LocalModDefId::new_unchecked(id)
     }
 
-    pub fn impl_subject(self, def_id: DefId) -> EarlyBinder<'tcx, ImplSubject<'tcx>> {
-        match self.impl_trait_ref(def_id) {
-            Some(t) => t.map_bound(ImplSubject::Trait),
-            None => self.type_of(def_id).map_bound(ImplSubject::Inherent),
-        }
-    }
-
     /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
     pub fn is_foreign_item(self, def_id: impl Into<DefId>) -> bool {
         self.opt_parent(def_id.into())
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 67962813ae4..8e603ce1b91 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -849,8 +849,13 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
     ///
     /// This is dangerous to use as it can violate internal `Allocation` invariants!
     /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
-    pub fn provenance_apply_copy(&mut self, copy: ProvenanceCopy<Prov>) {
-        self.provenance.apply_copy(copy)
+    pub fn provenance_apply_copy(
+        &mut self,
+        copy: ProvenanceCopy<Prov>,
+        range: AllocRange,
+        repeat: u64,
+    ) {
+        self.provenance.apply_copy(copy, range, repeat)
     }
 
     /// Applies a previously prepared copy of the init mask.
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
index 720e58d7aa0..67baf63bbfa 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs
@@ -278,90 +278,78 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
 
 /// A partial, owned list of provenance to transfer into another allocation.
 ///
-/// Offsets are already adjusted to the destination allocation.
+/// Offsets are relative to the beginning of the copied range.
 pub struct ProvenanceCopy<Prov> {
-    dest_ptrs: Option<Box<[(Size, Prov)]>>,
-    dest_bytes: Option<Box<[(Size, (Prov, u8))]>>,
+    ptrs: Box<[(Size, Prov)]>,
+    bytes: Box<[(Size, (Prov, u8))]>,
 }
 
 impl<Prov: Provenance> ProvenanceMap<Prov> {
     pub fn prepare_copy(
         &self,
-        src: AllocRange,
-        dest: Size,
-        count: u64,
+        range: AllocRange,
         cx: &impl HasDataLayout,
     ) -> AllocResult<ProvenanceCopy<Prov>> {
-        let shift_offset = move |idx, offset| {
-            // compute offset for current repetition
-            let dest_offset = dest + src.size * idx; // `Size` operations
-            // shift offsets from source allocation to destination allocation
-            (offset - src.start) + dest_offset // `Size` operations
-        };
+        let shift_offset = move |offset| offset - range.start;
         let ptr_size = cx.data_layout().pointer_size();
 
         // # Pointer-sized provenances
         // Get the provenances that are entirely within this range.
         // (Different from `range_get_ptrs` which asks if they overlap the range.)
         // Only makes sense if we are copying at least one pointer worth of bytes.
-        let mut dest_ptrs_box = None;
-        if src.size >= ptr_size {
-            let adjusted_end = Size::from_bytes(src.end().bytes() - (ptr_size.bytes() - 1));
-            let ptrs = self.ptrs.range(src.start..adjusted_end);
-            // If `count` is large, this is rather wasteful -- we are allocating a big array here, which
-            // is mostly filled with redundant information since it's just N copies of the same `Prov`s
-            // at slightly adjusted offsets. The reason we do this is so that in `mark_provenance_range`
-            // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces
-            // the right sequence of provenance for all N copies.
-            // Basically, this large array would have to be created anyway in the target allocation.
-            let mut dest_ptrs = Vec::with_capacity(ptrs.len() * (count as usize));
-            for i in 0..count {
-                dest_ptrs
-                    .extend(ptrs.iter().map(|&(offset, reloc)| (shift_offset(i, offset), reloc)));
-            }
-            debug_assert_eq!(dest_ptrs.len(), dest_ptrs.capacity());
-            dest_ptrs_box = Some(dest_ptrs.into_boxed_slice());
+        let mut ptrs_box: Box<[_]> = Box::new([]);
+        if range.size >= ptr_size {
+            let adjusted_end = Size::from_bytes(range.end().bytes() - (ptr_size.bytes() - 1));
+            let ptrs = self.ptrs.range(range.start..adjusted_end);
+            ptrs_box = ptrs.iter().map(|&(offset, reloc)| (shift_offset(offset), reloc)).collect();
         };
 
         // # Byte-sized provenances
         // This includes the existing bytewise provenance in the range, and ptr provenance
         // that overlaps with the begin/end of the range.
-        let mut dest_bytes_box = None;
-        let begin_overlap = self.range_ptrs_get(alloc_range(src.start, Size::ZERO), cx).first();
-        let end_overlap = self.range_ptrs_get(alloc_range(src.end(), Size::ZERO), cx).first();
+        let mut bytes_box: Box<[_]> = Box::new([]);
+        let begin_overlap = self.range_ptrs_get(alloc_range(range.start, Size::ZERO), cx).first();
+        let end_overlap = self.range_ptrs_get(alloc_range(range.end(), Size::ZERO), cx).first();
         // We only need to go here if there is some overlap or some bytewise provenance.
         if begin_overlap.is_some() || end_overlap.is_some() || self.bytes.is_some() {
             let mut bytes: Vec<(Size, (Prov, u8))> = Vec::new();
             // First, if there is a part of a pointer at the start, add that.
             if let Some(entry) = begin_overlap {
                 trace!("start overlapping entry: {entry:?}");
-                // For really small copies, make sure we don't run off the end of the `src` range.
-                let entry_end = cmp::min(entry.0 + ptr_size, src.end());
-                for offset in src.start..entry_end {
-                    bytes.push((offset, (entry.1, (offset - entry.0).bytes() as u8)));
+                // For really small copies, make sure we don't run off the end of the range.
+                let entry_end = cmp::min(entry.0 + ptr_size, range.end());
+                for offset in range.start..entry_end {
+                    bytes.push((shift_offset(offset), (entry.1, (offset - entry.0).bytes() as u8)));
                 }
             } else {
                 trace!("no start overlapping entry");
             }
 
             // Then the main part, bytewise provenance from `self.bytes`.
-            bytes.extend(self.range_bytes_get(src));
+            bytes.extend(
+                self.range_bytes_get(range)
+                    .iter()
+                    .map(|&(offset, reloc)| (shift_offset(offset), reloc)),
+            );
 
             // And finally possibly parts of a pointer at the end.
             if let Some(entry) = end_overlap {
                 trace!("end overlapping entry: {entry:?}");
-                // For really small copies, make sure we don't start before `src` does.
-                let entry_start = cmp::max(entry.0, src.start);
-                for offset in entry_start..src.end() {
+                // For really small copies, make sure we don't start before `range` does.
+                let entry_start = cmp::max(entry.0, range.start);
+                for offset in entry_start..range.end() {
                     if bytes.last().is_none_or(|bytes_entry| bytes_entry.0 < offset) {
                         // The last entry, if it exists, has a lower offset than us, so we
                         // can add it at the end and remain sorted.
-                        bytes.push((offset, (entry.1, (offset - entry.0).bytes() as u8)));
+                        bytes.push((
+                            shift_offset(offset),
+                            (entry.1, (offset - entry.0).bytes() as u8),
+                        ));
                     } else {
                         // There already is an entry for this offset in there! This can happen when the
                         // start and end range checks actually end up hitting the same pointer, so we
                         // already added this in the "pointer at the start" part above.
-                        assert!(entry.0 <= src.start);
+                        assert!(entry.0 <= range.start);
                     }
                 }
             } else {
@@ -372,33 +360,40 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
             if !bytes.is_empty() && !Prov::OFFSET_IS_ADDR {
                 // FIXME(#146291): We need to ensure that we don't mix different pointers with
                 // the same provenance.
-                return Err(AllocError::ReadPartialPointer(src.start));
+                return Err(AllocError::ReadPartialPointer(range.start));
             }
 
             // And again a buffer for the new list on the target side.
-            let mut dest_bytes = Vec::with_capacity(bytes.len() * (count as usize));
-            for i in 0..count {
-                dest_bytes
-                    .extend(bytes.iter().map(|&(offset, reloc)| (shift_offset(i, offset), reloc)));
-            }
-            debug_assert_eq!(dest_bytes.len(), dest_bytes.capacity());
-            dest_bytes_box = Some(dest_bytes.into_boxed_slice());
+            bytes_box = bytes.into_boxed_slice();
         }
 
-        Ok(ProvenanceCopy { dest_ptrs: dest_ptrs_box, dest_bytes: dest_bytes_box })
+        Ok(ProvenanceCopy { ptrs: ptrs_box, bytes: bytes_box })
     }
 
     /// Applies a provenance copy.
     /// The affected range, as defined in the parameters to `prepare_copy` is expected
     /// to be clear of provenance.
-    pub fn apply_copy(&mut self, copy: ProvenanceCopy<Prov>) {
-        if let Some(dest_ptrs) = copy.dest_ptrs {
-            self.ptrs.insert_presorted(dest_ptrs.into());
+    pub fn apply_copy(&mut self, copy: ProvenanceCopy<Prov>, range: AllocRange, repeat: u64) {
+        let shift_offset = |idx: u64, offset: Size| offset + range.start + idx * range.size;
+        if !copy.ptrs.is_empty() {
+            // We want to call `insert_presorted` only once so that, if possible, the entries
+            // after the range we insert are moved back only once.
+            let chunk_len = copy.ptrs.len() as u64;
+            self.ptrs.insert_presorted((0..chunk_len * repeat).map(|i| {
+                let chunk = i / chunk_len;
+                let (offset, reloc) = copy.ptrs[(i % chunk_len) as usize];
+                (shift_offset(chunk, offset), reloc)
+            }));
         }
-        if let Some(dest_bytes) = copy.dest_bytes
-            && !dest_bytes.is_empty()
-        {
-            self.bytes.get_or_insert_with(Box::default).insert_presorted(dest_bytes.into());
+        if !copy.bytes.is_empty() {
+            let chunk_len = copy.bytes.len() as u64;
+            self.bytes.get_or_insert_with(Box::default).insert_presorted(
+                (0..chunk_len * repeat).map(|i| {
+                    let chunk = i / chunk_len;
+                    let (offset, reloc) = copy.bytes[(i % chunk_len) as usize];
+                    (shift_offset(chunk, offset), reloc)
+                }),
+            );
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 07a15b3cd18..81df239dee4 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1475,3 +1475,20 @@ impl PlaceContext {
         }
     }
 }
+
+/// Small utility to visit places and locals without manually implementing a full visitor.
+pub struct VisitPlacesWith<F>(pub F);
+
+impl<'tcx, F> Visitor<'tcx> for VisitPlacesWith<F>
+where
+    F: FnMut(Place<'tcx>, PlaceContext),
+{
+    fn visit_local(&mut self, local: Local, ctxt: PlaceContext, _: Location) {
+        (self.0)(local.into(), ctxt);
+    }
+
+    fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, location: Location) {
+        (self.0)(*place, ctxt);
+        self.visit_projection(place.as_ref(), ctxt, location);
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 79700d485c4..7d3e2c9965d 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -574,7 +574,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(..)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 2114d080dfa..9524057eebc 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -812,7 +812,7 @@ where
                 | ty::CoroutineWitness(..)
                 | ty::Foreign(..)
                 | ty::Pat(_, _)
-                | ty::Dynamic(_, _, ty::Dyn) => {
+                | ty::Dynamic(_, _) => {
                     bug!("TyAndLayout::field({:?}): not applicable", this)
                 }
 
@@ -878,7 +878,7 @@ where
                         // `std::mem::uninitialized::<&dyn Trait>()`, for example.
                         if let ty::Adt(def, args) = metadata.kind()
                             && tcx.is_lang_item(def.did(), LangItem::DynMetadata)
-                            && let ty::Dynamic(data, _, ty::Dyn) = args.type_at(0).kind()
+                            && let ty::Dynamic(data, _) = args.type_at(0).kind()
                         {
                             mk_dyn_vtable(data.principal())
                         } else {
@@ -887,7 +887,7 @@ where
                     } else {
                         match tcx.struct_tail_for_codegen(pointee, cx.typing_env()).kind() {
                             ty::Slice(_) | ty::Str => tcx.types.usize,
-                            ty::Dynamic(data, _, ty::Dyn) => mk_dyn_vtable(data.principal()),
+                            ty::Dynamic(data, _) => mk_dyn_vtable(data.principal()),
                             _ => bug!("TyAndLayout::field({:?}): not applicable", this),
                         }
                     };
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index d4c001f625e..0ffef393a33 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -254,12 +254,6 @@ pub struct ImplTraitHeader<'tcx> {
     pub constness: hir::Constness,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
-pub enum ImplSubject<'tcx> {
-    Trait(TraitRef<'tcx>),
-    Inherent(Ty<'tcx>),
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub enum Asyncness {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index fc821ffdaa6..1b7ef8de845 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -784,14 +784,12 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 },
             },
             ty::Adt(def, args) => self.print_def_path(def.did(), args)?,
-            ty::Dynamic(data, r, repr) => {
+            ty::Dynamic(data, r) => {
                 let print_r = self.should_print_optional_region(r);
                 if print_r {
                     write!(self, "(")?;
                 }
-                match repr {
-                    ty::Dyn => write!(self, "dyn ")?,
-                }
+                write!(self, "dyn ")?;
                 data.print(self)?;
                 if print_r {
                     write!(self, " + ")?;
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index dc1d60f3d43..2f96970af47 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -7,30 +7,6 @@ use crate::ty::{self as ty, Ty, TyCtxt};
 
 pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>;
 
-impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> {
-    #[inline]
-    fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
-        relation: &mut R,
-        a: ty::ImplSubject<'tcx>,
-        b: ty::ImplSubject<'tcx>,
-    ) -> RelateResult<'tcx, ty::ImplSubject<'tcx>> {
-        match (a, b) {
-            (ty::ImplSubject::Trait(trait_ref_a), ty::ImplSubject::Trait(trait_ref_b)) => {
-                let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?;
-                Ok(ty::ImplSubject::Trait(trait_ref))
-            }
-            (ty::ImplSubject::Inherent(ty_a), ty::ImplSubject::Inherent(ty_b)) => {
-                let ty = Ty::relate(relation, ty_a, ty_b)?;
-                Ok(ty::ImplSubject::Inherent(ty))
-            }
-            (ty::ImplSubject::Trait(_), ty::ImplSubject::Inherent(_))
-            | (ty::ImplSubject::Inherent(_), ty::ImplSubject::Trait(_)) => {
-                bug!("can not relate TraitRef and Ty");
-            }
-        }
-    }
-}
-
 impl<'tcx> Relate<TyCtxt<'tcx>> for Ty<'tcx> {
     #[inline]
     fn relate<R: TypeRelation<TyCtxt<'tcx>>>(
diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs
index 5ada9ecc80c..f1aa7076d98 100644
--- a/compiler/rustc_middle/src/ty/significant_drop_order.rs
+++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs
@@ -132,7 +132,7 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
         | ty::Ref(_, _, _)
         | ty::FnPtr(_, _)
         | ty::Tuple(_)
-        | ty::Dynamic(_, _, _)
+        | ty::Dynamic(_, _)
         | ty::Alias(_, _)
         | ty::Bound(_, _)
         | ty::Pat(_, _)
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 89ef46b1ae5..11d109b463d 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -390,11 +390,9 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
             ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?),
             ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?),
             ty::Adt(tid, args) => ty::Adt(tid, args.try_fold_with(folder)?),
-            ty::Dynamic(trait_ty, region, representation) => ty::Dynamic(
-                trait_ty.try_fold_with(folder)?,
-                region.try_fold_with(folder)?,
-                representation,
-            ),
+            ty::Dynamic(trait_ty, region) => {
+                ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?)
+            }
             ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?),
             ty::FnDef(def_id, args) => ty::FnDef(def_id, args.try_fold_with(folder)?),
             ty::FnPtr(sig_tys, hdr) => ty::FnPtr(sig_tys.try_fold_with(folder)?, hdr),
@@ -437,8 +435,8 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
             ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
             ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
             ty::Adt(tid, args) => ty::Adt(tid, args.fold_with(folder)),
-            ty::Dynamic(trait_ty, region, representation) => {
-                ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder), representation)
+            ty::Dynamic(trait_ty, region) => {
+                ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
             }
             ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
             ty::FnDef(def_id, args) => ty::FnDef(def_id, args.fold_with(folder)),
@@ -481,7 +479,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
             }
             ty::Slice(typ) => typ.visit_with(visitor),
             ty::Adt(_, args) => args.visit_with(visitor),
-            ty::Dynamic(trait_ty, reg, _) => {
+            ty::Dynamic(trait_ty, reg) => {
                 try_visit!(trait_ty.visit_with(visitor));
                 reg.visit_with(visitor)
             }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 755fc68d86f..2bea7977999 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -17,7 +17,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 use rustc_type_ir::TyKind::*;
 use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::walk::TypeWalker;
-use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate};
+use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, TypeVisitableExt, elaborate};
 use tracing::instrument;
 use ty::util::IntTypeExt;
 
@@ -734,7 +734,6 @@ impl<'tcx> Ty<'tcx> {
         tcx: TyCtxt<'tcx>,
         obj: &'tcx List<ty::PolyExistentialPredicate<'tcx>>,
         reg: ty::Region<'tcx>,
-        repr: DynKind,
     ) -> Ty<'tcx> {
         if cfg!(debug_assertions) {
             let projection_count = obj
@@ -767,7 +766,7 @@ impl<'tcx> Ty<'tcx> {
                 but it has {projection_count}"
             );
         }
-        Ty::new(tcx, Dynamic(obj, reg, repr))
+        Ty::new(tcx, Dynamic(obj, reg))
     }
 
     #[inline]
@@ -980,9 +979,8 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
         interner: TyCtxt<'tcx>,
         preds: &'tcx List<ty::PolyExistentialPredicate<'tcx>>,
         region: ty::Region<'tcx>,
-        kind: ty::DynKind,
     ) -> Self {
-        Ty::new_dynamic(interner, preds, region, kind)
+        Ty::new_dynamic(interner, preds, region)
     }
 
     fn new_coroutine(
@@ -1356,7 +1354,7 @@ impl<'tcx> Ty<'tcx> {
 
     #[inline]
     pub fn is_trait(self) -> bool {
-        matches!(self.kind(), Dynamic(_, _, ty::Dyn))
+        matches!(self.kind(), Dynamic(_, _))
     }
 
     #[inline]
@@ -1671,7 +1669,7 @@ impl<'tcx> Ty<'tcx> {
 
             ty::Str | ty::Slice(_) => Ok(tcx.types.usize),
 
-            ty::Dynamic(_, _, ty::Dyn) => {
+            ty::Dynamic(_, _) => {
                 let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, DUMMY_SP);
                 Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]))
             }
@@ -1853,7 +1851,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Never
             | ty::Error(_) => true,
 
-            ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
+            ty::Str | ty::Slice(_) | ty::Dynamic(_, _) => match sizedness {
                 SizedTraitKind::Sized => false,
                 SizedTraitKind::MetaSized => true,
             },
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index f38bb445824..72d4cd72c2b 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -152,7 +152,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                     | ty::Slice(_)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(..)
-                    | ty::Dynamic(_, _, _)
+                    | ty::Dynamic(_, _)
                     | ty::Closure(..)
                     | ty::CoroutineClosure(..)
                     | ty::Coroutine(_, _)
@@ -196,7 +196,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                     | ty::Ref(_, _, _)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(..)
-                    | ty::Dynamic(_, _, _)
+                    | ty::Dynamic(_, _)
                     | ty::CoroutineWitness(..)
                     | ty::Never
                     | ty::UnsafeBinder(_)
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 08316aaed3b..c1cd2788348 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1884,7 +1884,7 @@ fn check_must_not_suspend_ty<'tcx>(
             }
             has_emitted
         }
-        ty::Dynamic(binder, _, _) => {
+        ty::Dynamic(binder, _) => {
             let mut has_emitted = false;
             for predicate in binder.iter() {
                 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index c57483a6811..74c22ff10c1 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -141,7 +141,7 @@ use rustc_data_structures::union_find::UnionFind;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_index::interval::SparseIntervalMatrix;
 use rustc_index::{IndexVec, newtype_index};
-use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
+use rustc_middle::mir::visit::{MutVisitor, PlaceContext, VisitPlacesWith, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::{DefUse, MaybeLiveLocals};
@@ -153,15 +153,7 @@ pub(super) struct DestinationPropagation;
 
 impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        // For now, only run at MIR opt level 3. Two things need to be changed before this can be
-        // turned on by default:
-        //  1. Because of the overeager removal of storage statements, this can cause stack space
-        //     regressions. This opt is not the place to fix this though, it's a more general
-        //     problem in MIR.
-        //  2. Despite being an overall perf improvement, this still causes a 30% regression in
-        //     keccak. We can temporarily fix this by bounding function size, but in the long term
-        //     we should fix this by being smarter about invalidating analysis results.
-        sess.mir_opt_level() >= 3
+        sess.mir_opt_level() >= 2
     }
 
     #[tracing::instrument(level = "trace", skip(self, tcx, body))]
@@ -511,22 +503,6 @@ impl TwoStepIndex {
     }
 }
 
-struct VisitPlacesWith<F>(F);
-
-impl<'tcx, F> Visitor<'tcx> for VisitPlacesWith<F>
-where
-    F: FnMut(Place<'tcx>, PlaceContext),
-{
-    fn visit_local(&mut self, local: Local, ctxt: PlaceContext, _: Location) {
-        (self.0)(local.into(), ctxt);
-    }
-
-    fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, location: Location) {
-        (self.0)(*place, ctxt);
-        self.visit_projection(place.as_ref(), ctxt, location);
-    }
-}
-
 /// Add points depending on the result of the given dataflow analysis.
 fn save_as_intervals<'tcx>(
     elements: &DenseLocationMap,
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 1663dfa744f..9ff7e0b5500 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -156,7 +156,6 @@ declare_passes! {
     mod match_branches : MatchBranchSimplification;
     mod mentioned_items : MentionedItems;
     mod multiple_return_terminators : MultipleReturnTerminators;
-    mod nrvo : RenameReturnPlace;
     mod post_drop_elaboration : CheckLiveDrops;
     mod prettify : ReorderBasicBlocks, ReorderLocals;
     mod promote_consts : PromoteTemps;
@@ -715,7 +714,6 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
             &jump_threading::JumpThreading,
             &early_otherwise_branch::EarlyOtherwiseBranch,
             &simplify_comparison_integral::SimplifyComparisonIntegral,
-            &dest_prop::DestinationPropagation,
             &o1(simplify_branches::SimplifyConstCondition::Final),
             &o1(remove_noop_landing_pads::RemoveNoopLandingPads),
             &o1(simplify::SimplifyCfg::Final),
@@ -723,7 +721,7 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'
             &strip_debuginfo::StripDebugInfo,
             &copy_prop::CopyProp,
             &dead_store_elimination::DeadStoreElimination::Final,
-            &nrvo::RenameReturnPlace,
+            &dest_prop::DestinationPropagation,
             &simplify::SimplifyLocals::Final,
             &multiple_return_terminators::MultipleReturnTerminators,
             &large_enums::EnumSizeOpt { discrepancy: 128 },
diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs
index f472c7cb493..2ab49645dc4 100644
--- a/compiler/rustc_mir_transform/src/lint.rs
+++ b/compiler/rustc_mir_transform/src/lint.rs
@@ -6,7 +6,7 @@ use std::borrow::Cow;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::DenseBitSet;
-use rustc_middle::mir::visit::{PlaceContext, Visitor};
+use rustc_middle::mir::visit::{PlaceContext, VisitPlacesWith, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 use rustc_mir_dataflow::impls::{MaybeStorageDead, MaybeStorageLive, always_storage_live_locals};
@@ -79,15 +79,39 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         match &statement.kind {
             StatementKind::Assign(box (dest, rvalue)) => {
-                if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue {
-                    // The sides of an assignment must not alias. Currently this just checks whether
-                    // the places are identical.
-                    if dest == src {
-                        self.fail(
-                            location,
-                            "encountered `Assign` statement with overlapping memory",
-                        );
-                    }
+                let forbid_aliasing = match rvalue {
+                    Rvalue::Use(..)
+                    | Rvalue::CopyForDeref(..)
+                    | Rvalue::Repeat(..)
+                    | Rvalue::Aggregate(..)
+                    | Rvalue::Cast(..)
+                    | Rvalue::ShallowInitBox(..)
+                    | Rvalue::WrapUnsafeBinder(..) => true,
+                    Rvalue::ThreadLocalRef(..)
+                    | Rvalue::NullaryOp(..)
+                    | Rvalue::UnaryOp(..)
+                    | Rvalue::BinaryOp(..)
+                    | Rvalue::Ref(..)
+                    | Rvalue::RawPtr(..)
+                    | Rvalue::Discriminant(..) => false,
+                };
+                // The sides of an assignment must not alias.
+                if forbid_aliasing {
+                    VisitPlacesWith(|src: Place<'tcx>, _| {
+                        if *dest == src
+                            || (dest.local == src.local
+                                && !dest.is_indirect()
+                                && !src.is_indirect())
+                        {
+                            self.fail(
+                                location,
+                                format!(
+                                    "encountered `{statement:?}` statement with overlapping memory"
+                                ),
+                            );
+                        }
+                    })
+                    .visit_rvalue(rvalue, location);
                 }
             }
             StatementKind::StorageLive(local) => {
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
deleted file mode 100644
index 965002aae04..00000000000
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ /dev/null
@@ -1,234 +0,0 @@
-//! See the docs for [`RenameReturnPlace`].
-
-use rustc_hir::Mutability;
-use rustc_index::bit_set::DenseBitSet;
-use rustc_middle::bug;
-use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{self, BasicBlock, Local, Location};
-use rustc_middle::ty::TyCtxt;
-use tracing::{debug, trace};
-
-/// This pass looks for MIR that always copies the same local into the return place and eliminates
-/// the copy by renaming all uses of that local to `_0`.
-///
-/// This allows LLVM to perform an optimization similar to the named return value optimization
-/// (NRVO) that is guaranteed in C++. This avoids a stack allocation and `memcpy` for the
-/// relatively common pattern of allocating a buffer on the stack, mutating it, and returning it by
-/// value like so:
-///
-/// ```rust
-/// fn foo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
-///     let mut buf = [0; 1024];
-///     init(&mut buf);
-///     buf
-/// }
-/// ```
-///
-/// For now, this pass is very simple and only capable of eliminating a single copy. A more general
-/// version of copy propagation, such as the one based on non-overlapping live ranges in [#47954] and
-/// [#71003], could yield even more benefits.
-///
-/// [#47954]: https://github.com/rust-lang/rust/pull/47954
-/// [#71003]: https://github.com/rust-lang/rust/pull/71003
-pub(super) struct RenameReturnPlace;
-
-impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
-    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        // unsound: #111005
-        sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts
-    }
-
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
-        let def_id = body.source.def_id();
-        let Some(returned_local) = local_eligible_for_nrvo(body) else {
-            debug!("`{:?}` was ineligible for NRVO", def_id);
-            return;
-        };
-
-        debug!(
-            "`{:?}` was eligible for NRVO, making {:?} the return place",
-            def_id, returned_local
-        );
-
-        RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body_preserves_cfg(body);
-
-        // Clean up the `NOP`s we inserted for statements made useless by our renaming.
-        for block_data in body.basic_blocks.as_mut_preserves_cfg() {
-            block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop);
-        }
-
-        // Overwrite the debuginfo of `_0` with that of the renamed local.
-        let (renamed_decl, ret_decl) =
-            body.local_decls.pick2_mut(returned_local, mir::RETURN_PLACE);
-
-        // Sometimes, the return place is assigned a local of a different but coercible type, for
-        // example `&mut T` instead of `&T`. Overwriting the `LocalInfo` for the return place means
-        // its type may no longer match the return type of its function. This doesn't cause a
-        // problem in codegen because these two types are layout-compatible, but may be unexpected.
-        debug!("_0: {:?} = {:?}: {:?}", ret_decl.ty, returned_local, renamed_decl.ty);
-        ret_decl.clone_from(renamed_decl);
-
-        // The return place is always mutable.
-        ret_decl.mutability = Mutability::Mut;
-    }
-
-    fn is_required(&self) -> bool {
-        false
-    }
-}
-
-/// MIR that is eligible for the NRVO must fulfill two conditions:
-///   1. The return place must not be read prior to the `Return` terminator.
-///   2. A simple assignment of a whole local to the return place (e.g., `_0 = _1`) must be the
-///      only definition of the return place reaching the `Return` terminator.
-///
-/// If the MIR fulfills both these conditions, this function returns the `Local` that is assigned
-/// to the return place along all possible paths through the control-flow graph.
-fn local_eligible_for_nrvo(body: &mir::Body<'_>) -> Option<Local> {
-    if IsReturnPlaceRead::run(body) {
-        return None;
-    }
-
-    let mut copied_to_return_place = None;
-    for block in body.basic_blocks.indices() {
-        // Look for blocks with a `Return` terminator.
-        if !matches!(body[block].terminator().kind, mir::TerminatorKind::Return) {
-            continue;
-        }
-
-        // Look for an assignment of a single local to the return place prior to the `Return`.
-        let returned_local = find_local_assigned_to_return_place(block, body)?;
-        match body.local_kind(returned_local) {
-            // FIXME: Can we do this for arguments as well?
-            mir::LocalKind::Arg => return None,
-
-            mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"),
-            mir::LocalKind::Temp => {}
-        }
-
-        // If multiple different locals are copied to the return place. We can't pick a
-        // single one to rename.
-        if copied_to_return_place.is_some_and(|old| old != returned_local) {
-            return None;
-        }
-
-        copied_to_return_place = Some(returned_local);
-    }
-
-    copied_to_return_place
-}
-
-fn find_local_assigned_to_return_place(start: BasicBlock, body: &mir::Body<'_>) -> Option<Local> {
-    let mut block = start;
-    let mut seen = DenseBitSet::new_empty(body.basic_blocks.len());
-
-    // Iterate as long as `block` has exactly one predecessor that we have not yet visited.
-    while seen.insert(block) {
-        trace!("Looking for assignments to `_0` in {:?}", block);
-
-        let local = body[block].statements.iter().rev().find_map(as_local_assigned_to_return_place);
-        if local.is_some() {
-            return local;
-        }
-
-        match body.basic_blocks.predecessors()[block].as_slice() {
-            &[pred] => block = pred,
-            _ => return None,
-        }
-    }
-
-    None
-}
-
-// If this statement is an assignment of an unprojected local to the return place,
-// return that local.
-fn as_local_assigned_to_return_place(stmt: &mir::Statement<'_>) -> Option<Local> {
-    if let mir::StatementKind::Assign(box (lhs, rhs)) = &stmt.kind {
-        if lhs.as_local() == Some(mir::RETURN_PLACE) {
-            if let mir::Rvalue::Use(mir::Operand::Copy(rhs) | mir::Operand::Move(rhs)) = rhs {
-                return rhs.as_local();
-            }
-        }
-    }
-
-    None
-}
-
-struct RenameToReturnPlace<'tcx> {
-    to_rename: Local,
-    tcx: TyCtxt<'tcx>,
-}
-
-/// Replaces all uses of `self.to_rename` with `_0`.
-impl<'tcx> MutVisitor<'tcx> for RenameToReturnPlace<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_statement(&mut self, stmt: &mut mir::Statement<'tcx>, loc: Location) {
-        // Remove assignments of the local being replaced to the return place, since it is now the
-        // return place:
-        //     _0 = _1
-        if as_local_assigned_to_return_place(stmt) == Some(self.to_rename) {
-            stmt.kind = mir::StatementKind::Nop;
-            return;
-        }
-
-        // Remove storage annotations for the local being replaced:
-        //     StorageLive(_1)
-        if let mir::StatementKind::StorageLive(local) | mir::StatementKind::StorageDead(local) =
-            stmt.kind
-        {
-            if local == self.to_rename {
-                stmt.kind = mir::StatementKind::Nop;
-                return;
-            }
-        }
-
-        self.super_statement(stmt, loc)
-    }
-
-    fn visit_terminator(&mut self, terminator: &mut mir::Terminator<'tcx>, loc: Location) {
-        // Ignore the implicit "use" of the return place in a `Return` statement.
-        if let mir::TerminatorKind::Return = terminator.kind {
-            return;
-        }
-
-        self.super_terminator(terminator, loc);
-    }
-
-    fn visit_local(&mut self, l: &mut Local, ctxt: PlaceContext, _: Location) {
-        if *l == mir::RETURN_PLACE {
-            assert_eq!(ctxt, PlaceContext::NonUse(NonUseContext::VarDebugInfo));
-        } else if *l == self.to_rename {
-            *l = mir::RETURN_PLACE;
-        }
-    }
-}
-
-struct IsReturnPlaceRead(bool);
-
-impl IsReturnPlaceRead {
-    fn run(body: &mir::Body<'_>) -> bool {
-        let mut vis = IsReturnPlaceRead(false);
-        vis.visit_body(body);
-        vis.0
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for IsReturnPlaceRead {
-    fn visit_local(&mut self, l: Local, ctxt: PlaceContext, _: Location) {
-        if l == mir::RETURN_PLACE && ctxt.is_use() && !ctxt.is_place_assignment() {
-            self.0 = true;
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, loc: Location) {
-        // Ignore the implicit "use" of the return place in a `Return` statement.
-        if let mir::TerminatorKind::Return = terminator.kind {
-            return;
-        }
-
-        self.super_terminator(terminator, loc);
-    }
-}
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index a8f2b4e8db6..4b4ec4956eb 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -390,7 +390,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             | ty::FnDef(_, _)
             | ty::FnPtr(..)
             | ty::UnsafeBinder(_)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index fb777496e31..7de7870bbb1 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -86,7 +86,7 @@ where
     ) -> Result<Candidate<I>, NoSolution> {
         Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
             let cx = ecx.cx();
-            let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {
+            let ty::Dynamic(bounds, _) = goal.predicate.self_ty().kind() else {
                 panic!("expected object type in `probe_and_consider_object_bound_candidate`");
             };
             match structural_traits::predicates_for_object_candidate(
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index f6eab286ba7..c40739d12e6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -383,7 +383,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern
         | ty::Slice(_)
         | ty::RawPtr(_, _)
         | ty::Ref(_, _, _)
-        | ty::Dynamic(_, _, _)
+        | ty::Dynamic(_, _)
         | ty::Coroutine(_, _)
         | ty::CoroutineWitness(..)
         | ty::Never
@@ -557,7 +557,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
         | ty::Slice(_)
         | ty::RawPtr(_, _)
         | ty::Ref(_, _, _)
-        | ty::Dynamic(_, _, _)
+        | ty::Dynamic(_, _)
         | ty::Coroutine(_, _)
         | ty::CoroutineWitness(..)
         | ty::Never
@@ -706,7 +706,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
         | ty::Slice(_)
         | ty::RawPtr(_, _)
         | ty::Ref(_, _, _)
-        | ty::Dynamic(_, _, _)
+        | ty::Dynamic(_, _)
         | ty::Coroutine(_, _)
         | ty::CoroutineWitness(..)
         | ty::Never
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 54b92ebac1d..653c59c5d42 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -665,7 +665,7 @@ where
 
             ty::Str | ty::Slice(_) => Ty::new_usize(cx),
 
-            ty::Dynamic(_, _, ty::Dyn) => {
+            ty::Dynamic(_, _) => {
                 let dyn_metadata = cx.require_lang_item(SolverLangItem::DynMetadata);
                 cx.type_of(dyn_metadata)
                     .instantiate(cx, &[I::GenericArg::from(goal.predicate.self_ty())])
@@ -916,7 +916,7 @@ where
             | ty::Adt(_, _)
             | ty::Str
             | ty::Slice(_)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Tuple(_)
             | ty::Error(_) => self_ty.discriminant_ty(ecx.cx()),
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index a69e867289c..3974114e9b4 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -817,15 +817,13 @@ where
                 }
 
                 // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
-                (
-                    ty::Dynamic(a_data, a_region, ty::Dyn),
-                    ty::Dynamic(b_data, b_region, ty::Dyn),
-                ) => ecx.consider_builtin_dyn_upcast_candidates(
-                    goal, a_data, a_region, b_data, b_region,
-                ),
+                (ty::Dynamic(a_data, a_region), ty::Dynamic(b_data, b_region)) => ecx
+                    .consider_builtin_dyn_upcast_candidates(
+                        goal, a_data, a_region, b_data, b_region,
+                    ),
 
                 // `T` -> `dyn Trait` unsizing.
-                (_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
+                (_, ty::Dynamic(b_region, b_data)) => result_to_single(
                     ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
                 ),
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 60f575cb844..4d5a8447695 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -246,7 +246,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::Repr { .. }
                     | AttributeKind::Cold(..)
                     | AttributeKind::ExportName { .. }
-                    | AttributeKind::CoherenceIsCore
                     | AttributeKind::Fundamental
                     | AttributeKind::Optimize(..)
                     | AttributeKind::LinkSection { .. }
@@ -278,6 +277,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::NoStd { .. }
                     | AttributeKind::ObjcClass { .. }
                     | AttributeKind::ObjcSelector { .. }
+                    | AttributeKind::RustcCoherenceIsCore(..)
                 ) => { /* do nothing  */ }
                 Attribute::Unparsed(attr_item) => {
                     style = Some(attr_item.style);
diff --git a/compiler/rustc_passes/src/check_export.rs b/compiler/rustc_passes/src/check_export.rs
index 6eded3a9eb9..fee920221e1 100644
--- a/compiler/rustc_passes/src/check_export.rs
+++ b/compiler/rustc_passes/src/check_export.rs
@@ -295,7 +295,7 @@ impl<'tcx, 'a> TypeVisitor<TyCtxt<'tcx>> for ExportableItemsChecker<'tcx, 'a> {
             | ty::Ref(_, _, _)
             | ty::Param(_)
             | ty::Closure(_, _)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Coroutine(_, _)
             | ty::Foreign(_)
             | ty::Str
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index c9bf4fe4449..d9f8085083e 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -407,7 +407,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             | ty::FnDef(_, _)
             | ty::FnPtr(..)
             | ty::Pat(_, _)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs
index bcc77ff849d..0afb94c18d7 100644
--- a/compiler/rustc_public/src/ty.rs
+++ b/compiler/rustc_public/src/ty.rs
@@ -333,7 +333,7 @@ impl TyKind {
 
     #[inline]
     pub fn is_trait(&self) -> bool {
-        matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _, DynKind::Dyn)))
+        matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _)))
     }
 
     #[inline]
@@ -472,7 +472,7 @@ impl TyKind {
     }
 
     pub fn trait_principal(&self) -> Option<Binder<ExistentialTraitRef>> {
-        if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self {
+        if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _)) = self {
             if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) =
                 predicates.first()
             {
@@ -562,7 +562,7 @@ pub enum RigidTy {
     Closure(ClosureDef, GenericArgs),
     Coroutine(CoroutineDef, GenericArgs),
     CoroutineClosure(CoroutineClosureDef, GenericArgs),
-    Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind),
+    Dynamic(Vec<Binder<ExistentialPredicate>>, Region),
     Never,
     Tuple(Vec<Ty>),
     CoroutineWitness(CoroutineWitnessDef, GenericArgs),
@@ -1207,11 +1207,6 @@ pub enum BoundRegionKind {
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
-pub enum DynKind {
-    Dyn,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
 pub enum ExistentialPredicate {
     Trait(ExistentialTraitRef),
     Projection(ExistentialProjection),
diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs
index 66f767a98f5..dc9abd88614 100644
--- a/compiler/rustc_public/src/unstable/convert/internal.rs
+++ b/compiler/rustc_public/src/unstable/convert/internal.rs
@@ -14,7 +14,7 @@ use crate::mir::alloc::AllocId;
 use crate::mir::mono::{Instance, MonoItem, StaticDef};
 use crate::mir::{BinOp, Mutability, Place, ProjectionElem, RawPtrKind, Safety, UnOp};
 use crate::ty::{
-    Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, DynKind,
+    Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind,
     ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
     GenericArgKind, GenericArgs, IntTy, MirConst, Movability, Pattern, Region, RigidTy, Span,
     TermKind, TraitRef, Ty, TyConst, UintTy, VariantDef, VariantIdx,
@@ -188,10 +188,9 @@ impl RustcInternal for RigidTy {
                 def.0.internal(tables, tcx),
                 args.internal(tables, tcx),
             ),
-            RigidTy::Dynamic(predicate, region, dyn_kind) => rustc_ty::TyKind::Dynamic(
+            RigidTy::Dynamic(predicate, region) => rustc_ty::TyKind::Dynamic(
                 tcx.mk_poly_existential_predicates(&predicate.internal(tables, tcx)),
                 region.internal(tables, tcx),
-                dyn_kind.internal(tables, tcx),
             ),
             RigidTy::Tuple(tys) => {
                 rustc_ty::TyKind::Tuple(tcx.mk_type_list(&tys.internal(tables, tcx)))
@@ -460,20 +459,6 @@ impl RustcInternal for BoundVariableKind {
     }
 }
 
-impl RustcInternal for DynKind {
-    type T<'tcx> = rustc_ty::DynKind;
-
-    fn internal<'tcx>(
-        &self,
-        _tables: &mut Tables<'_, BridgeTys>,
-        _tcx: impl InternalCx<'tcx>,
-    ) -> Self::T<'tcx> {
-        match self {
-            DynKind::Dyn => rustc_ty::DynKind::Dyn,
-        }
-    }
-}
-
 impl RustcInternal for ExistentialPredicate {
     type T<'tcx> = rustc_ty::ExistentialPredicate<'tcx>;
 
diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
index 5131611eb02..7f14f878d37 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
@@ -48,16 +48,6 @@ impl<'tcx> Stable<'tcx> for ty::AliasTerm<'tcx> {
     }
 }
 
-impl<'tcx> Stable<'tcx> for ty::DynKind {
-    type T = crate::ty::DynKind;
-
-    fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) -> Self::T {
-        match self {
-            ty::Dyn => crate::ty::DynKind::Dyn,
-        }
-    }
-}
-
 impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> {
     type T = crate::ty::ExistentialPredicate;
 
@@ -439,16 +429,13 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
             }
             // FIXME(unsafe_binders):
             ty::UnsafeBinder(_) => todo!(),
-            ty::Dynamic(existential_predicates, region, dyn_kind) => {
-                TyKind::RigidTy(RigidTy::Dynamic(
-                    existential_predicates
-                        .iter()
-                        .map(|existential_predicate| existential_predicate.stable(tables, cx))
-                        .collect(),
-                    region.stable(tables, cx),
-                    dyn_kind.stable(tables, cx),
-                ))
-            }
+            ty::Dynamic(existential_predicates, region) => TyKind::RigidTy(RigidTy::Dynamic(
+                existential_predicates
+                    .iter()
+                    .map(|existential_predicate| existential_predicate.stable(tables, cx))
+                    .collect(),
+                region.stable(tables, cx),
+            )),
             ty::Closure(def_id, generic_args) => TyKind::RigidTy(RigidTy::Closure(
                 tables.closure_def(*def_id),
                 generic_args.stable(tables, cx),
diff --git a/compiler/rustc_public/src/visitor.rs b/compiler/rustc_public/src/visitor.rs
index 87f1cc6ae69..acc33347696 100644
--- a/compiler/rustc_public/src/visitor.rs
+++ b/compiler/rustc_public/src/visitor.rs
@@ -171,7 +171,7 @@ impl Visitable for RigidTy {
             | RigidTy::CoroutineClosure(_, args)
             | RigidTy::FnDef(_, args) => args.visit(visitor),
             RigidTy::FnPtr(sig) => sig.visit(visitor),
-            RigidTy::Dynamic(pred, r, _) => {
+            RigidTy::Dynamic(pred, r) => {
                 pred.visit(visitor)?;
                 r.visit(visitor)
             }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index f4a14b36ce5..ec7a4a81a71 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -626,12 +626,10 @@ pub(crate) fn encode_ty<'tcx>(
         }
 
         // Trait types
-        ty::Dynamic(predicates, region, kind) => {
+        ty::Dynamic(predicates, region) => {
             // u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as
             // vendor extended type.
-            let mut s = String::from(match kind {
-                ty::Dyn => "u3dynI",
-            });
+            let mut s = String::from("u3dynI");
             s.push_str(&encode_predicates(tcx, predicates, dict, options));
             s.push_str(&encode_region(*region, dict));
             s.push('E');
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 577a16a0d25..82a2a64f230 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -268,7 +268,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
     let preds = tcx.mk_poly_existential_predicates_from_iter(
         iter::once(principal_pred).chain(assoc_preds.into_iter()),
     );
-    Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn)
+    Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased)
 }
 
 /// Transforms an instance for LLVM CFI and cross-language LLVM CFI support using Itanium C++ ABI
@@ -334,7 +334,7 @@ pub(crate) fn transform_instance<'tcx>(
             ty::List::empty(),
         ));
         let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
-        let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
+        let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased);
         instance.args = tcx.mk_args_trait(self_ty, List::empty());
     } else if let ty::InstanceKind::Virtual(def_id, _) = instance.def {
         // Transform self into a trait object of the trait that defines the method for virtual
@@ -347,7 +347,7 @@ pub(crate) fn transform_instance<'tcx>(
             // drop_in_place won't have a defining trait, skip the upcast
             None => instance.args.type_at(0),
         };
-        let ty::Dynamic(preds, lifetime, kind) = upcast_ty.kind() else {
+        let ty::Dynamic(preds, lifetime) = upcast_ty.kind() else {
             bug!("Tried to remove autotraits from non-dynamic type {upcast_ty}");
         };
         let self_ty = if preds.principal().is_some() {
@@ -355,7 +355,7 @@ pub(crate) fn transform_instance<'tcx>(
                 tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
                     !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
                 }));
-            Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind)
+            Ty::new_dynamic(tcx, filtered_preds, *lifetime)
         } else {
             // If there's no principal type, re-encode it as a unit, since we don't know anything
             // about it. This technically discards the knowledge that it was a type that was made
diff --git a/compiler/rustc_symbol_mangling/src/export.rs b/compiler/rustc_symbol_mangling/src/export.rs
index 76ac82cf95a..3896e06a627 100644
--- a/compiler/rustc_symbol_mangling/src/export.rs
+++ b/compiler/rustc_symbol_mangling/src/export.rs
@@ -110,7 +110,7 @@ impl<'tcx> AbiHashStable<'tcx> for Ty<'tcx> {
             | ty::RawPtr(_, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_, _)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Closure(_, _)
             | ty::CoroutineClosure(_, _)
             | ty::Coroutine(_, _)
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 1605b4958ba..9fa7e2f1003 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -577,10 +577,8 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
             // FIXME(unsafe_binder):
             ty::UnsafeBinder(..) => todo!(),
 
-            ty::Dynamic(predicates, r, kind) => {
-                self.push(match kind {
-                    ty::Dyn => "D",
-                });
+            ty::Dynamic(predicates, r) => {
+                self.push("D");
                 self.print_dyn_existential(predicates)?;
                 r.print(self)?;
             }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 3edc365c886..5b831584176 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -399,7 +399,7 @@ pub struct TraitObjectVisitor(pub FxIndexSet<DefId>);
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for TraitObjectVisitor {
     fn visit_ty(&mut self, t: Ty<'tcx>) {
         match t.kind() {
-            ty::Dynamic(preds, re, _) if re.is_static() => {
+            ty::Dynamic(preds, re) if re.is_static() => {
                 if let Some(def_id) = preds.principal_def_id() {
                     self.0.insert(def_id);
                 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index f997842a607..b0b858aa270 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -292,7 +292,7 @@ impl<T> Trait<T> for X {
                             );
                         }
                     }
-                    (ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias))
+                    (ty::Dynamic(t, _), ty::Alias(ty::Opaque, alias))
                         if let Some(def_id) = t.principal_def_id()
                             && tcx
                                 .explicit_item_self_bounds(alias.def_id)
@@ -314,9 +314,7 @@ impl<T> Trait<T> for X {
                             values.found, values.expected,
                         ));
                     }
-                    (ty::Dynamic(t, _, ty::DynKind::Dyn), _)
-                        if let Some(def_id) = t.principal_def_id() =>
-                    {
+                    (ty::Dynamic(t, _), _) if let Some(def_id) = t.principal_def_id() => {
                         let mut has_matching_impl = false;
                         tcx.for_each_relevant_impl(def_id, values.found, |did| {
                             if DeepRejectCtxt::relate_rigid_infer(tcx)
@@ -335,9 +333,7 @@ impl<T> Trait<T> for X {
                             ));
                         }
                     }
-                    (_, ty::Dynamic(t, _, ty::DynKind::Dyn))
-                        if let Some(def_id) = t.principal_def_id() =>
-                    {
+                    (_, ty::Dynamic(t, _)) if let Some(def_id) = t.principal_def_id() => {
                         let mut has_matching_impl = false;
                         tcx.for_each_relevant_impl(def_id, values.expected, |did| {
                             if DeepRejectCtxt::relate_rigid_infer(tcx)
@@ -489,7 +485,7 @@ impl<T> Trait<T> for X {
                             && let Some(then) = blk.expr
                             && def.is_box()
                             && let boxed_ty = args.type_at(0)
-                            && let ty::Dynamic(t, _, _) = boxed_ty.kind()
+                            && let ty::Dynamic(t, _) = boxed_ty.kind()
                             && let Some(def_id) = t.principal_def_id()
                             && let mut impl_def_ids = vec![]
                             && let _ =
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 518d4fe17e8..9a8ccea3aca 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -430,7 +430,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let mut alt_span = None;
                 if let Some(ty) = ty
                     && sub.is_static()
-                    && let ty::Dynamic(preds, _, ty::DynKind::Dyn) = ty.kind()
+                    && let ty::Dynamic(preds, _) = ty.kind()
                     && let Some(def_id) = preds.principal_def_id()
                 {
                     for (clause, span) in
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index f794ff632c5..b3d1b8e3888 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -554,7 +554,7 @@ fn attempt_dyn_to_enum_suggestion(
             // defaults to assuming that things are *not* sized, whereas we want to
             // fall back to assuming that things may be sized.
             match impl_type.kind() {
-                ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::DynKind::Dyn) => {
+                ty::Str | ty::Slice(_) | ty::Dynamic(_, _) => {
                     return None;
                 }
                 _ => {}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index bb5c6469f34..00c123981e1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -237,7 +237,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     }
                 }
             }
-            if let ty::Dynamic(traits, _, _) = self_ty.kind() {
+            if let ty::Dynamic(traits, _) = self_ty.kind() {
                 for t in traits.iter() {
                     if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
                         self_types.push(self.tcx.def_path_str(trait_ref.def_id));
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 f2f840581cf..37e622102e7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1131,7 +1131,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         },
                     )
                 }
-                ty::Dynamic(data, _, ty::Dyn) => data.iter().find_map(|pred| {
+                ty::Dynamic(data, _) => data.iter().find_map(|pred| {
                     if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
                         && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)
                         // for existential projection, args are shifted over by 1
@@ -1520,7 +1520,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else {
             return;
         };
-        let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else {
+        let ty::Dynamic(predicates, _) = object_ty.kind() else {
             return;
         };
         let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty);
@@ -1883,7 +1883,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let ObligationCauseCode::SizedReturnType = obligation.cause.code() else {
             return false;
         };
-        let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else {
+        let ty::Dynamic(_, _) = trait_pred.self_ty().skip_binder().kind() else {
             return false;
         };
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 62795c8a3a6..60f1fcb26c0 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -669,7 +669,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // These may potentially implement `FnPtr`
                 ty::Placeholder(..)
-                | ty::Dynamic(_, _, _)
+                | ty::Dynamic(_, _)
                 | ty::Alias(_, _)
                 | ty::Infer(_)
                 | ty::Param(..)
@@ -991,7 +991,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
-            (&ty::Dynamic(a_data, a_region, ty::Dyn), &ty::Dynamic(b_data, b_region, ty::Dyn)) => {
+            (&ty::Dynamic(a_data, a_region), &ty::Dynamic(b_data, b_region)) => {
                 // Upcast coercions permit several things:
                 //
                 // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
@@ -1054,7 +1054,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             // `T` -> `Trait`
-            (_, &ty::Dynamic(_, _, ty::Dyn)) => {
+            (_, &ty::Dynamic(_, _)) => {
                 candidates.vec.push(BuiltinUnsizeCandidate);
             }
 
@@ -1327,7 +1327,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Pat(_, _)
             | ty::FnPtr(..)
             | ty::UnsafeBinder(_)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Coroutine(_, _)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 488094b15ac..7ad65a1df8e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -1023,10 +1023,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let a_ty = self.infcx.shallow_resolve(predicate.self_ty());
         let b_ty = self.infcx.shallow_resolve(predicate.trait_ref.args.type_at(1));
 
-        let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
+        let ty::Dynamic(a_data, a_region) = *a_ty.kind() else {
             bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`")
         };
-        let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
+        let ty::Dynamic(b_data, b_region) = *b_ty.kind() else {
             bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`")
         };
 
@@ -1062,10 +1062,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         debug!(?source, ?target, "confirm_builtin_unsize_candidate");
 
         Ok(match (source.kind(), target.kind()) {
-            // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
-            (&ty::Dynamic(data_a, r_a, dyn_a), &ty::Dynamic(data_b, r_b, dyn_b))
-                if dyn_a == dyn_b =>
-            {
+            // `dyn Trait + Kx + 'a` -> `dyn Trait + Ky + 'b` (auto traits and lifetime subtyping).
+            (&ty::Dynamic(data_a, r_a), &ty::Dynamic(data_b, r_b)) => {
                 // See `assemble_candidates_for_unsizing` for more info.
                 // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
                 let existential_predicates = if data_b.principal().is_some() {
@@ -1098,7 +1096,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             .map(ty::Binder::dummy),
                     )
                 };
-                let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, dyn_a);
+                let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b);
 
                 // Require that the traits involved in this upcast are **equal**;
                 // only the **lifetime bound** is changed.
@@ -1122,7 +1120,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             // `T` -> `dyn Trait`
-            (_, &ty::Dynamic(data, r, ty::Dyn)) => {
+            (_, &ty::Dynamic(data, r)) => {
                 let mut object_dids = data.auto_traits().chain(data.principal_def_id());
                 if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) {
                     return Err(SelectionError::TraitDynIncompatible(did));
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 7e8a41457d4..584c8e2a27c 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -317,7 +317,7 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
         "vtable trait ref should be normalized"
     );
 
-    let ty::Dynamic(source, _, _) = *key.self_ty().kind() else {
+    let ty::Dynamic(source, _) = *key.self_ty().kind() else {
         bug!();
     };
     let source_principal = tcx.instantiate_bound_regions_with_erased(
@@ -384,13 +384,13 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
     let (source, target) = key;
 
     // If the target principal is `None`, we can just return `None`.
-    let ty::Dynamic(target_data, _, _) = *target.kind() else {
+    let ty::Dynamic(target_data, _) = *target.kind() else {
         bug!();
     };
     let target_principal = tcx.instantiate_bound_regions_with_erased(target_data.principal()?);
 
     // Given that we have a target principal, it is a bug for there not to be a source principal.
-    let ty::Dynamic(source_data, _, _) = *source.kind() else {
+    let ty::Dynamic(source_data, _) = *source.kind() else {
         bug!();
     };
     let source_principal = tcx.instantiate_bound_regions_with_erased(
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index adce9850b59..45cbb56b1c2 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -915,7 +915,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // We recurse into the binder below.
             }
 
-            ty::Dynamic(data, r, _) => {
+            ty::Dynamic(data, r) => {
                 // WfObject
                 //
                 // Here, we defer WF checking due to higher-ranked
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 79f7e228e2a..643e3db8f83 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -476,7 +476,7 @@ fn layout_of_uncached<'tcx>(
         }
 
         // Odd unit types.
-        ty::FnDef(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
+        ty::FnDef(..) | ty::Dynamic(_, _) | ty::Foreign(..) => {
             let sized = matches!(ty.kind(), ty::FnDef(..));
             tcx.mk_layout(LayoutData::unit(cx, sized))
         }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index a5987757dc3..18a9a7c22d9 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -40,7 +40,7 @@ fn sizedness_constraint_for_ty<'tcx>(
         | ty::CoroutineWitness(..)
         | ty::Never => None,
 
-        ty::Str | ty::Slice(..) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
+        ty::Str | ty::Slice(..) | ty::Dynamic(_, _) => match sizedness {
             // Never `Sized`
             SizedTraitKind::Sized => Some(ty),
             // Always `MetaSized`
@@ -366,7 +366,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId)
     );
 
     match tail.kind() {
-        ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
+        ty::Dynamic(_, _) | ty::Slice(_) | ty::Str => true,
         ty::Bool
         | ty::Char
         | ty::Int(_)
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index 23b7f55fbbe..24704c5bb53 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -288,7 +288,7 @@ impl<I: Interner> FlagComputation<I> {
                 self.add_alias_ty(data);
             }
 
-            ty::Dynamic(obj, r, _) => {
+            ty::Dynamic(obj, r) => {
                 for predicate in obj.iter() {
                     self.bound_computation(predicate, |computation, predicate| match predicate {
                         ty::ExistentialPredicate::Trait(tr) => {
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index ecfc05a6e20..b5b552dbaec 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -76,12 +76,7 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_foreign(interner: I, def_id: I::ForeignId) -> Self;
 
-    fn new_dynamic(
-        interner: I,
-        preds: I::BoundExistentialPredicates,
-        region: I::Region,
-        kind: ty::DynKind,
-    ) -> Self;
+    fn new_dynamic(interner: I, preds: I::BoundExistentialPredicates, region: I::Region) -> Self;
 
     fn new_coroutine(interner: I, def_id: I::CoroutineId, args: I::GenericArgs) -> Self;
 
@@ -167,7 +162,7 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn is_guaranteed_unsized_raw(self) -> bool {
         match self.kind() {
-            ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
+            ty::Dynamic(_, _) | ty::Slice(_) | ty::Str => true,
             ty::Bool
             | ty::Char
             | ty::Int(_)
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 50b588029ae..61e0b67b163 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -57,7 +57,6 @@ mod upcast;
 mod visit;
 
 pub use AliasTyKind::*;
-pub use DynKind::*;
 pub use InferTy::*;
 pub use RegionKind::*;
 pub use TyKind::*;
diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs
index b09a378d341..c7dccea6adc 100644
--- a/compiler/rustc_type_ir/src/outlives.rs
+++ b/compiler/rustc_type_ir/src/outlives.rs
@@ -203,7 +203,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
             | ty::Ref(_, _, _)
             | ty::FnPtr(..)
             | ty::UnsafeBinder(_)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Tuple(_) => {
                 ty.super_visit_with(self);
             }
diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs
index 690a5f65e08..09add529286 100644
--- a/compiler/rustc_type_ir/src/relate.rs
+++ b/compiler/rustc_type_ir/src/relate.rs
@@ -412,16 +412,11 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
 
         (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)),
 
-        (ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr))
-            if a_repr == b_repr =>
-        {
-            Ok(Ty::new_dynamic(
-                cx,
-                relation.relate(a_obj, b_obj)?,
-                relation.relate(a_region, b_region)?,
-                a_repr,
-            ))
-        }
+        (ty::Dynamic(a_obj, a_region), ty::Dynamic(b_obj, b_region)) => Ok(Ty::new_dynamic(
+            cx,
+            relation.relate(a_obj, b_obj)?,
+            relation.relate(a_region, b_region)?,
+        )),
 
         (ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => {
             // All Coroutine types with the same id represent
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 225d85f79c3..dda59283677 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -19,20 +19,6 @@ use crate::{self as ty, DebruijnIndex, FloatTy, IntTy, Interner, UintTy};
 
 mod closure;
 
-/// Specifies how a trait object is represented.
-///
-/// This used to have a variant `DynStar`, but that variant has been removed,
-/// and it's likely this whole enum will be removed soon.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[cfg_attr(
-    feature = "nightly",
-    derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
-)]
-pub enum DynKind {
-    /// An unsized `dyn Trait` object
-    Dyn,
-}
-
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[cfg_attr(
     feature = "nightly",
@@ -165,7 +151,7 @@ pub enum TyKind<I: Interner> {
     UnsafeBinder(UnsafeBinderInner<I>),
 
     /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
-    Dynamic(I::BoundExistentialPredicates, I::Region, DynKind),
+    Dynamic(I::BoundExistentialPredicates, I::Region),
 
     /// The anonymous type of a closure. Used to represent the type of `|a| a`.
     ///
@@ -314,7 +300,7 @@ impl<I: Interner> TyKind<I> {
             | ty::FnDef(_, _)
             | ty::FnPtr(..)
             | ty::UnsafeBinder(_)
-            | ty::Dynamic(_, _, _)
+            | ty::Dynamic(_, _)
             | ty::Closure(_, _)
             | ty::CoroutineClosure(_, _)
             | ty::Coroutine(_, _)
@@ -367,9 +353,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
             FnPtr(sig_tys, hdr) => write!(f, "{:?}", sig_tys.with(*hdr)),
             // FIXME(unsafe_binder): print this like `unsafe<'a> T<'a>`.
             UnsafeBinder(binder) => write!(f, "{:?}", binder),
-            Dynamic(p, r, repr) => match repr {
-                DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"),
-            },
+            Dynamic(p, r) => write!(f, "dyn {p:?} + {r:?}"),
             Closure(d, s) => f.debug_tuple("Closure").field(d).field(&s).finish(),
             CoroutineClosure(d, s) => f.debug_tuple("CoroutineClosure").field(d).field(&s).finish(),
             Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&s).finish(),
diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs
index 9912fad1756..6d51817a7bf 100644
--- a/compiler/rustc_type_ir/src/walk.rs
+++ b/compiler/rustc_type_ir/src/walk.rs
@@ -109,7 +109,7 @@ fn push_inner<I: Interner>(stack: &mut TypeWalkerStack<I>, parent: I::GenericArg
             ty::Alias(_, data) => {
                 stack.extend(data.args.iter().rev());
             }
-            ty::Dynamic(obj, lt, _) => {
+            ty::Dynamic(obj, lt) => {
                 stack.push(lt.into());
                 stack.extend(
                     obj.iter()
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 98c9f6b51ab..7d2dd12c6ea 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -640,7 +640,7 @@ impl<T> Box<[T]> {
     /// values[0].write(1);
     /// values[1].write(2);
     /// values[2].write(3);
-    /// let values = unsafe {values.assume_init() };
+    /// let values = unsafe { values.assume_init() };
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
diff --git a/library/std/src/sys/args/zkvm.rs b/library/std/src/sys/args/zkvm.rs
index 194ba7159d4..d26bf1eaff9 100644
--- a/library/std/src/sys/args/zkvm.rs
+++ b/library/std/src/sys/args/zkvm.rs
@@ -1,25 +1,20 @@
-use crate::ffi::OsString;
-use crate::fmt;
-use crate::sys::os_str;
+use crate::ffi::{OsStr, OsString};
+use crate::num::NonZero;
+use crate::sync::OnceLock;
 use crate::sys::pal::{WORD_SIZE, abi};
-use crate::sys_common::FromInner;
-
-pub struct Args {
-    i_forward: usize,
-    i_back: usize,
-    count: usize,
-}
+use crate::{fmt, ptr, slice};
 
 pub fn args() -> Args {
-    let count = unsafe { abi::sys_argc() };
-    Args { i_forward: 0, i_back: 0, count }
+    Args { iter: ARGS.get_or_init(|| get_args()).iter() }
 }
 
-impl Args {
-    /// Use sys_argv to get the arg at the requested index. Does not check that i is less than argc
-    /// and will not return if the index is out of bounds.
-    fn argv(i: usize) -> OsString {
-        let arg_len = unsafe { abi::sys_argv(crate::ptr::null_mut(), 0, i) };
+fn get_args() -> Vec<&'static OsStr> {
+    let argc = unsafe { abi::sys_argc() };
+    let mut args = Vec::with_capacity(argc);
+
+    for i in 0..argc {
+        // Get the size of the argument then the data.
+        let arg_len = unsafe { abi::sys_argv(ptr::null_mut(), 0, i) };
 
         let arg_len_words = (arg_len + WORD_SIZE - 1) / WORD_SIZE;
         let words = unsafe { abi::sys_alloc_words(arg_len_words) };
@@ -27,20 +22,24 @@ impl Args {
         let arg_len2 = unsafe { abi::sys_argv(words, arg_len_words, i) };
         debug_assert_eq!(arg_len, arg_len2);
 
-        // Convert to OsString.
-        //
-        // FIXME: We can probably get rid of the extra copy here if we
-        // reimplement "os_str" instead of just using the generic unix
-        // "os_str".
-        let arg_bytes: &[u8] =
-            unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, arg_len) };
-        OsString::from_inner(os_str::Buf { inner: arg_bytes.to_vec() })
+        let arg_bytes = unsafe { slice::from_raw_parts(words.cast(), arg_len) };
+        args.push(unsafe { OsStr::from_encoded_bytes_unchecked(arg_bytes) });
     }
+    args
 }
 
+static ARGS: OnceLock<Vec<&'static OsStr>> = OnceLock::new();
+
+pub struct Args {
+    iter: slice::Iter<'static, &'static OsStr>,
+}
+
+impl !Send for Args {}
+impl !Sync for Args {}
+
 impl fmt::Debug for Args {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().finish()
+        self.iter.as_slice().fmt(f)
     }
 }
 
@@ -48,34 +47,48 @@ impl Iterator for Args {
     type Item = OsString;
 
     fn next(&mut self) -> Option<OsString> {
-        if self.i_forward >= self.count - self.i_back {
-            None
-        } else {
-            let arg = Self::argv(self.i_forward);
-            self.i_forward += 1;
-            Some(arg)
-        }
+        self.iter.next().map(|arg| arg.to_os_string())
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.count, Some(self.count))
+        self.iter.size_hint()
     }
-}
 
-impl ExactSizeIterator for Args {
-    fn len(&self) -> usize {
-        self.count
+    #[inline]
+    fn count(self) -> usize {
+        self.iter.len()
+    }
+
+    fn last(self) -> Option<OsString> {
+        self.iter.last().map(|arg| arg.to_os_string())
+    }
+
+    #[inline]
+    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.iter.advance_by(n)
     }
 }
 
 impl DoubleEndedIterator for Args {
     fn next_back(&mut self) -> Option<OsString> {
-        if self.i_back >= self.count - self.i_forward {
-            None
-        } else {
-            let arg = Self::argv(self.count - 1 - self.i_back);
-            self.i_back += 1;
-            Some(arg)
-        }
+        self.iter.next_back().map(|arg| arg.to_os_string())
+    }
+
+    #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+        self.iter.advance_back_by(n)
+    }
+}
+
+impl ExactSizeIterator for Args {
+    #[inline]
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
     }
 }
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 19e87f9c293..effd33d288f 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1193,8 +1193,6 @@ class RustBuild(object):
             return "<commit>"
         cmd = [
             "git",
-            "-C",
-            repo_path,
             "rev-list",
             "--author",
             author_email,
@@ -1202,7 +1200,9 @@ class RustBuild(object):
             "HEAD",
         ]
         try:
-            commit = subprocess.check_output(cmd, universal_newlines=True).strip()
+            commit = subprocess.check_output(
+                cmd, universal_newlines=True, cwd=repo_path
+            ).strip()
             return commit or "<commit>"
         except subprocess.CalledProcessError:
             return "<commit>"
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index b05a5cc8b81..1915986be28 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -340,6 +340,11 @@ o(
     "don't truncate options when printing them in this configure script",
 )
 v("set", None, "set arbitrary key/value pairs in TOML configuration")
+v(
+    "parallel-frontend-threads",
+    "rust.parallel-frontend-threads",
+    "number of parallel threads for rustc compilation",
+)
 
 
 def p(msg):
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 1458b0beefa..14104d7d1d7 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1357,10 +1357,6 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
         cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
     }
 
-    if builder.config.llvm_enzyme {
-        cargo.rustflag("--cfg=llvm_enzyme");
-    }
-
     // These conditionals represent a tension between three forces:
     // - For non-check builds, we need to define some LLVM-related environment
     //   variables, requiring LLVM to have been built.
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 8e65ec7ce50..6121bf7d9cd 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -679,6 +679,12 @@ impl Builder<'_> {
         // cargo would implicitly add it, it was discover that sometimes bootstrap only use
         // `rustflags` without `cargo` making it required.
         rustflags.arg("-Zunstable-options");
+
+        // Add parallel frontend threads configuration
+        if let Some(threads) = self.config.rust_parallel_frontend_threads {
+            rustflags.arg(&format!("-Zthreads={threads}"));
+        }
+
         for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
             if restricted_mode.is_none() || *restricted_mode == Some(mode) {
                 rustflags.arg(&check_cfg_arg(name, *values));
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 0213047f3a1..efb7ad91699 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -191,7 +191,6 @@ pub struct Config {
     pub rust_optimize: RustOptimize,
     pub rust_codegen_units: Option<u32>,
     pub rust_codegen_units_std: Option<u32>,
-
     pub rustc_debug_assertions: bool,
     pub std_debug_assertions: bool,
     pub tools_debug_assertions: bool,
@@ -222,6 +221,8 @@ pub struct Config {
     pub rust_validate_mir_opts: Option<u32>,
     pub rust_std_features: BTreeSet<String>,
     pub rust_break_on_ice: bool,
+    pub rust_parallel_frontend_threads: Option<u32>,
+
     pub llvm_profile_use: Option<String>,
     pub llvm_profile_generate: bool,
     pub llvm_libunwind_default: Option<LlvmLibunwind>,
@@ -534,6 +535,7 @@ impl Config {
             backtrace_on_ice: rust_backtrace_on_ice,
             verify_llvm_ir: rust_verify_llvm_ir,
             thin_lto_import_instr_limit: rust_thin_lto_import_instr_limit,
+            parallel_frontend_threads: rust_parallel_frontend_threads,
             remap_debuginfo: rust_remap_debuginfo,
             jemalloc: rust_jemalloc,
             test_compare_mode: rust_test_compare_mode,
@@ -1298,6 +1300,7 @@ impl Config {
             rust_overflow_checks_std: rust_overflow_checks_std
                 .or(rust_overflow_checks)
                 .unwrap_or(rust_debug == Some(true)),
+            rust_parallel_frontend_threads: rust_parallel_frontend_threads.map(threads_from_config),
             rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate),
             rust_profile_use: flags_rust_profile_use.or(rust_profile_use),
             rust_randomize_layout: rust_randomize_layout.unwrap_or(false),
diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs
index 4832a1d37b7..e5987d7040a 100644
--- a/src/bootstrap/src/core/config/toml/rust.rs
+++ b/src/bootstrap/src/core/config/toml/rust.rs
@@ -66,6 +66,7 @@ define_config! {
         validate_mir_opts: Option<u32> = "validate-mir-opts",
         std_features: Option<BTreeSet<String>> = "std-features",
         break_on_ice: Option<bool> = "break-on-ice",
+        parallel_frontend_threads: Option<u32> = "parallel-frontend-threads",
     }
 }
 
@@ -357,6 +358,7 @@ pub fn check_incompatible_options_for_ci_rustc(
         validate_mir_opts: _,
         frame_pointers: _,
         break_on_ice: _,
+        parallel_frontend_threads: _,
     } = ci_rust_config;
 
     // There are two kinds of checks for CI rustc incompatible options:
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index a2aeed20948..e953fe2945e 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -87,9 +87,6 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
     (Some(Mode::Codegen), "bootstrap", None),
     (Some(Mode::ToolRustcPrivate), "bootstrap", None),
     (Some(Mode::ToolStd), "bootstrap", None),
-    (Some(Mode::Rustc), "llvm_enzyme", None),
-    (Some(Mode::Codegen), "llvm_enzyme", None),
-    (Some(Mode::ToolRustcPrivate), "llvm_enzyme", None),
     (Some(Mode::ToolRustcPrivate), "rust_analyzer", None),
     (Some(Mode::ToolStd), "rust_analyzer", None),
     // Any library specific cfgs like `target_os`, `target_arch` should be put in
@@ -869,6 +866,9 @@ impl Build {
         if (self.config.llvm_enabled(target) || kind == Kind::Check) && check("llvm") {
             features.push("llvm");
         }
+        if self.config.llvm_enzyme {
+            features.push("llvm_enzyme");
+        }
         // keep in sync with `bootstrap/compile.rs:rustc_cargo_env`
         if self.config.rust_randomize_layout && check("rustc_randomized_layouts") {
             features.push("rustc_randomized_layouts");
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 03b39882e30..2c48cebd2df 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -546,4 +546,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "The default value of the `gcc.download-ci-gcc` option has been changed to `true`.",
     },
+    ChangeInfo {
+        change_id: 146458,
+        severity: ChangeSeverity::Info,
+        summary: "There is now a bootstrap option called `rust.parallel-frontend-threads`, which can be used to set the number of threads for the compiler frontend used during compilation of Rust code.",
+    },
 ];
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 5ccacafea01..0afb969d5c8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2093,7 +2093,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
             );
             Type::Path { path }
         }
-        ty::Dynamic(obj, reg, _) => {
+        ty::Dynamic(obj, reg) => {
             // HACK: pick the first `did` as the `did` of the trait object. Someone
             // might want to implement "native" support for marker-trait-only
             // trait objects.
diff --git a/src/librustdoc/display.rs b/src/librustdoc/display.rs
index aa0fad26520..db868c5c9a8 100644
--- a/src/librustdoc/display.rs
+++ b/src/librustdoc/display.rs
@@ -10,7 +10,7 @@ pub(crate) trait Joined: IntoIterator {
     ///
     /// The performance of `joined` is slightly better than `format`, since it doesn't need to use a `Cell` to keep track of whether [`fmt`](Display::fmt)
     /// was already called (`joined`'s API doesn't allow it be called more than once).
-    fn joined(self, sep: &str, f: &mut Formatter<'_>) -> fmt::Result;
+    fn joined(self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result;
 }
 
 impl<I, T> Joined for I
@@ -18,12 +18,12 @@ where
     I: IntoIterator<Item = T>,
     T: Display,
 {
-    fn joined(self, sep: &str, f: &mut Formatter<'_>) -> fmt::Result {
+    fn joined(self, sep: impl Display, f: &mut Formatter<'_>) -> fmt::Result {
         let mut iter = self.into_iter();
         let Some(first) = iter.next() else { return Ok(()) };
         first.fmt(f)?;
         for item in iter {
-            f.write_str(sep)?;
+            sep.fmt(f)?;
             item.fmt(f)?;
         }
         Ok(())
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 493fdc6fb1b..8c75f301841 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1264,6 +1264,7 @@ impl std::fmt::Write for WriteCounter {
 }
 
 // Implements Display by emitting the given number of spaces.
+#[derive(Clone, Copy)]
 struct Indent(usize);
 
 impl Display for Indent {
@@ -1275,6 +1276,37 @@ impl Display for Indent {
     }
 }
 
+impl clean::Parameter {
+    fn print(&self, cx: &Context<'_>) -> impl fmt::Display {
+        fmt::from_fn(move |f| {
+            if let Some(self_ty) = self.to_receiver() {
+                match self_ty {
+                    clean::SelfTy => f.write_str("self"),
+                    clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => {
+                        f.write_str(if f.alternate() { "&" } else { "&amp;" })?;
+                        if let Some(lt) = lifetime {
+                            write!(f, "{lt} ", lt = lt.print())?;
+                        }
+                        write!(f, "{mutability}self", mutability = mutability.print_with_space())
+                    }
+                    _ => {
+                        f.write_str("self: ")?;
+                        self_ty.print(cx).fmt(f)
+                    }
+                }
+            } else {
+                if self.is_const {
+                    write!(f, "const ")?;
+                }
+                if let Some(name) = self.name {
+                    write!(f, "{name}: ")?;
+                }
+                self.type_.print(cx).fmt(f)
+            }
+        })
+    }
+}
+
 impl clean::FnDecl {
     pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
@@ -1333,63 +1365,42 @@ impl clean::FnDecl {
         f: &mut fmt::Formatter<'_>,
         cx: &Context<'_>,
     ) -> fmt::Result {
-        let amp = if f.alternate() { "&" } else { "&amp;" };
+        f.write_char('(')?;
 
-        write!(f, "(")?;
-        if let Some(n) = line_wrapping_indent
-            && !self.inputs.is_empty()
-        {
-            write!(f, "\n{}", Indent(n + 4))?;
-        }
+        if !self.inputs.is_empty() {
+            let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4));
 
-        let last_input_index = self.inputs.len().checked_sub(1);
-        for (i, param) in self.inputs.iter().enumerate() {
-            if let Some(selfty) = param.to_receiver() {
-                match selfty {
-                    clean::SelfTy => {
-                        write!(f, "self")?;
-                    }
-                    clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => {
-                        write!(f, "{amp}")?;
-                        if let Some(lt) = lifetime {
-                            write!(f, "{lt} ", lt = lt.print())?;
-                        }
-                        write!(f, "{mutability}self", mutability = mutability.print_with_space())?;
-                    }
-                    _ => {
-                        write!(f, "self: ")?;
-                        selfty.print(cx).fmt(f)?;
-                    }
-                }
-            } else {
-                if param.is_const {
-                    write!(f, "const ")?;
-                }
-                if let Some(name) = param.name {
-                    write!(f, "{name}: ")?;
+            if let Some(indent) = line_wrapping_indent {
+                write!(f, "\n{indent}")?;
+            }
+
+            let sep = fmt::from_fn(|f| {
+                if let Some(indent) = line_wrapping_indent {
+                    write!(f, ",\n{indent}")
+                } else {
+                    f.write_str(", ")
                 }
-                param.type_.print(cx).fmt(f)?;
+            });
+
+            self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?;
+
+            if line_wrapping_indent.is_some() {
+                writeln!(f, ",")?
             }
-            match (line_wrapping_indent, last_input_index) {
-                (_, None) => (),
-                (None, Some(last_i)) if i != last_i => write!(f, ", ")?,
-                (None, Some(_)) => (),
-                (Some(n), Some(last_i)) if i != last_i => write!(f, ",\n{}", Indent(n + 4))?,
-                (Some(_), Some(_)) => writeln!(f, ",")?,
+
+            if self.c_variadic {
+                match line_wrapping_indent {
+                    None => write!(f, ", ...")?,
+                    Some(indent) => writeln!(f, "{indent}...")?,
+                };
             }
         }
 
-        if self.c_variadic {
-            match line_wrapping_indent {
-                None => write!(f, ", ...")?,
-                Some(n) => writeln!(f, "{}...", Indent(n + 4))?,
-            };
+        if let Some(n) = line_wrapping_indent {
+            write!(f, "{}", Indent(n))?
         }
 
-        match line_wrapping_indent {
-            None => write!(f, ")")?,
-            Some(n) => write!(f, "{})", Indent(n))?,
-        };
+        f.write_char(')')?;
 
         self.print_output(cx).fmt(f)
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index b4ef47d1e26..6d684449b6d 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2454,11 +2454,11 @@ fn get_id_for_impl(tcx: TyCtxt<'_>, impl_id: ItemId) -> String {
             (ty, Some(ty::TraitRef::new(tcx, trait_, [ty])))
         }
         ItemId::Blanket { impl_id, .. } | ItemId::DefId(impl_id) => {
-            match tcx.impl_subject(impl_id).skip_binder() {
-                ty::ImplSubject::Trait(trait_ref) => {
-                    (trait_ref.args[0].expect_ty(), Some(trait_ref))
-                }
-                ty::ImplSubject::Inherent(ty) => (ty, None),
+            if let Some(trait_ref) = tcx.impl_trait_ref(impl_id) {
+                let trait_ref = trait_ref.skip_binder();
+                (trait_ref.self_ty(), Some(trait_ref))
+            } else {
+                (tcx.type_of(impl_id).skip_binder(), None)
             }
         }
     };
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 40fd2cdeb86..2bda6d50373 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -86,7 +86,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, msrv: Msrv)
             ty::FnPtr(..) => {
                 return Err((span, "function pointers in const fn are unstable".into()));
             },
-            ty::Dynamic(preds, _, _) => {
+            ty::Dynamic(preds, _) => {
                 for pred in *preds {
                     match pred.skip_binder() {
                         ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 9f77a1c4d9b..3e41bce1dc4 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -349,7 +349,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             }
             false
         },
-        ty::Dynamic(binder, _, _) => {
+        ty::Dynamic(binder, _) => {
             for predicate in *binder {
                 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
                     && find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { .. })
@@ -673,7 +673,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig_tys, hdr) => Some(ExprFnSig::Sig(sig_tys.with(hdr), None)),
-        ty::Dynamic(bounds, _, _) => {
+        ty::Dynamic(bounds, _) => {
             let lang_items = cx.tcx.lang_items();
             match bounds.principal() {
                 Some(bound)
diff --git a/tests/codegen-llvm/autodiff/abi_handling.rs b/tests/codegen-llvm/autodiff/abi_handling.rs
new file mode 100644
index 00000000000..454ec698b91
--- /dev/null
+++ b/tests/codegen-llvm/autodiff/abi_handling.rs
@@ -0,0 +1,210 @@
+//@ revisions: debug release
+
+//@[debug] compile-flags: -Zautodiff=Enable -C opt-level=0 -Clto=fat
+//@[release] compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+
+// This test checks that Rust types are lowered to LLVM-IR types in a way
+// we expect and Enzyme can handle. We explicitly check release mode to
+// ensure that LLVM's O3 pipeline doesn't rewrite function signatures
+// into forms that Enzyme can't process correctly.
+
+#![feature(autodiff)]
+
+use std::autodiff::{autodiff_forward, autodiff_reverse};
+
+#[derive(Copy, Clone)]
+struct Input {
+    x: f32,
+    y: f32,
+}
+
+#[derive(Copy, Clone)]
+struct Wrapper {
+    z: f32,
+}
+
+#[derive(Copy, Clone)]
+struct NestedInput {
+    x: f32,
+    y: Wrapper,
+}
+
+fn square(x: f32) -> f32 {
+    x * x
+}
+
+// CHECK-LABEL: ; abi_handling::df1
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal { float, float }
+// debug-SAME: (ptr align 4 %x, ptr align 4 %bx_0)
+// release-NEXT: define internal fastcc float
+// release-SAME: (float %x.0.val, float %x.4.val)
+
+// CHECK-LABEL: ; abi_handling::f1
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal float
+// debug-SAME: (ptr align 4 %x)
+// release-NEXT: define internal fastcc noundef float
+// release-SAME: (float %x.0.val, float %x.4.val)
+#[autodiff_forward(df1, Dual, Dual)]
+#[inline(never)]
+fn f1(x: &[f32; 2]) -> f32 {
+    x[0] + x[1]
+}
+
+// CHECK-LABEL: ; abi_handling::df2
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal { float, float }
+// debug-SAME: (ptr %f, float %x, float %dret)
+// release-NEXT: define internal fastcc float
+// release-SAME: (float noundef %x)
+
+// CHECK-LABEL: ; abi_handling::f2
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal float
+// debug-SAME: (ptr %f, float %x)
+// release-NEXT: define internal fastcc noundef float
+// release-SAME: (float noundef %x)
+#[autodiff_reverse(df2, Const, Active, Active)]
+#[inline(never)]
+fn f2(f: fn(f32) -> f32, x: f32) -> f32 {
+    f(x)
+}
+
+// CHECK-LABEL: ; abi_handling::df3
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal { float, float }
+// debug-SAME: (ptr align 4 %x, ptr align 4 %bx_0, ptr align 4 %y, ptr align 4 %by_0)
+// release-NEXT: define internal fastcc { float, float }
+// release-SAME: (float %x.0.val)
+
+// CHECK-LABEL: ; abi_handling::f3
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal float
+// debug-SAME: (ptr align 4 %x, ptr align 4 %y)
+// release-NEXT: define internal fastcc noundef float
+// release-SAME: (float %x.0.val)
+#[autodiff_forward(df3, Dual, Dual, Dual)]
+#[inline(never)]
+fn f3<'a>(x: &'a f32, y: &'a f32) -> f32 {
+    *x * *y
+}
+
+// CHECK-LABEL: ; abi_handling::df4
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal { float, float }
+// debug-SAME: (float %x.0, float %x.1, float %bx_0.0, float %bx_0.1)
+// release-NEXT: define internal fastcc { float, float }
+// release-SAME: (float noundef %x.0, float noundef %x.1)
+
+// CHECK-LABEL: ; abi_handling::f4
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal float
+// debug-SAME: (float %x.0, float %x.1)
+// release-NEXT: define internal fastcc noundef float
+// release-SAME: (float noundef %x.0, float noundef %x.1)
+#[autodiff_forward(df4, Dual, Dual)]
+#[inline(never)]
+fn f4(x: (f32, f32)) -> f32 {
+    x.0 * x.1
+}
+
+// CHECK-LABEL: ; abi_handling::df5
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal { float, float }
+// debug-SAME: (float %i.0, float %i.1, float %bi_0.0, float %bi_0.1)
+// release-NEXT: define internal fastcc { float, float }
+// release-SAME: (float noundef %i.0, float noundef %i.1)
+
+// CHECK-LABEL: ; abi_handling::f5
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal float
+// debug-SAME: (float %i.0, float %i.1)
+// release-NEXT: define internal fastcc noundef float
+// release-SAME: (float noundef %i.0, float noundef %i.1)
+#[autodiff_forward(df5, Dual, Dual)]
+#[inline(never)]
+fn f5(i: Input) -> f32 {
+    i.x + i.y
+}
+
+// CHECK-LABEL: ; abi_handling::df6
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal { float, float }
+// debug-SAME: (float %i.0, float %i.1, float %bi_0.0, float %bi_0.1)
+// release-NEXT: define internal fastcc { float, float }
+// release-SAME: float noundef %i.0, float noundef %i.1
+// release-SAME: float noundef %bi_0.0, float noundef %bi_0.1
+
+// CHECK-LABEL: ; abi_handling::f6
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal float
+// debug-SAME: (float %i.0, float %i.1)
+// release-NEXT: define internal fastcc noundef float
+// release-SAME: (float noundef %i.0, float noundef %i.1)
+#[autodiff_forward(df6, Dual, Dual)]
+#[inline(never)]
+fn f6(i: NestedInput) -> f32 {
+    i.x + i.y.z * i.y.z
+}
+
+// CHECK-LABEL: ; abi_handling::df7
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal { float, float }
+// debug-SAME: (ptr align 4 %x.0, ptr align 4 %x.1, ptr align 4 %bx_0.0, ptr align 4 %bx_0.1)
+// release-NEXT: define internal fastcc { float, float }
+// release-SAME: (float %x.0.0.val, float %x.1.0.val)
+
+// CHECK-LABEL: ; abi_handling::f7
+// CHECK-NEXT: Function Attrs
+// debug-NEXT: define internal float
+// debug-SAME: (ptr align 4 %x.0, ptr align 4 %x.1)
+// release-NEXT: define internal fastcc noundef float
+// release-SAME: (float %x.0.0.val, float %x.1.0.val)
+#[autodiff_forward(df7, Dual, Dual)]
+#[inline(never)]
+fn f7(x: (&f32, &f32)) -> f32 {
+    x.0 * x.1
+}
+
+fn main() {
+    let x = std::hint::black_box(2.0);
+    let y = std::hint::black_box(3.0);
+    let z = std::hint::black_box(4.0);
+    static Y: f32 = std::hint::black_box(3.2);
+
+    let in_f1 = [x, y];
+    dbg!(f1(&in_f1));
+    let res_f1 = df1(&in_f1, &[1.0, 0.0]);
+    dbg!(res_f1);
+
+    dbg!(f2(square, x));
+    let res_f2 = df2(square, x, 1.0);
+    dbg!(res_f2);
+
+    dbg!(f3(&x, &Y));
+    let res_f3 = df3(&x, &Y, &1.0, &0.0);
+    dbg!(res_f3);
+
+    let in_f4 = (x, y);
+    dbg!(f4(in_f4));
+    let res_f4 = df4(in_f4, (1.0, 0.0));
+    dbg!(res_f4);
+
+    let in_f5 = Input { x, y };
+    dbg!(f5(in_f5));
+    let res_f5 = df5(in_f5, Input { x: 1.0, y: 0.0 });
+    dbg!(res_f5);
+
+    let in_f6 = NestedInput { x, y: Wrapper { z: y } };
+    dbg!(f6(in_f6));
+    let res_f6 = df6(in_f6, NestedInput { x, y: Wrapper { z } });
+    dbg!(res_f6);
+
+    let in_f7 = (&x, &y);
+    dbg!(f7(in_f7));
+    let res_f7 = df7(in_f7, (&1.0, &0.0));
+    dbg!(res_f7);
+}
diff --git a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-abort.diff b/tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-abort.diff
index 6dce3ec5303..e9fbcf20a72 100644
--- a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-abort.diff
+++ b/tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `nrvo` before RenameReturnPlace
-+ // MIR for `nrvo` after RenameReturnPlace
+- // MIR for `nrvo` before DestinationPropagation
++ // MIR for `nrvo` after DestinationPropagation
   
   fn nrvo(_1: for<'a> fn(&'a mut [u8; 1024])) -> [u8; 1024] {
       debug init => _1;
@@ -10,32 +10,33 @@
       let mut _5: &mut [u8; 1024];
       let mut _6: &mut [u8; 1024];
       scope 1 {
--         debug buf => _2;
-+         debug buf => _0;
+          debug buf => _2;
       }
   
       bb0: {
--         StorageLive(_2);
--         _2 = [const 0_u8; 1024];
-+         _0 = [const 0_u8; 1024];
+          StorageLive(_2);
+          _2 = [const 0_u8; 1024];
           StorageLive(_3);
-          StorageLive(_4);
-          _4 = copy _1;
+-         StorageLive(_4);
+-         _4 = copy _1;
++         nop;
++         nop;
           StorageLive(_5);
           StorageLive(_6);
--         _6 = &mut _2;
-+         _6 = &mut _0;
+          _6 = &mut _2;
           _5 = &mut (*_6);
-          _3 = move _4(move _5) -> [return: bb1, unwind unreachable];
+-         _3 = move _4(move _5) -> [return: bb1, unwind unreachable];
++         _3 = move _1(move _5) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
           StorageDead(_5);
-          StorageDead(_4);
+-         StorageDead(_4);
++         nop;
           StorageDead(_6);
           StorageDead(_3);
--         _0 = copy _2;
--         StorageDead(_2);
+          _0 = copy _2;
+          StorageDead(_2);
           return;
       }
   }
diff --git a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff b/tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-unwind.diff
index 54cbe2871f1..95d5fe1b930 100644
--- a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `nrvo` before RenameReturnPlace
-+ // MIR for `nrvo` after RenameReturnPlace
+- // MIR for `nrvo` before DestinationPropagation
++ // MIR for `nrvo` after DestinationPropagation
   
   fn nrvo(_1: for<'a> fn(&'a mut [u8; 1024])) -> [u8; 1024] {
       debug init => _1;
@@ -10,32 +10,33 @@
       let mut _5: &mut [u8; 1024];
       let mut _6: &mut [u8; 1024];
       scope 1 {
--         debug buf => _2;
-+         debug buf => _0;
+          debug buf => _2;
       }
   
       bb0: {
--         StorageLive(_2);
--         _2 = [const 0_u8; 1024];
-+         _0 = [const 0_u8; 1024];
+          StorageLive(_2);
+          _2 = [const 0_u8; 1024];
           StorageLive(_3);
-          StorageLive(_4);
-          _4 = copy _1;
+-         StorageLive(_4);
+-         _4 = copy _1;
++         nop;
++         nop;
           StorageLive(_5);
           StorageLive(_6);
--         _6 = &mut _2;
-+         _6 = &mut _0;
+          _6 = &mut _2;
           _5 = &mut (*_6);
-          _3 = move _4(move _5) -> [return: bb1, unwind continue];
+-         _3 = move _4(move _5) -> [return: bb1, unwind continue];
++         _3 = move _1(move _5) -> [return: bb1, unwind continue];
       }
   
       bb1: {
           StorageDead(_5);
-          StorageDead(_4);
+-         StorageDead(_4);
++         nop;
           StorageDead(_6);
           StorageDead(_3);
--         _0 = copy _2;
--         StorageDead(_2);
+          _0 = copy _2;
+          StorageDead(_2);
           return;
       }
   }
diff --git a/tests/mir-opt/nrvo_simple.rs b/tests/mir-opt/dest-prop/nrvo_borrowed.rs
index df540472e1c..6f3076d4c13 100644
--- a/tests/mir-opt/nrvo_simple.rs
+++ b/tests/mir-opt/dest-prop/nrvo_borrowed.rs
@@ -1,8 +1,8 @@
 // skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-//@ test-mir-pass: RenameReturnPlace
+//@ test-mir-pass: DestinationPropagation
 
-// EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff
+// EMIT_MIR nrvo_borrowed.nrvo.DestinationPropagation.diff
 fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
     let mut buf = [0; 1024];
     init(&mut buf);
diff --git a/tests/mir-opt/nrvo_miscompile_111005.rs b/tests/mir-opt/dest-prop/nrvo_miscompile_111005.rs
index 131f7b8f6f9..17e6450278a 100644
--- a/tests/mir-opt/nrvo_miscompile_111005.rs
+++ b/tests/mir-opt/dest-prop/nrvo_miscompile_111005.rs
@@ -1,18 +1,17 @@
 // This is a miscompilation, #111005 to track
 
-//@ test-mir-pass: RenameReturnPlace
+//@ test-mir-pass: DestinationPropagation
 
 #![feature(custom_mir, core_intrinsics)]
 extern crate core;
 use core::intrinsics::mir::*;
 
-// EMIT_MIR nrvo_miscompile_111005.wrong.RenameReturnPlace.diff
+// EMIT_MIR nrvo_miscompile_111005.wrong.DestinationPropagation.diff
 #[custom_mir(dialect = "runtime", phase = "initial")]
 pub fn wrong(arg: char) -> char {
     // CHECK-LABEL: fn wrong(
     // CHECK: _0 = copy _1;
-    // FIXME: This is wrong:
-    // CHECK-NEXT: _0 = const 'b';
+    // CHECK-NEXT: _1 = const 'b';
     // CHECK-NEXT: return;
     mir! {
         {
diff --git a/tests/mir-opt/nrvo_miscompile_111005.wrong.RenameReturnPlace.diff b/tests/mir-opt/dest-prop/nrvo_miscompile_111005.wrong.DestinationPropagation.diff
index d248c76f261..60cf9236f6c 100644
--- a/tests/mir-opt/nrvo_miscompile_111005.wrong.RenameReturnPlace.diff
+++ b/tests/mir-opt/dest-prop/nrvo_miscompile_111005.wrong.DestinationPropagation.diff
@@ -1,5 +1,5 @@
-- // MIR for `wrong` before RenameReturnPlace
-+ // MIR for `wrong` after RenameReturnPlace
+- // MIR for `wrong` before DestinationPropagation
++ // MIR for `wrong` after DestinationPropagation
   
   fn wrong(_1: char) -> char {
       let mut _0: char;
@@ -9,8 +9,9 @@
 -         _2 = copy _1;
 -         _0 = copy _2;
 -         _2 = const 'b';
++         nop;
 +         _0 = copy _1;
-+         _0 = const 'b';
++         _1 = const 'b';
           return;
       }
   }
diff --git a/tests/mir-opt/pre-codegen/checked_ops.rs b/tests/mir-opt/pre-codegen/checked_ops.rs
index 8fd340503f5..dfbc0f4a110 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.rs
+++ b/tests/mir-opt/pre-codegen/checked_ops.rs
@@ -44,8 +44,7 @@ pub fn saturating_sub_at_home(lhs: u32, rhs: u32) -> u32 {
     // CHECK-LABEL: fn saturating_sub_at_home
     // CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2)
     // CHECK: [[TEMP1:_.+]] = Option::<u32>::Some({{move|copy}} [[DELTA]]);
-    // CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32);
-    // CHECK: _0 = {{move|copy}} [[TEMP2]];
+    // CHECK: _0 = {{move|copy}} (([[TEMP1]] as Some).0: u32);
     u32::checked_sub(lhs, rhs).unwrap_or(0)
 }
 
diff --git a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir
index 5b4fdeda857..dc7567b57e7 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir
@@ -10,7 +10,6 @@ fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 {
         let mut _4: u32;
     }
     scope 2 (inlined Option::<u32>::unwrap_or) {
-        let _6: u32;
         scope 3 {
         }
     }
@@ -28,10 +27,7 @@ fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 {
         _5 = Option::<u32>::Some(move _4);
         StorageDead(_4);
         StorageDead(_3);
-        StorageLive(_6);
-        _6 = move ((_5 as Some).0: u32);
-        _0 = move _6;
-        StorageDead(_6);
+        _0 = move ((_5 as Some).0: u32);
         goto -> bb3;
     }
 
diff --git a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir
index 5b4fdeda857..dc7567b57e7 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir
@@ -10,7 +10,6 @@ fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 {
         let mut _4: u32;
     }
     scope 2 (inlined Option::<u32>::unwrap_or) {
-        let _6: u32;
         scope 3 {
         }
     }
@@ -28,10 +27,7 @@ fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 {
         _5 = Option::<u32>::Some(move _4);
         StorageDead(_4);
         StorageDead(_3);
-        StorageLive(_6);
-        _6 = move ((_5 as Some).0: u32);
-        _0 = move _6;
-        StorageDead(_6);
+        _0 = move ((_5 as Some).0: u32);
         goto -> bb3;
     }
 
diff --git a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir
index 8746cb08991..e235fa35c02 100644
--- a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir
@@ -5,8 +5,9 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool {
     debug b => _2;
     let mut _0: bool;
     scope 1 (inlined <MultiField as PartialOrd>::le) {
-        let mut _11: std::option::Option<std::cmp::Ordering>;
+        let mut _6: std::option::Option<std::cmp::Ordering>;
         scope 2 (inlined Option::<std::cmp::Ordering>::is_some_and::<fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le}>) {
+            let mut _11: isize;
             let _12: std::cmp::Ordering;
             scope 3 {
                 scope 4 (inlined <fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le} as FnOnce<(std::cmp::Ordering,)>>::call_once - shim(fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le})) {
@@ -19,7 +20,6 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool {
             }
         }
         scope 7 (inlined <MultiField as PartialOrd>::partial_cmp) {
-            let mut _6: std::option::Option<std::cmp::Ordering>;
             let mut _7: i8;
             scope 8 {
             }
@@ -38,9 +38,8 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool {
 
     bb0: {
         StorageLive(_12);
-        StorageLive(_11);
-        StorageLive(_5);
         StorageLive(_6);
+        StorageLive(_5);
         StorageLive(_7);
         StorageLive(_3);
         _3 = copy ((*_1).0: char);
@@ -63,30 +62,44 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool {
         _10 = Cmp(move _8, move _9);
         StorageDead(_9);
         StorageDead(_8);
-        _11 = Option::<std::cmp::Ordering>::Some(move _10);
+        _6 = Option::<std::cmp::Ordering>::Some(move _10);
         StorageDead(_10);
         StorageDead(_7);
-        StorageDead(_6);
         StorageDead(_5);
-        goto -> bb3;
+        StorageLive(_11);
+        goto -> bb4;
     }
 
     bb2: {
-        _11 = copy _6;
         StorageDead(_7);
-        StorageDead(_6);
         StorageDead(_5);
-        goto -> bb3;
+        StorageLive(_11);
+        _11 = discriminant(_6);
+        switchInt(move _11) -> [0: bb3, 1: bb4, otherwise: bb6];
     }
 
     bb3: {
-        _12 = move ((_11 as Some).0: std::cmp::Ordering);
+        _0 = const false;
+        goto -> bb5;
+    }
+
+    bb4: {
+        _12 = move ((_6 as Some).0: std::cmp::Ordering);
         StorageLive(_13);
         _13 = discriminant(_12);
         _0 = Le(move _13, const 0_i8);
         StorageDead(_13);
+        goto -> bb5;
+    }
+
+    bb5: {
         StorageDead(_11);
+        StorageDead(_6);
         StorageDead(_12);
         return;
     }
+
+    bb6: {
+        unreachable;
+    }
 }
diff --git a/tests/mir-opt/pre-codegen/derived_ord.rs b/tests/mir-opt/pre-codegen/derived_ord.rs
index 73ae923a6cb..823e0f6d09c 100644
--- a/tests/mir-opt/pre-codegen/derived_ord.rs
+++ b/tests/mir-opt/pre-codegen/derived_ord.rs
@@ -25,7 +25,10 @@ pub fn demo_le(a: &MultiField, b: &MultiField) -> bool {
     // CHECK: Cmp(move [[A1]], move [[B1]]);
 
     // CHECK: [[D1:_[0-9]+]] = discriminant({{.+}});
-    // CHECK: _0 = Le(move [[D1]], const 0_i8);
+    // CHECK: switchInt(move [[D1]]) -> [0: bb{{[0-9]+}}, 1: bb{{[0-9]+}}, otherwise: bb{{[0-9]+}}];
+
+    // CHECK: [[D2:_[0-9]+]] = discriminant({{.+}});
+    // CHECK: _0 = Le(move [[D2]], const 0_i8);
     *a <= *b
 }
 
diff --git a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
index de25eebee77..5993bd79d27 100644
--- a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
@@ -4,10 +4,9 @@ fn <impl at $DIR/derived_ord.rs:5:10: 5:20>::partial_cmp(_1: &MultiField, _2: &M
     debug self => _1;
     debug other => _2;
     let mut _0: std::option::Option<std::cmp::Ordering>;
-    let mut _6: std::option::Option<std::cmp::Ordering>;
-    let mut _7: i8;
+    let mut _6: i8;
     scope 1 {
-        debug cmp => _6;
+        debug cmp => _0;
     }
     scope 2 (inlined std::cmp::impls::<impl PartialOrd for char>::partial_cmp) {
         let mut _3: char;
@@ -15,9 +14,9 @@ fn <impl at $DIR/derived_ord.rs:5:10: 5:20>::partial_cmp(_1: &MultiField, _2: &M
         let mut _5: std::cmp::Ordering;
     }
     scope 3 (inlined std::cmp::impls::<impl PartialOrd for i16>::partial_cmp) {
+        let mut _7: i16;
         let mut _8: i16;
-        let mut _9: i16;
-        let mut _10: std::cmp::Ordering;
+        let mut _9: std::cmp::Ordering;
     }
 
     bb0: {
@@ -28,27 +27,26 @@ fn <impl at $DIR/derived_ord.rs:5:10: 5:20>::partial_cmp(_1: &MultiField, _2: &M
         _5 = Cmp(move _3, move _4);
         StorageDead(_4);
         StorageDead(_3);
-        _6 = Option::<std::cmp::Ordering>::Some(copy _5);
-        _7 = discriminant(_5);
-        switchInt(move _7) -> [0: bb1, otherwise: bb2];
+        _0 = Option::<std::cmp::Ordering>::Some(copy _5);
+        _6 = discriminant(_5);
+        switchInt(move _6) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
-        StorageLive(_10);
-        StorageLive(_8);
-        _8 = copy ((*_1).1: i16);
         StorageLive(_9);
-        _9 = copy ((*_2).1: i16);
-        _10 = Cmp(move _8, move _9);
-        StorageDead(_9);
+        StorageLive(_7);
+        _7 = copy ((*_1).1: i16);
+        StorageLive(_8);
+        _8 = copy ((*_2).1: i16);
+        _9 = Cmp(move _7, move _8);
         StorageDead(_8);
-        _0 = Option::<std::cmp::Ordering>::Some(move _10);
-        StorageDead(_10);
+        StorageDead(_7);
+        _0 = Option::<std::cmp::Ordering>::Some(move _9);
+        StorageDead(_9);
         goto -> bb3;
     }
 
     bb2: {
-        _0 = copy _6;
         goto -> bb3;
     }
 
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
index dfe618612ab..03a52b82b49 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
@@ -5,23 +5,21 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     debug end => _2;
     debug f => _3;
     let mut _0: ();
-    let mut _4: u32;
-    let mut _9: std::option::Option<u32>;
-    let mut _11: &impl Fn(u32);
-    let mut _12: (u32,);
-    let _13: ();
+    let mut _7: std::option::Option<u32>;
+    let mut _9: &impl Fn(u32);
+    let mut _10: (u32,);
+    let _11: ();
     scope 1 {
-        debug ((iter: std::ops::Range<u32>).0: u32) => _4;
+        debug ((iter: std::ops::Range<u32>).0: u32) => _1;
         debug ((iter: std::ops::Range<u32>).1: u32) => _2;
-        let _10: u32;
+        let _8: u32;
         scope 2 {
-            debug x => _10;
+            debug x => _8;
         }
         scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) {
             scope 5 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) {
-                let mut _6: bool;
-                let _7: u32;
-                let mut _8: u32;
+                let mut _5: bool;
+                let _6: u32;
                 scope 6 {
                     scope 8 (inlined <u32 as Step>::forward_unchecked) {
                         scope 9 (inlined #[track_caller] core::num::<impl u32>::unchecked_add) {
@@ -33,7 +31,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
                     }
                 }
                 scope 7 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
-                    let mut _5: u32;
+                    let mut _4: u32;
                 }
             }
         }
@@ -42,25 +40,22 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     }
 
     bb0: {
-        StorageLive(_4);
-        _4 = copy _1;
         goto -> bb1;
     }
 
     bb1: {
-        StorageLive(_9);
-        StorageLive(_6);
+        StorageLive(_7);
         StorageLive(_5);
-        _5 = copy _4;
-        _6 = Lt(move _5, copy _2);
-        StorageDead(_5);
-        switchInt(move _6) -> [0: bb2, otherwise: bb4];
+        StorageLive(_4);
+        _4 = copy _1;
+        _5 = Lt(move _4, copy _2);
+        StorageDead(_4);
+        switchInt(move _5) -> [0: bb2, otherwise: bb4];
     }
 
     bb2: {
-        StorageDead(_6);
-        StorageDead(_9);
-        StorageDead(_4);
+        StorageDead(_5);
+        StorageDead(_7);
         drop(_3) -> [return: bb3, unwind unreachable];
     }
 
@@ -69,25 +64,22 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     }
 
     bb4: {
-        _7 = copy _4;
-        StorageLive(_8);
-        _8 = AddUnchecked(copy _7, const 1_u32);
-        _4 = move _8;
-        StorageDead(_8);
-        _9 = Option::<u32>::Some(copy _7);
-        StorageDead(_6);
-        _10 = copy ((_9 as Some).0: u32);
-        StorageLive(_11);
-        _11 = &_3;
-        StorageLive(_12);
-        _12 = (copy _10,);
-        _13 = <impl Fn(u32) as Fn<(u32,)>>::call(move _11, move _12) -> [return: bb5, unwind unreachable];
+        _6 = copy _1;
+        _1 = AddUnchecked(copy _6, const 1_u32);
+        _7 = Option::<u32>::Some(copy _6);
+        StorageDead(_5);
+        _8 = copy ((_7 as Some).0: u32);
+        StorageLive(_9);
+        _9 = &_3;
+        StorageLive(_10);
+        _10 = (copy _8,);
+        _11 = <impl Fn(u32) as Fn<(u32,)>>::call(move _9, move _10) -> [return: bb5, unwind unreachable];
     }
 
     bb5: {
-        StorageDead(_12);
-        StorageDead(_11);
+        StorageDead(_10);
         StorageDead(_9);
+        StorageDead(_7);
         goto -> bb1;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index e0fcfcaffc5..3b09f33e733 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -5,23 +5,21 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     debug end => _2;
     debug f => _3;
     let mut _0: ();
-    let mut _4: u32;
-    let mut _9: std::option::Option<u32>;
-    let mut _11: &impl Fn(u32);
-    let mut _12: (u32,);
-    let _13: ();
+    let mut _7: std::option::Option<u32>;
+    let mut _9: &impl Fn(u32);
+    let mut _10: (u32,);
+    let _11: ();
     scope 1 {
-        debug ((iter: std::ops::Range<u32>).0: u32) => _4;
+        debug ((iter: std::ops::Range<u32>).0: u32) => _1;
         debug ((iter: std::ops::Range<u32>).1: u32) => _2;
-        let _10: u32;
+        let _8: u32;
         scope 2 {
-            debug x => _10;
+            debug x => _8;
         }
         scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) {
             scope 5 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) {
-                let mut _6: bool;
-                let _7: u32;
-                let mut _8: u32;
+                let mut _5: bool;
+                let _6: u32;
                 scope 6 {
                     scope 8 (inlined <u32 as Step>::forward_unchecked) {
                         scope 9 (inlined #[track_caller] core::num::<impl u32>::unchecked_add) {
@@ -33,7 +31,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
                     }
                 }
                 scope 7 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) {
-                    let mut _5: u32;
+                    let mut _4: u32;
                 }
             }
         }
@@ -42,25 +40,22 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     }
 
     bb0: {
-        StorageLive(_4);
-        _4 = copy _1;
         goto -> bb1;
     }
 
     bb1: {
-        StorageLive(_9);
-        StorageLive(_6);
+        StorageLive(_7);
         StorageLive(_5);
-        _5 = copy _4;
-        _6 = Lt(move _5, copy _2);
-        StorageDead(_5);
-        switchInt(move _6) -> [0: bb2, otherwise: bb4];
+        StorageLive(_4);
+        _4 = copy _1;
+        _5 = Lt(move _4, copy _2);
+        StorageDead(_4);
+        switchInt(move _5) -> [0: bb2, otherwise: bb4];
     }
 
     bb2: {
-        StorageDead(_6);
-        StorageDead(_9);
-        StorageDead(_4);
+        StorageDead(_5);
+        StorageDead(_7);
         drop(_3) -> [return: bb3, unwind continue];
     }
 
@@ -69,25 +64,22 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     }
 
     bb4: {
-        _7 = copy _4;
-        StorageLive(_8);
-        _8 = AddUnchecked(copy _7, const 1_u32);
-        _4 = move _8;
-        StorageDead(_8);
-        _9 = Option::<u32>::Some(copy _7);
-        StorageDead(_6);
-        _10 = copy ((_9 as Some).0: u32);
-        StorageLive(_11);
-        _11 = &_3;
-        StorageLive(_12);
-        _12 = (copy _10,);
-        _13 = <impl Fn(u32) as Fn<(u32,)>>::call(move _11, move _12) -> [return: bb5, unwind: bb6];
+        _6 = copy _1;
+        _1 = AddUnchecked(copy _6, const 1_u32);
+        _7 = Option::<u32>::Some(copy _6);
+        StorageDead(_5);
+        _8 = copy ((_7 as Some).0: u32);
+        StorageLive(_9);
+        _9 = &_3;
+        StorageLive(_10);
+        _10 = (copy _8,);
+        _11 = <impl Fn(u32) as Fn<(u32,)>>::call(move _9, move _10) -> [return: bb5, unwind: bb6];
     }
 
     bb5: {
-        StorageDead(_12);
-        StorageDead(_11);
+        StorageDead(_10);
         StorageDead(_9);
+        StorageDead(_7);
         goto -> bb1;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
index 72b39a7f6a8..104987b0fdd 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir
@@ -4,30 +4,28 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     debug slice => _1;
     debug f => _2;
     let mut _0: ();
-    let mut _11: std::ptr::NonNull<T>;
-    let mut _12: *const T;
-    let mut _13: usize;
-    let mut _32: std::option::Option<(usize, &T)>;
-    let mut _35: &impl Fn(usize, &T);
-    let mut _36: (usize, &T);
-    let _37: ();
+    let mut _10: usize;
+    let mut _28: std::option::Option<(usize, &T)>;
+    let mut _31: &impl Fn(usize, &T);
+    let mut _32: (usize, &T);
+    let _33: ();
     scope 1 {
-        debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11;
-        debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).1: *const T) => _12;
+        debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _6;
+        debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).1: *const T) => _9;
         debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>;
-        debug ((iter: Enumerate<std::slice::Iter<'_, T>>).1: usize) => _13;
-        let _33: usize;
-        let _34: &T;
+        debug ((iter: Enumerate<std::slice::Iter<'_, T>>).1: usize) => _10;
+        let _29: usize;
+        let _30: &T;
         scope 2 {
-            debug i => _33;
-            debug x => _34;
+            debug i => _29;
+            debug x => _30;
         }
         scope 18 (inlined <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next) {
-            let mut _27: std::option::Option<&T>;
-            let mut _30: (usize, bool);
-            let mut _31: (usize, &T);
+            let mut _23: std::option::Option<&T>;
+            let mut _26: (usize, bool);
+            let mut _27: (usize, &T);
             scope 19 {
-                let _29: usize;
+                let _25: usize;
                 scope 24 {
                 }
             }
@@ -42,21 +40,21 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
                 }
             }
             scope 25 (inlined <Option<&T> as Try>::branch) {
-                let _28: &T;
+                let _24: &T;
                 scope 26 {
                 }
             }
             scope 28 (inlined <std::slice::Iter<'_, T> as Iterator>::next) {
-                let _14: std::ptr::NonNull<T>;
-                let _16: std::ptr::NonNull<T>;
-                let mut _19: bool;
-                let mut _22: std::ptr::NonNull<T>;
-                let mut _24: usize;
-                let _26: &T;
+                let mut _6: std::ptr::NonNull<T>;
+                let _11: std::ptr::NonNull<T>;
+                let _13: std::ptr::NonNull<T>;
+                let mut _16: bool;
+                let mut _20: usize;
+                let _22: &T;
                 scope 29 {
-                    let _15: *const T;
+                    let _12: *const T;
                     scope 30 {
-                        let _23: usize;
+                        let _19: usize;
                         scope 31 {
                             scope 34 (inlined #[track_caller] core::num::<impl usize>::unchecked_sub) {
                                 scope 35 (inlined core::ub_checks::check_language_ub) {
@@ -72,21 +70,21 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
                             }
                         }
                         scope 38 (inlined <NonNull<T> as PartialEq>::eq) {
-                            let mut _17: *mut T;
-                            let mut _18: *mut T;
+                            let mut _14: *mut T;
+                            let mut _15: *mut T;
                             scope 39 (inlined NonNull::<T>::as_ptr) {
                             }
                             scope 40 (inlined NonNull::<T>::as_ptr) {
                             }
                         }
                         scope 41 (inlined NonNull::<T>::add) {
-                            let mut _20: *const T;
-                            let mut _21: *const T;
+                            let mut _17: *const T;
+                            let mut _18: *const T;
                             scope 42 (inlined NonNull::<T>::as_ptr) {
                             }
                         }
                         scope 43 (inlined NonNull::<T>::as_ref::<'_>) {
-                            let _25: *const T;
+                            let _21: *const T;
                             scope 44 (inlined NonNull::<T>::as_ptr) {
                             }
                             scope 45 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) {
@@ -102,9 +100,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
             let _3: usize;
             let mut _7: *mut T;
             let mut _8: *mut T;
-            let mut _10: *const T;
             scope 5 {
-                let _6: std::ptr::NonNull<T>;
                 scope 6 {
                     let _9: *const T;
                     scope 7 {
@@ -145,7 +141,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
         _5 = copy _4 as *const T (PtrToPtr);
         _6 = NonNull::<T> { pointer: copy _5 };
         StorageDead(_5);
-        StorageLive(_9);
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
@@ -166,97 +161,86 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb3: {
-        _10 = copy _9;
-        StorageDead(_9);
         StorageDead(_4);
         StorageDead(_3);
-        StorageLive(_11);
-        StorageLive(_12);
-        StorageLive(_13);
-        _11 = copy _6;
-        _12 = copy _10;
-        _13 = const 0_usize;
+        StorageLive(_10);
+        _10 = const 0_usize;
         goto -> bb4;
     }
 
     bb4: {
-        StorageLive(_32);
-        StorageLive(_29);
-        StorageLive(_30);
-        StorageLive(_27);
-        StorageLive(_14);
-        StorageLive(_15);
-        StorageLive(_23);
-        StorageLive(_24);
-        StorageLive(_16);
+        StorageLive(_28);
+        StorageLive(_25);
         StorageLive(_26);
-        _14 = copy _11;
-        _15 = copy _12;
+        StorageLive(_23);
+        StorageLive(_11);
+        StorageLive(_12);
+        StorageLive(_19);
+        StorageLive(_20);
+        StorageLive(_13);
+        StorageLive(_22);
+        _11 = copy _6;
+        _12 = copy _9;
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8];
     }
 
     bb5: {
-        StorageLive(_19);
-        _16 = copy _15 as std::ptr::NonNull<T> (Transmute);
-        StorageLive(_17);
-        _17 = copy _14 as *mut T (Transmute);
-        StorageLive(_18);
-        _18 = copy _16 as *mut T (Transmute);
-        _19 = Eq(copy _17, copy _18);
-        StorageDead(_18);
-        StorageDead(_17);
-        switchInt(move _19) -> [0: bb6, otherwise: bb7];
+        StorageLive(_16);
+        _13 = copy _12 as std::ptr::NonNull<T> (Transmute);
+        StorageLive(_14);
+        _14 = copy _11 as *mut T (Transmute);
+        StorageLive(_15);
+        _15 = copy _13 as *mut T (Transmute);
+        _16 = Eq(copy _14, copy _15);
+        StorageDead(_15);
+        StorageDead(_14);
+        switchInt(move _16) -> [0: bb6, otherwise: bb7];
     }
 
     bb6: {
-        StorageDead(_19);
-        StorageLive(_22);
-        StorageLive(_21);
-        StorageLive(_20);
-        _20 = copy _14 as *const T (Transmute);
-        _21 = Offset(copy _20, const 1_usize);
-        StorageDead(_20);
-        _22 = NonNull::<T> { pointer: copy _21 };
-        StorageDead(_21);
-        _11 = move _22;
-        StorageDead(_22);
+        StorageDead(_16);
+        StorageLive(_18);
+        StorageLive(_17);
+        _17 = copy _11 as *const T (Transmute);
+        _18 = Offset(copy _17, const 1_usize);
+        StorageDead(_17);
+        _6 = NonNull::<T> { pointer: copy _18 };
+        StorageDead(_18);
         goto -> bb13;
     }
 
     bb7: {
-        StorageDead(_19);
-        StorageDead(_26);
         StorageDead(_16);
-        StorageDead(_24);
-        StorageDead(_23);
-        StorageDead(_15);
-        StorageDead(_14);
+        StorageDead(_22);
+        StorageDead(_13);
+        StorageDead(_20);
+        StorageDead(_19);
+        StorageDead(_12);
+        StorageDead(_11);
         goto -> bb10;
     }
 
     bb8: {
-        _23 = copy _15 as usize (Transmute);
-        switchInt(copy _23) -> [0: bb9, otherwise: bb12];
+        _19 = copy _12 as usize (Transmute);
+        switchInt(copy _19) -> [0: bb9, otherwise: bb12];
     }
 
     bb9: {
-        StorageDead(_26);
-        StorageDead(_16);
-        StorageDead(_24);
-        StorageDead(_23);
-        StorageDead(_15);
-        StorageDead(_14);
+        StorageDead(_22);
+        StorageDead(_13);
+        StorageDead(_20);
+        StorageDead(_19);
+        StorageDead(_12);
+        StorageDead(_11);
         goto -> bb10;
     }
 
     bb10: {
-        StorageDead(_27);
-        StorageDead(_30);
-        StorageDead(_29);
-        StorageDead(_32);
-        StorageDead(_11);
-        StorageDead(_12);
-        StorageDead(_13);
+        StorageDead(_23);
+        StorageDead(_26);
+        StorageDead(_25);
+        StorageDead(_28);
+        StorageDead(_10);
         drop(_2) -> [return: bb11, unwind unreachable];
     }
 
@@ -265,51 +249,51 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb12: {
-        _24 = SubUnchecked(copy _23, const 1_usize);
-        _12 = copy _24 as *const T (Transmute);
+        _20 = SubUnchecked(copy _19, const 1_usize);
+        _9 = copy _20 as *const T (Transmute);
         goto -> bb13;
     }
 
     bb13: {
-        StorageLive(_25);
-        _25 = copy _14 as *const T (Transmute);
-        _26 = &(*_25);
-        StorageDead(_25);
-        _27 = Option::<&T>::Some(copy _26);
-        StorageDead(_26);
-        StorageDead(_16);
-        StorageDead(_24);
+        StorageLive(_21);
+        _21 = copy _11 as *const T (Transmute);
+        _22 = &(*_21);
+        StorageDead(_21);
+        _23 = Option::<&T>::Some(copy _22);
+        StorageDead(_22);
+        StorageDead(_13);
+        StorageDead(_20);
+        StorageDead(_19);
+        StorageDead(_12);
+        StorageDead(_11);
+        _24 = copy ((_23 as Some).0: &T);
         StorageDead(_23);
-        StorageDead(_15);
-        StorageDead(_14);
-        _28 = copy ((_27 as Some).0: &T);
-        StorageDead(_27);
-        _29 = copy _13;
-        _30 = AddWithOverflow(copy _13, const 1_usize);
-        assert(!move (_30.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _13, const 1_usize) -> [success: bb14, unwind unreachable];
+        _25 = copy _10;
+        _26 = AddWithOverflow(copy _10, const 1_usize);
+        assert(!move (_26.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _10, const 1_usize) -> [success: bb14, unwind unreachable];
     }
 
     bb14: {
-        _13 = move (_30.0: usize);
+        _10 = move (_26.0: usize);
+        StorageLive(_27);
+        _27 = (copy _25, copy _24);
+        _28 = Option::<(usize, &T)>::Some(move _27);
+        StorageDead(_27);
+        StorageDead(_26);
+        StorageDead(_25);
+        _29 = copy (((_28 as Some).0: (usize, &T)).0: usize);
+        _30 = copy (((_28 as Some).0: (usize, &T)).1: &T);
         StorageLive(_31);
-        _31 = (copy _29, copy _28);
-        _32 = Option::<(usize, &T)>::Some(move _31);
-        StorageDead(_31);
-        StorageDead(_30);
-        StorageDead(_29);
-        _33 = copy (((_32 as Some).0: (usize, &T)).0: usize);
-        _34 = copy (((_32 as Some).0: (usize, &T)).1: &T);
-        StorageLive(_35);
-        _35 = &_2;
-        StorageLive(_36);
-        _36 = (copy _33, copy _34);
-        _37 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _35, move _36) -> [return: bb15, unwind unreachable];
+        _31 = &_2;
+        StorageLive(_32);
+        _32 = (copy _29, copy _30);
+        _33 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _31, move _32) -> [return: bb15, unwind unreachable];
     }
 
     bb15: {
-        StorageDead(_36);
-        StorageDead(_35);
         StorageDead(_32);
+        StorageDead(_31);
+        StorageDead(_28);
         goto -> bb4;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
index 42aa152ec99..28b12cdf367 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
@@ -4,22 +4,22 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     debug slice => _1;
     debug f => _2;
     let mut _0: ();
-    let mut _11: std::slice::Iter<'_, T>;
+    let mut _10: std::slice::Iter<'_, T>;
+    let mut _11: std::iter::Enumerate<std::slice::Iter<'_, T>>;
     let mut _12: std::iter::Enumerate<std::slice::Iter<'_, T>>;
-    let mut _13: std::iter::Enumerate<std::slice::Iter<'_, T>>;
-    let mut _14: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>;
-    let mut _15: std::option::Option<(usize, &T)>;
-    let mut _16: isize;
-    let mut _19: &impl Fn(usize, &T);
-    let mut _20: (usize, &T);
-    let _21: ();
+    let mut _13: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>;
+    let mut _14: std::option::Option<(usize, &T)>;
+    let mut _15: isize;
+    let mut _18: &impl Fn(usize, &T);
+    let mut _19: (usize, &T);
+    let _20: ();
     scope 1 {
-        debug iter => _13;
-        let _17: usize;
-        let _18: &T;
+        debug iter => _12;
+        let _16: usize;
+        let _17: &T;
         scope 2 {
-            debug i => _17;
-            debug x => _18;
+            debug i => _16;
+            debug x => _17;
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -27,7 +27,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
             let _3: usize;
             let mut _7: *mut T;
             let mut _8: *mut T;
-            let mut _10: *const T;
             scope 5 {
                 let _6: std::ptr::NonNull<T>;
                 scope 6 {
@@ -62,9 +61,10 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb0: {
-        StorageLive(_11);
+        StorageLive(_10);
         StorageLive(_3);
         StorageLive(_6);
+        StorageLive(_9);
         StorageLive(_4);
         _3 = PtrMetadata(copy _1);
         _4 = &raw const (*_1);
@@ -72,7 +72,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
         _5 = copy _4 as *const T (PtrToPtr);
         _6 = NonNull::<T> { pointer: copy _5 };
         StorageDead(_5);
-        StorageLive(_9);
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
@@ -93,33 +92,30 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb3: {
-        StorageLive(_10);
-        _10 = copy _9;
-        _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> };
-        StorageDead(_10);
-        StorageDead(_9);
+        _10 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _9, _marker: const ZeroSized: PhantomData<&T> };
         StorageDead(_4);
+        StorageDead(_9);
         StorageDead(_6);
         StorageDead(_3);
-        _12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize };
-        StorageDead(_11);
-        StorageLive(_13);
-        _13 = copy _12;
+        _11 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _10, count: const 0_usize };
+        StorageDead(_10);
+        StorageLive(_12);
+        _12 = copy _11;
         goto -> bb4;
     }
 
     bb4: {
-        _14 = &mut _13;
-        _15 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _14) -> [return: bb5, unwind: bb11];
+        _13 = &mut _12;
+        _14 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _13) -> [return: bb5, unwind: bb11];
     }
 
     bb5: {
-        _16 = discriminant(_15);
-        switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10];
+        _15 = discriminant(_14);
+        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        StorageDead(_13);
+        StorageDead(_12);
         drop(_2) -> [return: bb7, unwind continue];
     }
 
@@ -128,18 +124,18 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     }
 
     bb8: {
-        _17 = copy (((_15 as Some).0: (usize, &T)).0: usize);
-        _18 = copy (((_15 as Some).0: (usize, &T)).1: &T);
+        _16 = copy (((_14 as Some).0: (usize, &T)).0: usize);
+        _17 = copy (((_14 as Some).0: (usize, &T)).1: &T);
+        StorageLive(_18);
+        _18 = &_2;
         StorageLive(_19);
-        _19 = &_2;
-        StorageLive(_20);
-        _20 = copy ((_15 as Some).0: (usize, &T));
-        _21 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11];
+        _19 = copy ((_14 as Some).0: (usize, &T));
+        _20 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _18, move _19) -> [return: bb9, unwind: bb11];
     }
 
     bb9: {
-        StorageDead(_20);
         StorageDead(_19);
+        StorageDead(_18);
         goto -> bb4;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
index 0d65640ec9b..4d0e3548e7d 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir
@@ -4,31 +4,29 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     debug slice => _1;
     debug f => _2;
     let mut _0: ();
-    let mut _11: std::ptr::NonNull<T>;
-    let mut _12: *const T;
-    let mut _26: std::option::Option<&T>;
-    let mut _28: &impl Fn(&T);
-    let mut _29: (&T,);
-    let _30: ();
+    let mut _22: std::option::Option<&T>;
+    let mut _24: &impl Fn(&T);
+    let mut _25: (&T,);
+    let _26: ();
     scope 1 {
-        debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11;
-        debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _12;
+        debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _6;
+        debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _9;
         debug ((iter: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>;
-        let _27: &T;
+        let _23: &T;
         scope 2 {
-            debug x => _27;
+            debug x => _23;
         }
         scope 16 (inlined <std::slice::Iter<'_, T> as Iterator>::next) {
-            let _13: std::ptr::NonNull<T>;
-            let _15: std::ptr::NonNull<T>;
-            let mut _18: bool;
-            let mut _21: std::ptr::NonNull<T>;
-            let mut _23: usize;
-            let _25: &T;
+            let mut _6: std::ptr::NonNull<T>;
+            let _10: std::ptr::NonNull<T>;
+            let _12: std::ptr::NonNull<T>;
+            let mut _15: bool;
+            let mut _19: usize;
+            let _21: &T;
             scope 17 {
-                let _14: *const T;
+                let _11: *const T;
                 scope 18 {
-                    let _22: usize;
+                    let _18: usize;
                     scope 19 {
                         scope 22 (inlined #[track_caller] core::num::<impl usize>::unchecked_sub) {
                             scope 23 (inlined core::ub_checks::check_language_ub) {
@@ -44,21 +42,21 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
                         }
                     }
                     scope 26 (inlined <NonNull<T> as PartialEq>::eq) {
-                        let mut _16: *mut T;
-                        let mut _17: *mut T;
+                        let mut _13: *mut T;
+                        let mut _14: *mut T;
                         scope 27 (inlined NonNull::<T>::as_ptr) {
                         }
                         scope 28 (inlined NonNull::<T>::as_ptr) {
                         }
                     }
                     scope 29 (inlined NonNull::<T>::add) {
-                        let mut _19: *const T;
-                        let mut _20: *const T;
+                        let mut _16: *const T;
+                        let mut _17: *const T;
                         scope 30 (inlined NonNull::<T>::as_ptr) {
                         }
                     }
                     scope 31 (inlined NonNull::<T>::as_ref::<'_>) {
-                        let _24: *const T;
+                        let _20: *const T;
                         scope 32 (inlined NonNull::<T>::as_ptr) {
                         }
                         scope 33 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) {
@@ -73,9 +71,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
             let _3: usize;
             let mut _7: *mut T;
             let mut _8: *mut T;
-            let mut _10: *const T;
             scope 5 {
-                let _6: std::ptr::NonNull<T>;
                 scope 6 {
                     let _9: *const T;
                     scope 7 {
@@ -112,7 +108,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
         _5 = copy _4 as *const T (PtrToPtr);
         _6 = NonNull::<T> { pointer: copy _5 };
         StorageDead(_5);
-        StorageLive(_9);
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
@@ -133,88 +128,77 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb3: {
-        _10 = copy _9;
-        StorageDead(_9);
         StorageDead(_4);
         StorageDead(_3);
-        StorageLive(_11);
-        StorageLive(_12);
-        _11 = copy _6;
-        _12 = copy _10;
         goto -> bb4;
     }
 
     bb4: {
-        StorageLive(_26);
-        StorageLive(_13);
-        StorageLive(_14);
         StorageLive(_22);
-        StorageLive(_23);
-        StorageLive(_15);
-        StorageLive(_25);
-        _13 = copy _11;
-        _14 = copy _12;
+        StorageLive(_10);
+        StorageLive(_11);
+        StorageLive(_18);
+        StorageLive(_19);
+        StorageLive(_12);
+        StorageLive(_21);
+        _10 = copy _6;
+        _11 = copy _9;
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8];
     }
 
     bb5: {
-        StorageLive(_18);
-        _15 = copy _14 as std::ptr::NonNull<T> (Transmute);
-        StorageLive(_16);
-        _16 = copy _13 as *mut T (Transmute);
-        StorageLive(_17);
-        _17 = copy _15 as *mut T (Transmute);
-        _18 = Eq(copy _16, copy _17);
-        StorageDead(_17);
-        StorageDead(_16);
-        switchInt(move _18) -> [0: bb6, otherwise: bb7];
+        StorageLive(_15);
+        _12 = copy _11 as std::ptr::NonNull<T> (Transmute);
+        StorageLive(_13);
+        _13 = copy _10 as *mut T (Transmute);
+        StorageLive(_14);
+        _14 = copy _12 as *mut T (Transmute);
+        _15 = Eq(copy _13, copy _14);
+        StorageDead(_14);
+        StorageDead(_13);
+        switchInt(move _15) -> [0: bb6, otherwise: bb7];
     }
 
     bb6: {
-        StorageDead(_18);
-        StorageLive(_21);
-        StorageLive(_20);
-        StorageLive(_19);
-        _19 = copy _13 as *const T (Transmute);
-        _20 = Offset(copy _19, const 1_usize);
-        StorageDead(_19);
-        _21 = NonNull::<T> { pointer: copy _20 };
-        StorageDead(_20);
-        _11 = move _21;
-        StorageDead(_21);
+        StorageDead(_15);
+        StorageLive(_17);
+        StorageLive(_16);
+        _16 = copy _10 as *const T (Transmute);
+        _17 = Offset(copy _16, const 1_usize);
+        StorageDead(_16);
+        _6 = NonNull::<T> { pointer: copy _17 };
+        StorageDead(_17);
         goto -> bb13;
     }
 
     bb7: {
-        StorageDead(_18);
-        StorageDead(_25);
         StorageDead(_15);
-        StorageDead(_23);
-        StorageDead(_22);
-        StorageDead(_14);
-        StorageDead(_13);
+        StorageDead(_21);
+        StorageDead(_12);
+        StorageDead(_19);
+        StorageDead(_18);
+        StorageDead(_11);
+        StorageDead(_10);
         goto -> bb10;
     }
 
     bb8: {
-        _22 = copy _14 as usize (Transmute);
-        switchInt(copy _22) -> [0: bb9, otherwise: bb12];
+        _18 = copy _11 as usize (Transmute);
+        switchInt(copy _18) -> [0: bb9, otherwise: bb12];
     }
 
     bb9: {
-        StorageDead(_25);
-        StorageDead(_15);
-        StorageDead(_23);
-        StorageDead(_22);
-        StorageDead(_14);
-        StorageDead(_13);
+        StorageDead(_21);
+        StorageDead(_12);
+        StorageDead(_19);
+        StorageDead(_18);
+        StorageDead(_11);
+        StorageDead(_10);
         goto -> bb10;
     }
 
     bb10: {
-        StorageDead(_26);
-        StorageDead(_11);
-        StorageDead(_12);
+        StorageDead(_22);
         drop(_2) -> [return: bb11, unwind unreachable];
     }
 
@@ -223,35 +207,35 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb12: {
-        _23 = SubUnchecked(copy _22, const 1_usize);
-        _12 = copy _23 as *const T (Transmute);
+        _19 = SubUnchecked(copy _18, const 1_usize);
+        _9 = copy _19 as *const T (Transmute);
         goto -> bb13;
     }
 
     bb13: {
+        StorageLive(_20);
+        _20 = copy _10 as *const T (Transmute);
+        _21 = &(*_20);
+        StorageDead(_20);
+        _22 = Option::<&T>::Some(copy _21);
+        StorageDead(_21);
+        StorageDead(_12);
+        StorageDead(_19);
+        StorageDead(_18);
+        StorageDead(_11);
+        StorageDead(_10);
+        _23 = copy ((_22 as Some).0: &T);
         StorageLive(_24);
-        _24 = copy _13 as *const T (Transmute);
-        _25 = &(*_24);
-        StorageDead(_24);
-        _26 = Option::<&T>::Some(copy _25);
-        StorageDead(_25);
-        StorageDead(_15);
-        StorageDead(_23);
-        StorageDead(_22);
-        StorageDead(_14);
-        StorageDead(_13);
-        _27 = copy ((_26 as Some).0: &T);
-        StorageLive(_28);
-        _28 = &_2;
-        StorageLive(_29);
-        _29 = (copy _27,);
-        _30 = <impl Fn(&T) as Fn<(&T,)>>::call(move _28, move _29) -> [return: bb14, unwind unreachable];
+        _24 = &_2;
+        StorageLive(_25);
+        _25 = (copy _23,);
+        _26 = <impl Fn(&T) as Fn<(&T,)>>::call(move _24, move _25) -> [return: bb14, unwind unreachable];
     }
 
     bb14: {
-        StorageDead(_29);
-        StorageDead(_28);
-        StorageDead(_26);
+        StorageDead(_25);
+        StorageDead(_24);
+        StorageDead(_22);
         goto -> bb4;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index 02efb193474..2b5d8c27d71 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -4,31 +4,29 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     debug slice => _1;
     debug f => _2;
     let mut _0: ();
-    let mut _11: std::ptr::NonNull<T>;
-    let mut _12: *const T;
-    let mut _26: std::option::Option<&T>;
-    let mut _28: &impl Fn(&T);
-    let mut _29: (&T,);
-    let _30: ();
+    let mut _22: std::option::Option<&T>;
+    let mut _24: &impl Fn(&T);
+    let mut _25: (&T,);
+    let _26: ();
     scope 1 {
-        debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11;
-        debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _12;
+        debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _6;
+        debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _9;
         debug ((iter: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>;
-        let _27: &T;
+        let _23: &T;
         scope 2 {
-            debug x => _27;
+            debug x => _23;
         }
         scope 16 (inlined <std::slice::Iter<'_, T> as Iterator>::next) {
-            let _13: std::ptr::NonNull<T>;
-            let _15: std::ptr::NonNull<T>;
-            let mut _18: bool;
-            let mut _21: std::ptr::NonNull<T>;
-            let mut _23: usize;
-            let _25: &T;
+            let mut _6: std::ptr::NonNull<T>;
+            let _10: std::ptr::NonNull<T>;
+            let _12: std::ptr::NonNull<T>;
+            let mut _15: bool;
+            let mut _19: usize;
+            let _21: &T;
             scope 17 {
-                let _14: *const T;
+                let _11: *const T;
                 scope 18 {
-                    let _22: usize;
+                    let _18: usize;
                     scope 19 {
                         scope 22 (inlined #[track_caller] core::num::<impl usize>::unchecked_sub) {
                             scope 23 (inlined core::ub_checks::check_language_ub) {
@@ -44,21 +42,21 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
                         }
                     }
                     scope 26 (inlined <NonNull<T> as PartialEq>::eq) {
-                        let mut _16: *mut T;
-                        let mut _17: *mut T;
+                        let mut _13: *mut T;
+                        let mut _14: *mut T;
                         scope 27 (inlined NonNull::<T>::as_ptr) {
                         }
                         scope 28 (inlined NonNull::<T>::as_ptr) {
                         }
                     }
                     scope 29 (inlined NonNull::<T>::add) {
-                        let mut _19: *const T;
-                        let mut _20: *const T;
+                        let mut _16: *const T;
+                        let mut _17: *const T;
                         scope 30 (inlined NonNull::<T>::as_ptr) {
                         }
                     }
                     scope 31 (inlined NonNull::<T>::as_ref::<'_>) {
-                        let _24: *const T;
+                        let _20: *const T;
                         scope 32 (inlined NonNull::<T>::as_ptr) {
                         }
                         scope 33 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) {
@@ -73,9 +71,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
             let _3: usize;
             let mut _7: *mut T;
             let mut _8: *mut T;
-            let mut _10: *const T;
             scope 5 {
-                let _6: std::ptr::NonNull<T>;
                 scope 6 {
                     let _9: *const T;
                     scope 7 {
@@ -112,7 +108,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
         _5 = copy _4 as *const T (PtrToPtr);
         _6 = NonNull::<T> { pointer: copy _5 };
         StorageDead(_5);
-        StorageLive(_9);
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
@@ -133,88 +128,77 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb3: {
-        _10 = copy _9;
-        StorageDead(_9);
         StorageDead(_4);
         StorageDead(_3);
-        StorageLive(_11);
-        StorageLive(_12);
-        _11 = copy _6;
-        _12 = copy _10;
         goto -> bb4;
     }
 
     bb4: {
-        StorageLive(_26);
-        StorageLive(_13);
-        StorageLive(_14);
         StorageLive(_22);
-        StorageLive(_23);
-        StorageLive(_15);
-        StorageLive(_25);
-        _13 = copy _11;
-        _14 = copy _12;
+        StorageLive(_10);
+        StorageLive(_11);
+        StorageLive(_18);
+        StorageLive(_19);
+        StorageLive(_12);
+        StorageLive(_21);
+        _10 = copy _6;
+        _11 = copy _9;
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8];
     }
 
     bb5: {
-        StorageLive(_18);
-        _15 = copy _14 as std::ptr::NonNull<T> (Transmute);
-        StorageLive(_16);
-        _16 = copy _13 as *mut T (Transmute);
-        StorageLive(_17);
-        _17 = copy _15 as *mut T (Transmute);
-        _18 = Eq(copy _16, copy _17);
-        StorageDead(_17);
-        StorageDead(_16);
-        switchInt(move _18) -> [0: bb6, otherwise: bb7];
+        StorageLive(_15);
+        _12 = copy _11 as std::ptr::NonNull<T> (Transmute);
+        StorageLive(_13);
+        _13 = copy _10 as *mut T (Transmute);
+        StorageLive(_14);
+        _14 = copy _12 as *mut T (Transmute);
+        _15 = Eq(copy _13, copy _14);
+        StorageDead(_14);
+        StorageDead(_13);
+        switchInt(move _15) -> [0: bb6, otherwise: bb7];
     }
 
     bb6: {
-        StorageDead(_18);
-        StorageLive(_21);
-        StorageLive(_20);
-        StorageLive(_19);
-        _19 = copy _13 as *const T (Transmute);
-        _20 = Offset(copy _19, const 1_usize);
-        StorageDead(_19);
-        _21 = NonNull::<T> { pointer: copy _20 };
-        StorageDead(_20);
-        _11 = move _21;
-        StorageDead(_21);
+        StorageDead(_15);
+        StorageLive(_17);
+        StorageLive(_16);
+        _16 = copy _10 as *const T (Transmute);
+        _17 = Offset(copy _16, const 1_usize);
+        StorageDead(_16);
+        _6 = NonNull::<T> { pointer: copy _17 };
+        StorageDead(_17);
         goto -> bb13;
     }
 
     bb7: {
-        StorageDead(_18);
-        StorageDead(_25);
         StorageDead(_15);
-        StorageDead(_23);
-        StorageDead(_22);
-        StorageDead(_14);
-        StorageDead(_13);
+        StorageDead(_21);
+        StorageDead(_12);
+        StorageDead(_19);
+        StorageDead(_18);
+        StorageDead(_11);
+        StorageDead(_10);
         goto -> bb10;
     }
 
     bb8: {
-        _22 = copy _14 as usize (Transmute);
-        switchInt(copy _22) -> [0: bb9, otherwise: bb12];
+        _18 = copy _11 as usize (Transmute);
+        switchInt(copy _18) -> [0: bb9, otherwise: bb12];
     }
 
     bb9: {
-        StorageDead(_25);
-        StorageDead(_15);
-        StorageDead(_23);
-        StorageDead(_22);
-        StorageDead(_14);
-        StorageDead(_13);
+        StorageDead(_21);
+        StorageDead(_12);
+        StorageDead(_19);
+        StorageDead(_18);
+        StorageDead(_11);
+        StorageDead(_10);
         goto -> bb10;
     }
 
     bb10: {
-        StorageDead(_26);
-        StorageDead(_11);
-        StorageDead(_12);
+        StorageDead(_22);
         drop(_2) -> [return: bb11, unwind continue];
     }
 
@@ -223,35 +207,35 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb12: {
-        _23 = SubUnchecked(copy _22, const 1_usize);
-        _12 = copy _23 as *const T (Transmute);
+        _19 = SubUnchecked(copy _18, const 1_usize);
+        _9 = copy _19 as *const T (Transmute);
         goto -> bb13;
     }
 
     bb13: {
+        StorageLive(_20);
+        _20 = copy _10 as *const T (Transmute);
+        _21 = &(*_20);
+        StorageDead(_20);
+        _22 = Option::<&T>::Some(copy _21);
+        StorageDead(_21);
+        StorageDead(_12);
+        StorageDead(_19);
+        StorageDead(_18);
+        StorageDead(_11);
+        StorageDead(_10);
+        _23 = copy ((_22 as Some).0: &T);
         StorageLive(_24);
-        _24 = copy _13 as *const T (Transmute);
-        _25 = &(*_24);
-        StorageDead(_24);
-        _26 = Option::<&T>::Some(copy _25);
-        StorageDead(_25);
-        StorageDead(_15);
-        StorageDead(_23);
-        StorageDead(_22);
-        StorageDead(_14);
-        StorageDead(_13);
-        _27 = copy ((_26 as Some).0: &T);
-        StorageLive(_28);
-        _28 = &_2;
-        StorageLive(_29);
-        _29 = (copy _27,);
-        _30 = <impl Fn(&T) as Fn<(&T,)>>::call(move _28, move _29) -> [return: bb14, unwind: bb15];
+        _24 = &_2;
+        StorageLive(_25);
+        _25 = (copy _23,);
+        _26 = <impl Fn(&T) as Fn<(&T,)>>::call(move _24, move _25) -> [return: bb14, unwind: bb15];
     }
 
     bb14: {
-        StorageDead(_29);
-        StorageDead(_28);
-        StorageDead(_26);
+        StorageDead(_25);
+        StorageDead(_24);
+        StorageDead(_22);
         goto -> bb4;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
index 41e273151ec..14537599071 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
@@ -5,28 +5,27 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     debug f => _2;
     let mut _0: ();
     let mut _3: usize;
-    let mut _4: usize;
-    let mut _9: std::option::Option<usize>;
-    let mut _11: bool;
-    let mut _13: &impl Fn(usize, &T);
-    let mut _14: (usize, &T);
-    let _15: ();
+    let mut _8: std::option::Option<usize>;
+    let mut _10: bool;
+    let mut _12: &impl Fn(usize, &T);
+    let mut _13: (usize, &T);
+    let _14: ();
     scope 1 {
         debug ((iter: std::ops::Range<usize>).0: usize) => _4;
         debug ((iter: std::ops::Range<usize>).1: usize) => _3;
-        let _10: usize;
+        let _9: usize;
         scope 2 {
-            debug i => _10;
-            let _12: &T;
+            debug i => _9;
+            let _11: &T;
             scope 3 {
-                debug x => _12;
+                debug x => _11;
             }
         }
         scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) {
             scope 6 (inlined <std::ops::Range<usize> as iter::range::RangeIteratorImpl>::spec_next) {
+                let mut _4: usize;
                 let mut _6: bool;
                 let _7: usize;
-                let mut _8: usize;
                 scope 7 {
                     scope 9 (inlined <usize as Step>::forward_unchecked) {
                         scope 10 (inlined #[track_caller] core::num::<impl usize>::unchecked_add) {
@@ -48,13 +47,12 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
 
     bb0: {
         _3 = PtrMetadata(copy _1);
-        StorageLive(_4);
         _4 = const 0_usize;
         goto -> bb1;
     }
 
     bb1: {
-        StorageLive(_9);
+        StorageLive(_8);
         StorageLive(_6);
         StorageLive(_5);
         _5 = copy _4;
@@ -65,8 +63,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
 
     bb2: {
         StorageDead(_6);
-        StorageDead(_9);
-        StorageDead(_4);
+        StorageDead(_8);
         drop(_2) -> [return: bb3, unwind unreachable];
     }
 
@@ -76,30 +73,27 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
 
     bb4: {
         _7 = copy _4;
-        StorageLive(_8);
-        _8 = AddUnchecked(copy _7, const 1_usize);
-        _4 = move _8;
-        StorageDead(_8);
-        _9 = Option::<usize>::Some(copy _7);
+        _4 = AddUnchecked(copy _7, const 1_usize);
+        _8 = Option::<usize>::Some(copy _7);
         StorageDead(_6);
-        _10 = copy ((_9 as Some).0: usize);
-        _11 = Lt(copy _10, copy _3);
-        assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb5, unwind unreachable];
+        _9 = copy ((_8 as Some).0: usize);
+        _10 = Lt(copy _9, copy _3);
+        assert(move _10, "index out of bounds: the length is {} but the index is {}", copy _3, copy _9) -> [success: bb5, unwind unreachable];
     }
 
     bb5: {
-        _12 = &(*_1)[_10];
+        _11 = &(*_1)[_9];
+        StorageLive(_12);
+        _12 = &_2;
         StorageLive(_13);
-        _13 = &_2;
-        StorageLive(_14);
-        _14 = (copy _10, copy _12);
-        _15 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _13, move _14) -> [return: bb6, unwind unreachable];
+        _13 = (copy _9, copy _11);
+        _14 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _12, move _13) -> [return: bb6, unwind unreachable];
     }
 
     bb6: {
-        StorageDead(_14);
         StorageDead(_13);
-        StorageDead(_9);
+        StorageDead(_12);
+        StorageDead(_8);
         goto -> bb1;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
index ec781c1480c..8e573ef488f 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
@@ -5,28 +5,27 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     debug f => _2;
     let mut _0: ();
     let mut _3: usize;
-    let mut _4: usize;
-    let mut _9: std::option::Option<usize>;
-    let mut _11: bool;
-    let mut _13: &impl Fn(usize, &T);
-    let mut _14: (usize, &T);
-    let _15: ();
+    let mut _8: std::option::Option<usize>;
+    let mut _10: bool;
+    let mut _12: &impl Fn(usize, &T);
+    let mut _13: (usize, &T);
+    let _14: ();
     scope 1 {
         debug ((iter: std::ops::Range<usize>).0: usize) => _4;
         debug ((iter: std::ops::Range<usize>).1: usize) => _3;
-        let _10: usize;
+        let _9: usize;
         scope 2 {
-            debug i => _10;
-            let _12: &T;
+            debug i => _9;
+            let _11: &T;
             scope 3 {
-                debug x => _12;
+                debug x => _11;
             }
         }
         scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) {
             scope 6 (inlined <std::ops::Range<usize> as iter::range::RangeIteratorImpl>::spec_next) {
+                let mut _4: usize;
                 let mut _6: bool;
                 let _7: usize;
-                let mut _8: usize;
                 scope 7 {
                     scope 9 (inlined <usize as Step>::forward_unchecked) {
                         scope 10 (inlined #[track_caller] core::num::<impl usize>::unchecked_add) {
@@ -48,13 +47,12 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
 
     bb0: {
         _3 = PtrMetadata(copy _1);
-        StorageLive(_4);
         _4 = const 0_usize;
         goto -> bb1;
     }
 
     bb1: {
-        StorageLive(_9);
+        StorageLive(_8);
         StorageLive(_6);
         StorageLive(_5);
         _5 = copy _4;
@@ -65,8 +63,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
 
     bb2: {
         StorageDead(_6);
-        StorageDead(_9);
-        StorageDead(_4);
+        StorageDead(_8);
         drop(_2) -> [return: bb3, unwind continue];
     }
 
@@ -76,30 +73,27 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
 
     bb4: {
         _7 = copy _4;
-        StorageLive(_8);
-        _8 = AddUnchecked(copy _7, const 1_usize);
-        _4 = move _8;
-        StorageDead(_8);
-        _9 = Option::<usize>::Some(copy _7);
+        _4 = AddUnchecked(copy _7, const 1_usize);
+        _8 = Option::<usize>::Some(copy _7);
         StorageDead(_6);
-        _10 = copy ((_9 as Some).0: usize);
-        _11 = Lt(copy _10, copy _3);
-        assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb5, unwind: bb7];
+        _9 = copy ((_8 as Some).0: usize);
+        _10 = Lt(copy _9, copy _3);
+        assert(move _10, "index out of bounds: the length is {} but the index is {}", copy _3, copy _9) -> [success: bb5, unwind: bb7];
     }
 
     bb5: {
-        _12 = &(*_1)[_10];
+        _11 = &(*_1)[_9];
+        StorageLive(_12);
+        _12 = &_2;
         StorageLive(_13);
-        _13 = &_2;
-        StorageLive(_14);
-        _14 = (copy _10, copy _12);
-        _15 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _13, move _14) -> [return: bb6, unwind: bb7];
+        _13 = (copy _9, copy _11);
+        _14 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _12, move _13) -> [return: bb6, unwind: bb7];
     }
 
     bb6: {
-        StorageDead(_14);
         StorageDead(_13);
-        StorageDead(_9);
+        StorageDead(_12);
+        StorageDead(_8);
         goto -> bb1;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
index ee638be7d7a..0adf268d766 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
@@ -4,22 +4,22 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     debug slice => _1;
     debug f => _2;
     let mut _0: ();
-    let mut _11: std::slice::Iter<'_, T>;
+    let mut _10: std::slice::Iter<'_, T>;
+    let mut _11: std::iter::Rev<std::slice::Iter<'_, T>>;
     let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _13: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _15: std::option::Option<&T>;
-    let mut _16: isize;
-    let mut _18: &impl Fn(&T);
-    let mut _19: (&T,);
-    let _20: ();
+    let mut _14: std::option::Option<&T>;
+    let mut _15: isize;
+    let mut _17: &impl Fn(&T);
+    let mut _18: (&T,);
+    let _19: ();
     scope 1 {
-        debug iter => _13;
-        let _17: &T;
+        debug iter => _12;
+        let _16: &T;
         scope 2 {
-            debug x => _17;
+            debug x => _16;
         }
         scope 18 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
-            let mut _14: &mut std::slice::Iter<'_, T>;
+            let mut _13: &mut std::slice::Iter<'_, T>;
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -27,7 +27,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
             let _3: usize;
             let mut _7: *mut T;
             let mut _8: *mut T;
-            let mut _10: *const T;
             scope 5 {
                 let _6: std::ptr::NonNull<T>;
                 scope 6 {
@@ -62,9 +61,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb0: {
-        StorageLive(_11);
+        StorageLive(_10);
         StorageLive(_3);
         StorageLive(_6);
+        StorageLive(_9);
         StorageLive(_4);
         _3 = PtrMetadata(copy _1);
         _4 = &raw const (*_1);
@@ -72,7 +72,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
         _5 = copy _4 as *const T (PtrToPtr);
         _6 = NonNull::<T> { pointer: copy _5 };
         StorageDead(_5);
-        StorageLive(_9);
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
@@ -93,37 +92,34 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb3: {
-        StorageLive(_10);
-        _10 = copy _9;
-        _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> };
-        StorageDead(_10);
-        StorageDead(_9);
+        _10 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _9, _marker: const ZeroSized: PhantomData<&T> };
         StorageDead(_4);
+        StorageDead(_9);
         StorageDead(_6);
         StorageDead(_3);
-        _12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 };
-        StorageDead(_11);
-        StorageLive(_13);
-        _13 = copy _12;
+        _11 = Rev::<std::slice::Iter<'_, T>> { iter: copy _10 };
+        StorageDead(_10);
+        StorageLive(_12);
+        _12 = copy _11;
         goto -> bb4;
     }
 
     bb4: {
-        StorageLive(_15);
         StorageLive(_14);
-        _14 = &mut (_13.0: std::slice::Iter<'_, T>);
-        _15 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind unreachable];
+        StorageLive(_13);
+        _13 = &mut (_12.0: std::slice::Iter<'_, T>);
+        _14 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _13) -> [return: bb5, unwind unreachable];
     }
 
     bb5: {
-        StorageDead(_14);
-        _16 = discriminant(_15);
-        switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10];
+        StorageDead(_13);
+        _15 = discriminant(_14);
+        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        StorageDead(_15);
-        StorageDead(_13);
+        StorageDead(_14);
+        StorageDead(_12);
         drop(_2) -> [return: bb7, unwind unreachable];
     }
 
@@ -132,18 +128,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb8: {
-        _17 = copy ((_15 as Some).0: &T);
+        _16 = copy ((_14 as Some).0: &T);
+        StorageLive(_17);
+        _17 = &_2;
         StorageLive(_18);
-        _18 = &_2;
-        StorageLive(_19);
-        _19 = (copy _17,);
-        _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind unreachable];
+        _18 = (copy _16,);
+        _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind unreachable];
     }
 
     bb9: {
-        StorageDead(_19);
         StorageDead(_18);
-        StorageDead(_15);
+        StorageDead(_17);
+        StorageDead(_14);
         goto -> bb4;
     }
 
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
index aee29d4d4fe..cb0d640d445 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
@@ -4,22 +4,22 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     debug slice => _1;
     debug f => _2;
     let mut _0: ();
-    let mut _11: std::slice::Iter<'_, T>;
+    let mut _10: std::slice::Iter<'_, T>;
+    let mut _11: std::iter::Rev<std::slice::Iter<'_, T>>;
     let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _13: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _15: std::option::Option<&T>;
-    let mut _16: isize;
-    let mut _18: &impl Fn(&T);
-    let mut _19: (&T,);
-    let _20: ();
+    let mut _14: std::option::Option<&T>;
+    let mut _15: isize;
+    let mut _17: &impl Fn(&T);
+    let mut _18: (&T,);
+    let _19: ();
     scope 1 {
-        debug iter => _13;
-        let _17: &T;
+        debug iter => _12;
+        let _16: &T;
         scope 2 {
-            debug x => _17;
+            debug x => _16;
         }
         scope 18 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
-            let mut _14: &mut std::slice::Iter<'_, T>;
+            let mut _13: &mut std::slice::Iter<'_, T>;
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -27,7 +27,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
             let _3: usize;
             let mut _7: *mut T;
             let mut _8: *mut T;
-            let mut _10: *const T;
             scope 5 {
                 let _6: std::ptr::NonNull<T>;
                 scope 6 {
@@ -62,9 +61,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb0: {
-        StorageLive(_11);
+        StorageLive(_10);
         StorageLive(_3);
         StorageLive(_6);
+        StorageLive(_9);
         StorageLive(_4);
         _3 = PtrMetadata(copy _1);
         _4 = &raw const (*_1);
@@ -72,7 +72,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
         _5 = copy _4 as *const T (PtrToPtr);
         _6 = NonNull::<T> { pointer: copy _5 };
         StorageDead(_5);
-        StorageLive(_9);
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
@@ -93,37 +92,34 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb3: {
-        StorageLive(_10);
-        _10 = copy _9;
-        _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> };
-        StorageDead(_10);
-        StorageDead(_9);
+        _10 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _9, _marker: const ZeroSized: PhantomData<&T> };
         StorageDead(_4);
+        StorageDead(_9);
         StorageDead(_6);
         StorageDead(_3);
-        _12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 };
-        StorageDead(_11);
-        StorageLive(_13);
-        _13 = copy _12;
+        _11 = Rev::<std::slice::Iter<'_, T>> { iter: copy _10 };
+        StorageDead(_10);
+        StorageLive(_12);
+        _12 = copy _11;
         goto -> bb4;
     }
 
     bb4: {
-        StorageLive(_15);
         StorageLive(_14);
-        _14 = &mut (_13.0: std::slice::Iter<'_, T>);
-        _15 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind: bb11];
+        StorageLive(_13);
+        _13 = &mut (_12.0: std::slice::Iter<'_, T>);
+        _14 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _13) -> [return: bb5, unwind: bb11];
     }
 
     bb5: {
-        StorageDead(_14);
-        _16 = discriminant(_15);
-        switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10];
+        StorageDead(_13);
+        _15 = discriminant(_14);
+        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10];
     }
 
     bb6: {
-        StorageDead(_15);
-        StorageDead(_13);
+        StorageDead(_14);
+        StorageDead(_12);
         drop(_2) -> [return: bb7, unwind continue];
     }
 
@@ -132,18 +128,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb8: {
-        _17 = copy ((_15 as Some).0: &T);
+        _16 = copy ((_14 as Some).0: &T);
+        StorageLive(_17);
+        _17 = &_2;
         StorageLive(_18);
-        _18 = &_2;
-        StorageLive(_19);
-        _19 = (copy _17,);
-        _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind: bb11];
+        _18 = (copy _16,);
+        _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind: bb11];
     }
 
     bb9: {
-        StorageDead(_19);
         StorageDead(_18);
-        StorageDead(_15);
+        StorageDead(_17);
+        StorageDead(_14);
         goto -> bb4;
     }
 
diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir
index c4d0e318b58..29bfe962974 100644
--- a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir
@@ -7,7 +7,6 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool {
     scope 1 (inlined std::cmp::impls::<impl PartialOrd for &(f32, f32)>::ge) {
         scope 2 (inlined core::tuple::<impl PartialOrd for (f32, f32)>::ge) {
             let mut _7: std::ops::ControlFlow<bool>;
-            let _8: bool;
             scope 3 {
             }
             scope 4 (inlined std::cmp::impls::<impl PartialOrd for f32>::__chaining_ge) {
@@ -19,8 +18,8 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool {
                 }
             }
             scope 6 (inlined std::cmp::impls::<impl PartialOrd for f32>::ge) {
+                let mut _8: f32;
                 let mut _9: f32;
-                let mut _10: f32;
             }
         }
     }
@@ -44,10 +43,7 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool {
         StorageDead(_5);
         StorageDead(_4);
         StorageDead(_3);
-        StorageLive(_8);
-        _8 = copy ((_7 as Break).0: bool);
-        _0 = copy _8;
-        StorageDead(_8);
+        _0 = copy ((_7 as Break).0: bool);
         goto -> bb3;
     }
 
@@ -55,13 +51,13 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool {
         StorageDead(_5);
         StorageDead(_4);
         StorageDead(_3);
+        StorageLive(_8);
+        _8 = copy ((*_1).1: f32);
         StorageLive(_9);
-        _9 = copy ((*_1).1: f32);
-        StorageLive(_10);
-        _10 = copy ((*_2).1: f32);
-        _0 = Ge(move _9, move _10);
-        StorageDead(_10);
+        _9 = copy ((*_2).1: f32);
+        _0 = Ge(move _8, move _9);
         StorageDead(_9);
+        StorageDead(_8);
         goto -> bb3;
     }
 
diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir
index 44df8b27993..7678c92a1f0 100644
--- a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir
@@ -7,7 +7,6 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool {
     scope 1 (inlined std::cmp::impls::<impl PartialOrd for &(u16, i16)>::le) {
         scope 2 (inlined core::tuple::<impl PartialOrd for (u16, i16)>::le) {
             let mut _7: std::ops::ControlFlow<bool>;
-            let _8: bool;
             scope 3 {
             }
             scope 4 (inlined std::cmp::impls::<impl PartialOrd for u16>::__chaining_le) {
@@ -19,8 +18,8 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool {
                 }
             }
             scope 6 (inlined std::cmp::impls::<impl PartialOrd for i16>::le) {
+                let mut _8: i16;
                 let mut _9: i16;
-                let mut _10: i16;
             }
         }
     }
@@ -44,10 +43,7 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool {
         StorageDead(_5);
         StorageDead(_4);
         StorageDead(_3);
-        StorageLive(_8);
-        _8 = copy ((_7 as Break).0: bool);
-        _0 = copy _8;
-        StorageDead(_8);
+        _0 = copy ((_7 as Break).0: bool);
         goto -> bb3;
     }
 
@@ -55,13 +51,13 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool {
         StorageDead(_5);
         StorageDead(_4);
         StorageDead(_3);
+        StorageLive(_8);
+        _8 = copy ((*_1).1: i16);
         StorageLive(_9);
-        _9 = copy ((*_1).1: i16);
-        StorageLive(_10);
-        _10 = copy ((*_2).1: i16);
-        _0 = Le(move _9, move _10);
-        StorageDead(_10);
+        _9 = copy ((*_2).1: i16);
+        _0 = Le(move _8, move _9);
         StorageDead(_9);
+        StorageDead(_8);
         goto -> bb3;
     }
 
diff --git a/tests/ui/autodiff/zst.rs b/tests/ui/autodiff/zst.rs
new file mode 100644
index 00000000000..7b9b5f5f20b
--- /dev/null
+++ b/tests/ui/autodiff/zst.rs
@@ -0,0 +1,17 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+//@ build-pass
+
+// Check that differentiating functions with ZST args does not break
+
+#![feature(autodiff)]
+
+#[core::autodiff::autodiff_forward(fd_inner, Const, Dual)]
+fn f(_zst: (), _x: &mut f64) {}
+
+fn fd(x: &mut f64, xd: &mut f64) {
+    fd_inner((), x, xd);
+}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-18088.rs b/tests/ui/issues/issue-18088.rs
deleted file mode 100644
index ba198884c63..00000000000
--- a/tests/ui/issues/issue-18088.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ check-pass
-
-pub trait Indexable<T>: std::ops::Index<usize, Output = T> {
-    fn index2(&self, i: usize) -> &T {
-        &self[i]
-    }
-}
-fn main() {}
diff --git a/tests/ui/issues/issue-21950.rs b/tests/ui/issues/issue-21950.rs
deleted file mode 100644
index 7a85ac91bca..00000000000
--- a/tests/ui/issues/issue-21950.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-trait Add<Rhs=Self> {
-    type Output;
-}
-
-impl Add for i32 {
-    type Output = i32;
-}
-
-fn main() {
-    let x = &10 as &dyn Add;
-    //~^ ERROR E0191
-}
diff --git a/tests/ui/issues/issue-2284.rs b/tests/ui/issues/issue-2284.rs
deleted file mode 100644
index 358331ecd9a..00000000000
--- a/tests/ui/issues/issue-2284.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ run-pass
-#![allow(dead_code)]
-
-trait Send {
-    fn f(&self);
-}
-
-fn f<T:Send>(t: T) {
-    t.f();
-}
-
-pub fn main() {
-}
diff --git a/tests/ui/mir/lint/assignment-overlap.rs b/tests/ui/mir/lint/assignment-overlap.rs
index bbc14090467..5d1213a7758 100644
--- a/tests/ui/mir/lint/assignment-overlap.rs
+++ b/tests/ui/mir/lint/assignment-overlap.rs
@@ -13,7 +13,7 @@ pub fn main() {
         let a: [u8; 1024];
         {
             a = a; //~ ERROR broken MIR
-                   //~^ ERROR encountered `Assign` statement with overlapping memory
+                   //~^ ERROR encountered `_1 = copy _1` statement with overlapping memory
             Return()
         }
     }
diff --git a/tests/ui/issues/issue-19479.rs b/tests/ui/traits/associated_type_bound/assoc-type-via-another-trait-issue-19479.rs
index ed586b76550..f17a89bcb5f 100644
--- a/tests/ui/issues/issue-19479.rs
+++ b/tests/ui/traits/associated_type_bound/assoc-type-via-another-trait-issue-19479.rs
@@ -1,5 +1,11 @@
 //@ check-pass
 
+//! Tests that it's possible to define an associated type in a trait
+//! using an associated type from type parameter bound trait in a blanket implementation.
+//!
+//! # Context
+//! Original issue: https://github.com/rust-lang/rust/issues/19479
+
 trait Base {
     fn dummy(&self) { }
 }
diff --git a/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs b/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs
new file mode 100644
index 00000000000..3c381505450
--- /dev/null
+++ b/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs
@@ -0,0 +1,19 @@
+//! Tests that compiler yields error E0191 when value with existing trait implementation
+//! is cast as same `dyn` trait without specifying associated type at the cast.
+//!
+//! # Context
+//! Original issue: https://github.com/rust-lang/rust/issues/21950
+
+trait Add<Rhs=Self> {
+    type Output;
+}
+
+impl Add for i32 {
+    type Output = i32;
+}
+
+fn main() {
+    let x = &10 as &dyn Add<i32, Output = i32>; //OK
+    let x = &10 as &dyn Add;
+    //~^ ERROR E0191
+}
diff --git a/tests/ui/issues/issue-21950.stderr b/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.stderr
index 24230cfe17f..5f4974e6f23 100644
--- a/tests/ui/issues/issue-21950.stderr
+++ b/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.stderr
@@ -1,5 +1,5 @@
 error[E0191]: the value of the associated type `Output` in `Add` must be specified
-  --> $DIR/issue-21950.rs:10:25
+  --> $DIR/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs:17:25
    |
 LL |     type Output;
    |     ----------- `Output` defined here
diff --git a/tests/ui/traits/core-marker-name-shadowing-issue-2284.rs b/tests/ui/traits/core-marker-name-shadowing-issue-2284.rs
new file mode 100644
index 00000000000..e5d083ac8c3
--- /dev/null
+++ b/tests/ui/traits/core-marker-name-shadowing-issue-2284.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+#![allow(dead_code)]
+
+//! Tests that user-defined trait is prioritized in compile time over
+//! the core::marker trait with the same name, allowing shadowing core traits.
+//!
+//! # Context
+//! Original issue: https://github.com/rust-lang/rust/issues/2284
+//! Original fix pull request: https://github.com/rust-lang/rust/pull/3792
+
+
+trait Send {
+    fn f(&self);
+}
+
+fn f<T:Send>(t: T) {
+    t.f();
+}
+
+pub fn main() {
+}
diff --git a/tests/ui/traits/inheritance/supertrait-operator-issue-18088.rs b/tests/ui/traits/inheritance/supertrait-operator-issue-18088.rs
new file mode 100644
index 00000000000..8bd45cd54a4
--- /dev/null
+++ b/tests/ui/traits/inheritance/supertrait-operator-issue-18088.rs
@@ -0,0 +1,13 @@
+//@ check-pass
+
+//! Tests that operators from supertrait are available directly on `self` for an inheritor trait.
+//!
+//! # Context
+//! Original issue: https://github.com/rust-lang/rust/issues/18088
+
+pub trait Indexable<T>: std::ops::Index<usize, Output = T> {
+    fn index2(&self, i: usize) -> &T {
+        &self[i]
+    }
+}
+fn main() {}