about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_arena/src/lib.rs28
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs25
-rw-r--r--compiler/rustc_borrowck/src/constraints/graph.rs40
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs43
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/find_use.rs14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs171
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs16
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_kills.rs12
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs6
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs14
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs40
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs39
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs80
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs28
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/constant.rs35
-rw-r--r--compiler/rustc_const_eval/messages.ftl10
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs253
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs116
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs26
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs23
-rw-r--r--compiler/rustc_const_eval/src/errors.rs38
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs58
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs21
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs72
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs31
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/stack.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs9
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs8
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0764.md4
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs8
-rw-r--r--compiler/rustc_feature/src/accepted.rs6
-rw-r--r--compiler/rustc_feature/src/unstable.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs413
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs24
-rw-r--r--compiler/rustc_interface/src/passes.rs2
-rw-r--r--compiler/rustc_lint/src/async_closures.rs1
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs74
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs8
-rw-r--r--compiler/rustc_lint/src/lib.rs4
-rw-r--r--compiler/rustc_lint/src/lints.rs6
-rw-r--r--compiler/rustc_lint/src/tail_expr_drop_order.rs16
-rw-r--r--compiler/rustc_lint/src/types.rs10
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs47
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs47
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs6
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs9
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs4
-rw-r--r--compiler/rustc_mir_build/messages.ftl1
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs9
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs2
-rw-r--r--compiler/rustc_mir_build/src/errors.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs35
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs20
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs14
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs55
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs10
-rw-r--r--compiler/rustc_mir_dataflow/src/points.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs10
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs10
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs22
-rw-r--r--compiler/rustc_mir_transform/src/deduplicate_blocks.rs2
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs4
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs2
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs98
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs4
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs2
-rw-r--r--compiler/rustc_mir_transform/src/ssa.rs4
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs6
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs66
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs3
-rw-r--r--compiler/rustc_passes/src/errors.rs4
-rw-r--r--compiler/rustc_passes/src/loops.rs38
-rw-r--r--compiler/rustc_privacy/src/lib.rs10
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs14
-rw-r--r--compiler/rustc_session/src/parse.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs12
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs24
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs35
-rw-r--r--compiler/rustc_ty_utils/src/layout_sanity_check.rs2
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs11
112 files changed, 1200 insertions, 1433 deletions
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 260c9fe44ba..cecf223b961 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -614,34 +614,34 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
 
     pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized {
         #[allow(clippy::mut_from_ref)]
-        fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
+        fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self;
         #[allow(clippy::mut_from_ref)]
-        fn allocate_from_iter<'a>(
-            arena: &'a Arena<'tcx>,
+        fn allocate_from_iter(
+            arena: &'tcx Arena<'tcx>,
             iter: impl ::std::iter::IntoIterator<Item = Self>,
-        ) -> &'a mut [Self];
+        ) -> &'tcx mut [Self];
     }
 
     // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
     impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T {
         #[inline]
         #[allow(clippy::mut_from_ref)]
-        fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
+        fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self {
             arena.dropless.alloc(self)
         }
         #[inline]
         #[allow(clippy::mut_from_ref)]
-        fn allocate_from_iter<'a>(
-            arena: &'a Arena<'tcx>,
+        fn allocate_from_iter(
+            arena: &'tcx Arena<'tcx>,
             iter: impl ::std::iter::IntoIterator<Item = Self>,
-        ) -> &'a mut [Self] {
+        ) -> &'tcx mut [Self] {
             arena.dropless.alloc_from_iter(iter)
         }
     }
     $(
         impl<'tcx> ArenaAllocatable<'tcx, rustc_arena::IsNotCopy> for $ty {
             #[inline]
-            fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
+            fn allocate_on(self, arena: &'tcx Arena<'tcx>) -> &'tcx mut Self {
                 if !::std::mem::needs_drop::<Self>() {
                     arena.dropless.alloc(self)
                 } else {
@@ -651,10 +651,10 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
 
             #[inline]
             #[allow(clippy::mut_from_ref)]
-            fn allocate_from_iter<'a>(
-                arena: &'a Arena<'tcx>,
+            fn allocate_from_iter(
+                arena: &'tcx Arena<'tcx>,
                 iter: impl ::std::iter::IntoIterator<Item = Self>,
-            ) -> &'a mut [Self] {
+            ) -> &'tcx mut [Self] {
                 if !::std::mem::needs_drop::<Self>() {
                     arena.dropless.alloc_from_iter(iter)
                 } else {
@@ -667,7 +667,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
     impl<'tcx> Arena<'tcx> {
         #[inline]
         #[allow(clippy::mut_from_ref)]
-        pub fn alloc<T: ArenaAllocatable<'tcx, C>, C>(&self, value: T) -> &mut T {
+        pub fn alloc<T: ArenaAllocatable<'tcx, C>, C>(&'tcx self, value: T) -> &mut T {
             value.allocate_on(self)
         }
 
@@ -691,7 +691,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
 
         #[allow(clippy::mut_from_ref)]
         pub fn alloc_from_iter<T: ArenaAllocatable<'tcx, C>, C>(
-            &self,
+            &'tcx self,
             iter: impl ::std::iter::IntoIterator<Item = T>,
         ) -> &mut [T] {
             T::allocate_from_iter(self, iter)
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 45e397a58c0..cfc534acd98 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -75,22 +75,9 @@ struct PostExpansionVisitor<'a> {
 
 impl<'a> PostExpansionVisitor<'a> {
     #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
-    fn check_abi(&self, abi: ast::StrLit, constness: ast::Const) {
+    fn check_abi(&self, abi: ast::StrLit) {
         let ast::StrLit { symbol_unescaped, span, .. } = abi;
 
-        if let ast::Const::Yes(_) = constness {
-            match symbol_unescaped {
-                // Stable
-                sym::Rust | sym::C => {}
-                abi => gate!(
-                    &self,
-                    const_extern_fn,
-                    span,
-                    format!("`{}` as a `const fn` ABI is unstable", abi)
-                ),
-            }
-        }
-
         match abi::is_enabled(self.features, span, symbol_unescaped.as_str()) {
             Ok(()) => (),
             Err(abi::AbiDisabled::Unstable { feature, explain }) => {
@@ -110,9 +97,9 @@ impl<'a> PostExpansionVisitor<'a> {
         }
     }
 
-    fn check_extern(&self, ext: ast::Extern, constness: ast::Const) {
+    fn check_extern(&self, ext: ast::Extern) {
         if let ast::Extern::Explicit(abi, _) = ext {
-            self.check_abi(abi, constness);
+            self.check_abi(abi);
         }
     }
 
@@ -239,7 +226,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         match &i.kind {
             ast::ItemKind::ForeignMod(foreign_module) => {
                 if let Some(abi) = foreign_module.abi {
-                    self.check_abi(abi, ast::Const::No);
+                    self.check_abi(abi);
                 }
             }
 
@@ -341,7 +328,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         match &ty.kind {
             ast::TyKind::BareFn(bare_fn_ty) => {
                 // Function pointers cannot be `const`
-                self.check_extern(bare_fn_ty.ext, ast::Const::No);
+                self.check_extern(bare_fn_ty.ext);
                 self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params);
             }
             ast::TyKind::Never => {
@@ -446,7 +433,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
         if let Some(header) = fn_kind.header() {
             // Stability of const fn methods are covered in `visit_assoc_item` below.
-            self.check_extern(header.ext, header.constness);
+            self.check_extern(header.ext);
         }
 
         if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind {
diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index 0ae837898b9..9d500586f08 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -97,11 +97,11 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> {
     /// Given the constraint set from which this graph was built
     /// creates a region graph so that you can iterate over *regions*
     /// and not constraints.
-    pub(crate) fn region_graph<'rg, 'tcx>(
-        &'rg self,
-        set: &'rg OutlivesConstraintSet<'tcx>,
+    pub(crate) fn region_graph<'a, 'tcx>(
+        &'a self,
+        set: &'a OutlivesConstraintSet<'tcx>,
         static_region: RegionVid,
-    ) -> RegionGraph<'rg, 'tcx, D> {
+    ) -> RegionGraph<'a, 'tcx, D> {
         RegionGraph::new(set, self, static_region)
     }
 
@@ -130,15 +130,15 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> {
     }
 }
 
-pub(crate) struct Edges<'s, 'tcx, D: ConstraintGraphDirection> {
-    graph: &'s ConstraintGraph<D>,
-    constraints: &'s OutlivesConstraintSet<'tcx>,
+pub(crate) struct Edges<'a, 'tcx, D: ConstraintGraphDirection> {
+    graph: &'a ConstraintGraph<D>,
+    constraints: &'a OutlivesConstraintSet<'tcx>,
     pointer: Option<OutlivesConstraintIndex>,
     next_static_idx: Option<usize>,
     static_region: RegionVid,
 }
 
-impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> {
+impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'a, 'tcx, D> {
     type Item = OutlivesConstraint<'tcx>;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -171,20 +171,20 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'s, 'tcx, D> {
 /// This struct brings together a constraint set and a (normal, not
 /// reverse) constraint graph. It implements the graph traits and is
 /// usd for doing the SCC computation.
-pub(crate) struct RegionGraph<'s, 'tcx, D: ConstraintGraphDirection> {
-    set: &'s OutlivesConstraintSet<'tcx>,
-    constraint_graph: &'s ConstraintGraph<D>,
+pub(crate) struct RegionGraph<'a, 'tcx, D: ConstraintGraphDirection> {
+    set: &'a OutlivesConstraintSet<'tcx>,
+    constraint_graph: &'a ConstraintGraph<D>,
     static_region: RegionVid,
 }
 
-impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> {
+impl<'a, 'tcx, D: ConstraintGraphDirection> RegionGraph<'a, 'tcx, D> {
     /// Creates a "dependency graph" where each region constraint `R1:
     /// R2` is treated as an edge `R1 -> R2`. We use this graph to
     /// construct SCCs for region inference but also for error
     /// reporting.
     pub(crate) fn new(
-        set: &'s OutlivesConstraintSet<'tcx>,
-        constraint_graph: &'s ConstraintGraph<D>,
+        set: &'a OutlivesConstraintSet<'tcx>,
+        constraint_graph: &'a ConstraintGraph<D>,
         static_region: RegionVid,
     ) -> Self {
         Self { set, constraint_graph, static_region }
@@ -192,18 +192,18 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> RegionGraph<'s, 'tcx, D> {
 
     /// Given a region `R`, iterate over all regions `R1` such that
     /// there exists a constraint `R: R1`.
-    pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'s, 'tcx, D> {
+    pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'a, 'tcx, D> {
         Successors {
             edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
         }
     }
 }
 
-pub(crate) struct Successors<'s, 'tcx, D: ConstraintGraphDirection> {
-    edges: Edges<'s, 'tcx, D>,
+pub(crate) struct Successors<'a, 'tcx, D: ConstraintGraphDirection> {
+    edges: Edges<'a, 'tcx, D>,
 }
 
-impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D> {
+impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'a, 'tcx, D> {
     type Item = RegionVid;
 
     fn next(&mut self) -> Option<Self::Item> {
@@ -211,7 +211,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'s, 'tcx, D>
     }
 }
 
-impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'s, 'tcx, D> {
+impl<'a, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph<'a, 'tcx, D> {
     type Node = RegionVid;
 
     fn num_nodes(&self) -> usize {
@@ -219,7 +219,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirection> graph::DirectedGraph for RegionGraph
     }
 }
 
-impl<'s, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'s, 'tcx, D> {
+impl<'a, 'tcx, D: ConstraintGraphDirection> graph::Successors for RegionGraph<'a, 'tcx, D> {
     fn successors(&self, node: Self::Node) -> impl Iterator<Item = Self::Node> {
         self.outgoing_regions(node)
     }
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 39994ad784a..5e1043ec817 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::{RegionVid, TyCtxt};
 use rustc_mir_dataflow::fmt::DebugWithContext;
 use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
-use rustc_mir_dataflow::{Analysis, AnalysisDomain, GenKill, Results, ResultsVisitable};
+use rustc_mir_dataflow::{Analysis, AnalysisDomain, Forward, GenKill, Results, ResultsVisitable};
 use tracing::debug;
 
 use crate::{places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext};
@@ -23,26 +23,25 @@ pub(crate) struct BorrowckResults<'a, 'tcx> {
 
 /// The transient state of the dataflow analyses used by the borrow checker.
 #[derive(Debug)]
-pub(crate) struct BorrowckFlowState<'a, 'tcx> {
+pub(crate) struct BorrowckDomain<'a, 'tcx> {
     pub(crate) borrows: <Borrows<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain,
     pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain,
     pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as AnalysisDomain<'tcx>>::Domain,
 }
 
 impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
-    // All three analyses are forward, but we have to use just one here.
-    type Direction = <Borrows<'a, 'tcx> as AnalysisDomain<'tcx>>::Direction;
-    type FlowState = BorrowckFlowState<'a, 'tcx>;
+    type Direction = Forward;
+    type Domain = BorrowckDomain<'a, 'tcx>;
 
-    fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
-        BorrowckFlowState {
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        BorrowckDomain {
             borrows: self.borrows.analysis.bottom_value(body),
             uninits: self.uninits.analysis.bottom_value(body),
             ever_inits: self.ever_inits.analysis.bottom_value(body),
         }
     }
 
-    fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
+    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
         state.borrows.clone_from(self.borrows.entry_set_for_block(block));
         state.uninits.clone_from(self.uninits.entry_set_for_block(block));
         state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block));
@@ -50,7 +49,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
 
     fn reconstruct_before_statement_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
@@ -61,7 +60,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
 
     fn reconstruct_statement_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
@@ -72,7 +71,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
 
     fn reconstruct_before_terminator_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         term: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
@@ -83,7 +82,7 @@ impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
 
     fn reconstruct_terminator_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         term: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
@@ -113,16 +112,16 @@ pub struct Borrows<'a, 'tcx> {
     borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
 }
 
-struct OutOfScopePrecomputer<'mir, 'tcx> {
+struct OutOfScopePrecomputer<'a, 'tcx> {
     visited: BitSet<mir::BasicBlock>,
     visit_stack: Vec<mir::BasicBlock>,
-    body: &'mir Body<'tcx>,
-    regioncx: &'mir RegionInferenceContext<'tcx>,
+    body: &'a Body<'tcx>,
+    regioncx: &'a RegionInferenceContext<'tcx>,
     borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
 }
 
-impl<'mir, 'tcx> OutOfScopePrecomputer<'mir, 'tcx> {
-    fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self {
+impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
+    fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
         OutOfScopePrecomputer {
             visited: BitSet::new_empty(body.basic_blocks.len()),
             visit_stack: vec![],
@@ -225,17 +224,17 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
     prec.borrows_out_of_scope_at_location
 }
 
-struct PoloniusOutOfScopePrecomputer<'mir, 'tcx> {
+struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
     visited: BitSet<mir::BasicBlock>,
     visit_stack: Vec<mir::BasicBlock>,
-    body: &'mir Body<'tcx>,
-    regioncx: &'mir RegionInferenceContext<'tcx>,
+    body: &'a Body<'tcx>,
+    regioncx: &'a RegionInferenceContext<'tcx>,
 
     loans_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
 }
 
-impl<'mir, 'tcx> PoloniusOutOfScopePrecomputer<'mir, 'tcx> {
-    fn new(body: &'mir Body<'tcx>, regioncx: &'mir RegionInferenceContext<'tcx>) -> Self {
+impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
+    fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
         Self {
             visited: BitSet::new_empty(body.basic_blocks.len()),
             visit_stack: vec![],
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 4a31aee5c96..c7a5d516ad7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3553,7 +3553,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         location: Location,
         mpi: MovePathIndex,
     ) -> (Vec<MoveSite>, Vec<Location>) {
-        fn predecessor_locations<'tcx, 'a>(
+        fn predecessor_locations<'a, 'tcx>(
             body: &'a mir::Body<'tcx>,
             location: Location,
         ) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a {
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
index bea8d3bfdfb..d8fa5506a99 100644
--- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
@@ -21,15 +21,15 @@ pub(crate) fn find<'tcx>(
     uf.find()
 }
 
-struct UseFinder<'cx, 'tcx> {
-    body: &'cx Body<'tcx>,
-    regioncx: &'cx Rc<RegionInferenceContext<'tcx>>,
+struct UseFinder<'a, 'tcx> {
+    body: &'a Body<'tcx>,
+    regioncx: &'a Rc<RegionInferenceContext<'tcx>>,
     tcx: TyCtxt<'tcx>,
     region_vid: RegionVid,
     start_point: Location,
 }
 
-impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
+impl<'a, 'tcx> UseFinder<'a, 'tcx> {
     fn find(&mut self) -> Option<Cause> {
         let mut queue = VecDeque::new();
         let mut visited = FxIndexSet::default();
@@ -93,8 +93,8 @@ impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
     }
 }
 
-struct DefUseVisitor<'cx, 'tcx> {
-    body: &'cx Body<'tcx>,
+struct DefUseVisitor<'a, 'tcx> {
+    body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     region_vid: RegionVid,
     def_use_result: Option<DefUseResult>,
@@ -106,7 +106,7 @@ enum DefUseResult {
     UseDrop { local: Local },
 }
 
-impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for DefUseVisitor<'a, 'tcx> {
     fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
         let local_ty = self.body.local_decls[local].ty;
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 6e3fac1e680..2bbafb0163e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -558,7 +558,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 ty: Ty<'tcx>,
                 suggested: bool,
             }
-            impl<'a, 'cx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'cx, 'tcx> {
+            impl<'a, 'infcx, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'infcx, 'tcx> {
                 fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
                     hir::intravisit::walk_stmt(self, stmt);
                     let expr = match stmt.kind {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index d98c66b0f3b..58e73030749 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -83,7 +83,7 @@ mod util;
 pub mod consumers;
 
 use borrow_set::{BorrowData, BorrowSet};
-use dataflow::{BorrowIndex, BorrowckFlowState as Flows, BorrowckResults, Borrows};
+use dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows};
 use nll::PoloniusOutput;
 use place_ext::PlaceExt;
 use places_conflict::{places_conflict, PlaceConflictBias};
@@ -602,25 +602,25 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
 impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
     for MirBorrowckCtxt<'a, '_, 'tcx>
 {
-    type FlowState = Flows<'a, 'tcx>;
+    type Domain = BorrowckDomain<'a, 'tcx>;
 
     fn visit_statement_before_primary_effect(
         &mut self,
         _results: &mut R,
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
         stmt: &'a Statement<'tcx>,
         location: Location,
     ) {
-        debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, flow_state);
+        debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
         let span = stmt.source_info.span;
 
-        self.check_activations(location, span, flow_state);
+        self.check_activations(location, span, state);
 
         match &stmt.kind {
             StatementKind::Assign(box (lhs, rhs)) => {
-                self.consume_rvalue(location, (rhs, span), flow_state);
+                self.consume_rvalue(location, (rhs, span), state);
 
-                self.mutate_place(location, (*lhs, span), Shallow(None), flow_state);
+                self.mutate_place(location, (*lhs, span), Shallow(None), state);
             }
             StatementKind::FakeRead(box (_, place)) => {
                 // Read for match doesn't access any memory and is used to
@@ -637,11 +637,11 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
                     location,
                     InitializationRequiringAction::Use,
                     (place.as_ref(), span),
-                    flow_state,
+                    state,
                 );
             }
             StatementKind::Intrinsic(box kind) => match kind {
-                NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
+                NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), state),
                 NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
                     span,
                     "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
@@ -662,7 +662,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
                     (Place::from(*local), span),
                     (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
                     LocalMutationIsAllowed::Yes,
-                    flow_state,
+                    state,
                 );
             }
             StatementKind::Nop
@@ -677,18 +677,18 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
     fn visit_terminator_before_primary_effect(
         &mut self,
         _results: &mut R,
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
         term: &'a Terminator<'tcx>,
         loc: Location,
     ) {
-        debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, flow_state);
+        debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
         let span = term.source_info.span;
 
-        self.check_activations(loc, span, flow_state);
+        self.check_activations(loc, span, state);
 
         match &term.kind {
             TerminatorKind::SwitchInt { discr, targets: _ } => {
-                self.consume_operand(loc, (discr, span), flow_state);
+                self.consume_operand(loc, (discr, span), state);
             }
             TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
                 debug!(
@@ -704,7 +704,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
                     (*place, span),
                     (AccessDepth::Drop, Write(write_kind)),
                     LocalMutationIsAllowed::Yes,
-                    flow_state,
+                    state,
                 );
             }
             TerminatorKind::Call {
@@ -716,29 +716,29 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
                 call_source: _,
                 fn_span: _,
             } => {
-                self.consume_operand(loc, (func, span), flow_state);
+                self.consume_operand(loc, (func, span), state);
                 for arg in args {
-                    self.consume_operand(loc, (&arg.node, arg.span), flow_state);
+                    self.consume_operand(loc, (&arg.node, arg.span), state);
                 }
-                self.mutate_place(loc, (*destination, span), Deep, flow_state);
+                self.mutate_place(loc, (*destination, span), Deep, state);
             }
             TerminatorKind::TailCall { func, args, fn_span: _ } => {
-                self.consume_operand(loc, (func, span), flow_state);
+                self.consume_operand(loc, (func, span), state);
                 for arg in args {
-                    self.consume_operand(loc, (&arg.node, arg.span), flow_state);
+                    self.consume_operand(loc, (&arg.node, arg.span), state);
                 }
             }
             TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
-                self.consume_operand(loc, (cond, span), flow_state);
+                self.consume_operand(loc, (cond, span), state);
                 if let AssertKind::BoundsCheck { len, index } = &**msg {
-                    self.consume_operand(loc, (len, span), flow_state);
-                    self.consume_operand(loc, (index, span), flow_state);
+                    self.consume_operand(loc, (len, span), state);
+                    self.consume_operand(loc, (index, span), state);
                 }
             }
 
             TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
-                self.consume_operand(loc, (value, span), flow_state);
-                self.mutate_place(loc, (*resume_arg, span), Deep, flow_state);
+                self.consume_operand(loc, (value, span), state);
+                self.mutate_place(loc, (*resume_arg, span), Deep, state);
             }
 
             TerminatorKind::InlineAsm {
@@ -752,22 +752,17 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
                 for op in operands {
                     match op {
                         InlineAsmOperand::In { reg: _, value } => {
-                            self.consume_operand(loc, (value, span), flow_state);
+                            self.consume_operand(loc, (value, span), state);
                         }
                         InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
                             if let Some(place) = place {
-                                self.mutate_place(loc, (*place, span), Shallow(None), flow_state);
+                                self.mutate_place(loc, (*place, span), Shallow(None), state);
                             }
                         }
                         InlineAsmOperand::InOut { reg: _, late: _, in_value, out_place } => {
-                            self.consume_operand(loc, (in_value, span), flow_state);
+                            self.consume_operand(loc, (in_value, span), state);
                             if let &Some(out_place) = out_place {
-                                self.mutate_place(
-                                    loc,
-                                    (out_place, span),
-                                    Shallow(None),
-                                    flow_state,
-                                );
+                                self.mutate_place(loc, (out_place, span), Shallow(None), state);
                             }
                         }
                         InlineAsmOperand::Const { value: _ }
@@ -794,7 +789,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
     fn visit_terminator_after_primary_effect(
         &mut self,
         _results: &mut R,
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
         term: &'a Terminator<'tcx>,
         loc: Location,
     ) {
@@ -805,7 +800,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
                 if self.movable_coroutine {
                     // Look for any active borrows to locals
                     let borrow_set = self.borrow_set.clone();
-                    for i in flow_state.borrows.iter() {
+                    for i in state.borrows.iter() {
                         let borrow = &borrow_set[i];
                         self.check_for_local_borrow(borrow, span);
                     }
@@ -821,7 +816,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
                 // StorageDead, but we don't always emit those (notably on unwind paths),
                 // so this "extra check" serves as a kind of backup.
                 let borrow_set = self.borrow_set.clone();
-                for i in flow_state.borrows.iter() {
+                for i in state.borrows.iter() {
                     let borrow = &borrow_set[i];
                     self.check_for_invalidation_at_exit(loc, borrow, span);
                 }
@@ -989,7 +984,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         place_span: (Place<'tcx>, Span),
         kind: (AccessDepth, ReadOrWrite),
         is_local_mutation_allowed: LocalMutationIsAllowed,
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) {
         let (sd, rw) = kind;
 
@@ -1020,11 +1015,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
             place_span,
             rw,
             is_local_mutation_allowed,
-            flow_state,
+            state,
             location,
         );
-        let conflict_error =
-            self.check_access_for_conflict(location, place_span, sd, rw, flow_state);
+        let conflict_error = self.check_access_for_conflict(location, place_span, sd, rw, state);
 
         if conflict_error || mutability_error {
             debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
@@ -1032,14 +1026,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         }
     }
 
-    #[instrument(level = "debug", skip(self, flow_state))]
+    #[instrument(level = "debug", skip(self, state))]
     fn check_access_for_conflict(
         &mut self,
         location: Location,
         place_span: (Place<'tcx>, Span),
         sd: AccessDepth,
         rw: ReadOrWrite,
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) -> bool {
         let mut error_reported = false;
         let borrow_set = Rc::clone(&self.borrow_set);
@@ -1054,7 +1048,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
             }
             &polonius_output
         } else {
-            &flow_state.borrows
+            &state.borrows
         };
 
         each_borrow_involving_path(
@@ -1180,17 +1174,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         location: Location,
         place_span: (Place<'tcx>, Span),
         kind: AccessDepth,
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) {
         // Write of P[i] or *P requires P init'd.
-        self.check_if_assigned_path_is_moved(location, place_span, flow_state);
+        self.check_if_assigned_path_is_moved(location, place_span, state);
 
         self.access_place(
             location,
             place_span,
             (kind, Write(WriteKind::Mutate)),
             LocalMutationIsAllowed::No,
-            flow_state,
+            state,
         );
     }
 
@@ -1198,7 +1192,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         &mut self,
         location: Location,
         (rvalue, span): (&'a Rvalue<'tcx>, Span),
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) {
         match rvalue {
             &Rvalue::Ref(_ /*rgn*/, bk, place) => {
@@ -1224,7 +1218,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     (place, span),
                     access_kind,
                     LocalMutationIsAllowed::No,
-                    flow_state,
+                    state,
                 );
 
                 let action = if bk == BorrowKind::Fake(FakeBorrowKind::Shallow) {
@@ -1237,7 +1231,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     location,
                     action,
                     (place.as_ref(), span),
-                    flow_state,
+                    state,
                 );
             }
 
@@ -1257,14 +1251,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     (place, span),
                     access_kind,
                     LocalMutationIsAllowed::No,
-                    flow_state,
+                    state,
                 );
 
                 self.check_if_path_or_subpath_is_moved(
                     location,
                     InitializationRequiringAction::Borrow,
                     (place.as_ref(), span),
-                    flow_state,
+                    state,
                 );
             }
 
@@ -1275,7 +1269,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
             | Rvalue::UnaryOp(_ /*un_op*/, operand)
             | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
             | Rvalue::ShallowInitBox(operand, _ /*ty*/) => {
-                self.consume_operand(location, (operand, span), flow_state)
+                self.consume_operand(location, (operand, span), state)
             }
 
             &Rvalue::CopyForDeref(place) => {
@@ -1284,7 +1278,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     (place, span),
                     (Deep, Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
-                    flow_state,
+                    state,
                 );
 
                 // Finally, check if path was already moved.
@@ -1292,7 +1286,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     location,
                     InitializationRequiringAction::Use,
                     (place.as_ref(), span),
-                    flow_state,
+                    state,
                 );
             }
 
@@ -1307,19 +1301,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     (place, span),
                     (Shallow(af), Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
-                    flow_state,
+                    state,
                 );
                 self.check_if_path_or_subpath_is_moved(
                     location,
                     InitializationRequiringAction::Use,
                     (place.as_ref(), span),
-                    flow_state,
+                    state,
                 );
             }
 
             Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
-                self.consume_operand(location, (operand1, span), flow_state);
-                self.consume_operand(location, (operand2, span), flow_state);
+                self.consume_operand(location, (operand1, span), state);
+                self.consume_operand(location, (operand2, span), state);
             }
 
             Rvalue::NullaryOp(_op, _ty) => {
@@ -1349,7 +1343,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                 }
 
                 for operand in operands {
-                    self.consume_operand(location, (operand, span), flow_state);
+                    self.consume_operand(location, (operand, span), state);
                 }
             }
         }
@@ -1456,7 +1450,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         &mut self,
         location: Location,
         (operand, span): (&'a Operand<'tcx>, Span),
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) {
         match *operand {
             Operand::Copy(place) => {
@@ -1467,7 +1461,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     (place, span),
                     (Deep, Read(ReadKind::Copy)),
                     LocalMutationIsAllowed::No,
-                    flow_state,
+                    state,
                 );
 
                 // Finally, check if path was already moved.
@@ -1475,7 +1469,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     location,
                     InitializationRequiringAction::Use,
                     (place.as_ref(), span),
-                    flow_state,
+                    state,
                 );
             }
             Operand::Move(place) => {
@@ -1488,7 +1482,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     (place, span),
                     (Deep, Write(WriteKind::Move)),
                     LocalMutationIsAllowed::Yes,
-                    flow_state,
+                    state,
                 );
 
                 // Finally, check if path was already moved.
@@ -1496,7 +1490,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     location,
                     InitializationRequiringAction::Use,
                     (place.as_ref(), span),
-                    flow_state,
+                    state,
                 );
             }
             Operand::Constant(_) => {}
@@ -1576,7 +1570,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         }
     }
 
-    fn check_activations(&mut self, location: Location, span: Span, flow_state: &Flows<'a, 'tcx>) {
+    fn check_activations(
+        &mut self,
+        location: Location,
+        span: Span,
+        state: &BorrowckDomain<'a, 'tcx>,
+    ) {
         // Two-phase borrow support: For each activation that is newly
         // generated at this statement, check if it interferes with
         // another borrow.
@@ -1595,7 +1594,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                 (borrow.borrowed_place, span),
                 (Deep, Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index)),
                 LocalMutationIsAllowed::No,
-                flow_state,
+                state,
             );
             // We do not need to call `check_if_path_or_subpath_is_moved`
             // again, as we already called it when we made the
@@ -1739,9 +1738,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         location: Location,
         desired_action: InitializationRequiringAction,
         place_span: (PlaceRef<'tcx>, Span),
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) {
-        let maybe_uninits = &flow_state.uninits;
+        let maybe_uninits = &state.uninits;
 
         // Bad scenarios:
         //
@@ -1844,9 +1843,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         location: Location,
         desired_action: InitializationRequiringAction,
         place_span: (PlaceRef<'tcx>, Span),
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) {
-        let maybe_uninits = &flow_state.uninits;
+        let maybe_uninits = &state.uninits;
 
         // Bad scenarios:
         //
@@ -1863,7 +1862,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         //    must have been initialized for the use to be sound.
         // 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
 
-        self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
+        self.check_if_full_path_is_moved(location, desired_action, place_span, state);
 
         if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
             place_span.0.last_projection()
@@ -1943,7 +1942,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         &mut self,
         location: Location,
         (place, span): (Place<'tcx>, Span),
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) {
         debug!("check_if_assigned_path_is_moved place: {:?}", place);
 
@@ -1965,7 +1964,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                 ProjectionElem::Deref => {
                     self.check_if_full_path_is_moved(
                         location, InitializationRequiringAction::Use,
-                        (place_base, span), flow_state);
+                        (place_base, span), state);
                     // (base initialized; no need to
                     // recur further)
                     break;
@@ -1985,7 +1984,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                         ty::Adt(def, _) if def.has_dtor(tcx) => {
                             self.check_if_path_or_subpath_is_moved(
                                 location, InitializationRequiringAction::Assignment,
-                                (place_base, span), flow_state);
+                                (place_base, span), state);
 
                             // (base initialized; no need to
                             // recur further)
@@ -1995,7 +1994,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                         // Once `let s; s.x = V; read(s.x);`,
                         // is allowed, remove this match arm.
                         ty::Adt(..) | ty::Tuple(..) => {
-                            check_parent_of_field(self, location, place_base, span, flow_state);
+                            check_parent_of_field(self, location, place_base, span, state);
                         }
 
                         _ => {}
@@ -2009,7 +2008,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
             location: Location,
             base: PlaceRef<'tcx>,
             span: Span,
-            flow_state: &Flows<'a, 'tcx>,
+            state: &BorrowckDomain<'a, 'tcx>,
         ) {
             // rust-lang/rust#21232: Until Rust allows reads from the
             // initialized parts of partially initialized structs, we
@@ -2042,7 +2041,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
 
             // Shallow so that we'll stop at any dereference; we'll
             // report errors about issues with such bases elsewhere.
-            let maybe_uninits = &flow_state.uninits;
+            let maybe_uninits = &state.uninits;
 
             // Find the shortest uninitialized prefix you can reach
             // without going over a Deref.
@@ -2100,7 +2099,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         (place, span): (Place<'tcx>, Span),
         kind: ReadOrWrite,
         is_local_mutation_allowed: LocalMutationIsAllowed,
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
         location: Location,
     ) -> bool {
         debug!(
@@ -2124,7 +2123,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                 };
                 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
                     Ok(root_place) => {
-                        self.add_used_mut(root_place, flow_state);
+                        self.add_used_mut(root_place, state);
                         return false;
                     }
                     Err(place_err) => {
@@ -2136,7 +2135,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
             Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => {
                 match self.is_mutable(place.as_ref(), is_local_mutation_allowed) {
                     Ok(root_place) => {
-                        self.add_used_mut(root_place, flow_state);
+                        self.add_used_mut(root_place, state);
                         return false;
                     }
                     Err(place_err) => {
@@ -2194,7 +2193,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         // partial initialization, do not complain about mutability
         // errors except for actual mutation (as opposed to an attempt
         // to do a partial initialization).
-        let previously_initialized = self.is_local_ever_initialized(place.local, flow_state);
+        let previously_initialized = self.is_local_ever_initialized(place.local, state);
 
         // at this point, we have set up the error reporting state.
         if let Some(init_index) = previously_initialized {
@@ -2216,22 +2215,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
     fn is_local_ever_initialized(
         &self,
         local: Local,
-        flow_state: &Flows<'a, 'tcx>,
+        state: &BorrowckDomain<'a, 'tcx>,
     ) -> Option<InitIndex> {
         let mpi = self.move_data.rev_lookup.find_local(local)?;
         let ii = &self.move_data.init_path_map[mpi];
-        ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied()
+        ii.into_iter().find(|&&index| state.ever_inits.contains(index)).copied()
     }
 
     /// Adds the place into the used mutable variables set
-    fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'a, 'tcx>) {
+    fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, state: &BorrowckDomain<'a, 'tcx>) {
         match root_place {
             RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => {
                 // If the local may have been initialized, and it is now currently being
                 // mutated, then it is justified to be annotated with the `mut`
                 // keyword, since the mutation may be a possible reassignment.
                 if is_local_mutation_allowed != LocalMutationIsAllowed::Yes
-                    && self.is_local_ever_initialized(local, flow_state).is_some()
+                    && self.is_local_ever_initialized(local, state).is_some()
                 {
                     self.used_mut.insert(local);
                 }
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index 0b9b8768b56..afd811a0efb 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -32,18 +32,18 @@ pub(super) fn emit_loan_invalidations<'tcx>(
     visitor.visit_body(body);
 }
 
-struct LoanInvalidationsGenerator<'cx, 'tcx> {
+struct LoanInvalidationsGenerator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    all_facts: &'cx mut AllFacts,
-    location_table: &'cx LocationTable,
-    body: &'cx Body<'tcx>,
-    dominators: &'cx Dominators<BasicBlock>,
-    borrow_set: &'cx BorrowSet<'tcx>,
+    all_facts: &'a mut AllFacts,
+    location_table: &'a LocationTable,
+    body: &'a Body<'tcx>,
+    dominators: &'a Dominators<BasicBlock>,
+    borrow_set: &'a BorrowSet<'tcx>,
 }
 
 /// Visits the whole MIR and generates `invalidates()` facts.
 /// Most of the code implementing this was stolen from `borrow_check/mod.rs`.
-impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'a, 'tcx> {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         self.check_activations(location);
 
@@ -212,7 +212,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
+impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
     /// Simulates mutation of a place.
     fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) {
         self.access_place(
diff --git a/compiler/rustc_borrowck/src/polonius/loan_kills.rs b/compiler/rustc_borrowck/src/polonius/loan_kills.rs
index ed9f714e500..68e0865ab82 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_kills.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_kills.rs
@@ -25,15 +25,15 @@ pub(super) fn emit_loan_kills<'tcx>(
     }
 }
 
-struct LoanKillsGenerator<'cx, 'tcx> {
+struct LoanKillsGenerator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    all_facts: &'cx mut AllFacts,
-    location_table: &'cx LocationTable,
-    borrow_set: &'cx BorrowSet<'tcx>,
-    body: &'cx Body<'tcx>,
+    all_facts: &'a mut AllFacts,
+    location_table: &'a LocationTable,
+    borrow_set: &'a BorrowSet<'tcx>,
+    body: &'a Body<'tcx>,
 }
 
-impl<'cx, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'cx, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'a, 'tcx> {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         // Also record CFG facts here.
         self.all_facts.cfg_edge.push((
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 33cdb1b1f37..c711190cb97 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -181,12 +181,12 @@ impl UniversalRegionRelations<'_> {
     }
 }
 
-struct UniversalRegionRelationsBuilder<'this, 'tcx> {
-    infcx: &'this InferCtxt<'tcx>,
+struct UniversalRegionRelationsBuilder<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     universal_regions: Rc<UniversalRegions<'tcx>>,
     implicit_region_bound: ty::Region<'tcx>,
-    constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
+    constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 
     // outputs:
     outlives: TransitiveRelationBuilder<RegionVid>,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index 79db8f4252b..a73467824de 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -148,12 +148,12 @@ fn record_regular_live_regions<'tcx>(
 }
 
 /// Visitor looking for regions that should be live within rvalues or calls.
-struct LiveVariablesVisitor<'cx, 'tcx> {
+struct LiveVariablesVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    liveness_constraints: &'cx mut LivenessValues,
+    liveness_constraints: &'a mut LivenessValues,
 }
 
-impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> {
     /// We sometimes have `args` within an rvalue, or within a
     /// call. Make them live at the location where they appear.
     fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) {
@@ -188,7 +188,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'cx, 'tcx> {
     }
 }
 
-impl<'cx, 'tcx> LiveVariablesVisitor<'cx, 'tcx> {
+impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> {
     /// Some variable is "regular live" at `location` -- i.e., it may be used later. This means that
     /// all regions appearing in the type of `value` must be live at `location`.
     fn record_regions_live_at<T>(&mut self, value: T, location: Location)
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index 7f6aabf8841..3a458731f28 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -11,13 +11,13 @@ use crate::location::{LocationIndex, LocationTable};
 type VarPointRelation = Vec<(Local, LocationIndex)>;
 type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;
 
-struct UseFactsExtractor<'me, 'tcx> {
-    var_defined_at: &'me mut VarPointRelation,
-    var_used_at: &'me mut VarPointRelation,
-    location_table: &'me LocationTable,
-    var_dropped_at: &'me mut VarPointRelation,
-    move_data: &'me MoveData<'tcx>,
-    path_accessed_at_base: &'me mut PathPointRelation,
+struct UseFactsExtractor<'a, 'tcx> {
+    var_defined_at: &'a mut VarPointRelation,
+    var_used_at: &'a mut VarPointRelation,
+    location_table: &'a LocationTable,
+    var_dropped_at: &'a mut VarPointRelation,
+    move_data: &'a MoveData<'tcx>,
+    path_accessed_at_base: &'a mut PathPointRelation,
 }
 
 // A Visitor to walk through the MIR and extract point-wise facts
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 421f4e2efe0..71892a67ffc 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -58,8 +58,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     }
 }
 
-struct NllTypeRelating<'me, 'bccx, 'tcx> {
-    type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
+struct NllTypeRelating<'a, 'b, 'tcx> {
+    type_checker: &'a mut TypeChecker<'b, 'tcx>,
 
     /// Where (and why) is this relation taking place?
     locations: Locations,
@@ -82,9 +82,9 @@ struct NllTypeRelating<'me, 'bccx, 'tcx> {
     ambient_variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
 }
 
-impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
+impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
     fn new(
-        type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
+        type_checker: &'a mut TypeChecker<'b, 'tcx>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
         universe_info: UniverseInfo<'tcx>,
@@ -309,7 +309,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
     }
 }
 
-impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> {
+impl<'b, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
     fn cx(&self) -> TyCtxt<'tcx> {
         self.type_checker.infcx.tcx
     }
@@ -520,7 +520,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx
     }
 }
 
-impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> {
+impl<'b, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'b, 'tcx> {
     fn span(&self) -> Span {
         self.locations.span(self.type_checker.body)
     }
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 734da318ac1..66df393b501 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -65,7 +65,7 @@ struct AllocFnFactory<'a, 'b> {
     span: Span,
     ty_span: Span,
     global: Ident,
-    cx: &'b ExtCtxt<'a>,
+    cx: &'a ExtCtxt<'b>,
 }
 
 impl AllocFnFactory<'_, '_> {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 604a88393fd..a5621aec244 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -180,34 +180,20 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 return;
             }
 
-            // Make sure this is actually an array, since typeck only checks the length-suffixed
-            // version of this intrinsic.
+            // Make sure this is actually a SIMD vector.
             let idx_ty = fx.monomorphize(idx.node.ty(fx.mir, fx.tcx));
-            let n: u16 = match idx_ty.kind() {
-                ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => len
-                    .try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
-                    .unwrap_or_else(|| {
-                        span_bug!(span, "could not evaluate shuffle index array length")
-                    })
-                    .try_into()
-                    .unwrap(),
-                _ if idx_ty.is_simd()
-                    && matches!(
-                        idx_ty.simd_size_and_type(fx.tcx).1.kind(),
-                        ty::Uint(ty::UintTy::U32)
-                    ) =>
-                {
-                    idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap()
-                }
-                _ => {
-                    fx.tcx.dcx().span_err(
-                        span,
-                        format!("simd_shuffle index must be an array of `u32`, got `{}`", idx_ty),
-                    );
-                    // Prevent verifier error
-                    fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
-                    return;
-                }
+            let n: u16 = if idx_ty.is_simd()
+                && matches!(idx_ty.simd_size_and_type(fx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
+            {
+                idx_ty.simd_size_and_type(fx.tcx).0.try_into().unwrap()
+            } else {
+                fx.tcx.dcx().span_err(
+                    span,
+                    format!("simd_shuffle index must be a SIMD vector of `u32`, got `{}`", idx_ty),
+                );
+                // Prevent verifier error
+                fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
+                return;
             };
 
             assert_eq!(x.layout(), y.layout());
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 6ba678e2e7c..31d778823e0 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1939,33 +1939,18 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
             self.int_type
         };
 
-        let mut mask_elements = if let Some(vector_type) = mask.get_type().dyncast_vector() {
-            let mask_num_units = vector_type.get_num_units();
-            let mut mask_elements = vec![];
-            for i in 0..mask_num_units {
-                let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
-                mask_elements.push(self.context.new_cast(
-                    self.location,
-                    self.extract_element(mask, index).to_rvalue(),
-                    mask_element_type,
-                ));
-            }
-            mask_elements
-        } else {
-            let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
-            let mask_num_units = struct_type.get_field_count();
-            let mut mask_elements = vec![];
-            for i in 0..mask_num_units {
-                let field = struct_type.get_field(i as i32);
-                mask_elements.push(self.context.new_cast(
-                    self.location,
-                    mask.access_field(self.location, field).to_rvalue(),
-                    mask_element_type,
-                ));
-            }
-            mask_elements
-        };
-        let mask_num_units = mask_elements.len();
+        let vector_type =
+            mask.get_type().dyncast_vector().expect("simd_shuffle mask should be of vector type");
+        let mask_num_units = vector_type.get_num_units();
+        let mut mask_elements = vec![];
+        for i in 0..mask_num_units {
+            let index = self.context.new_rvalue_from_long(self.cx.type_u32(), i as _);
+            mask_elements.push(self.context.new_cast(
+                self.location,
+                self.extract_element(mask, index).to_rvalue(),
+                mask_element_type,
+            ));
+        }
 
         // NOTE: the mask needs to be the same length as the input vectors, so add the missing
         // elements in the mask if needed.
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 96a833ccaf2..2eabc1430db 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -14,7 +14,6 @@ use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
 #[cfg(feature = "master")]
 use rustc_hir as hir;
 use rustc_middle::mir::BinOp;
-use rustc_middle::span_bug;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{sym, Span, Symbol};
@@ -353,24 +352,14 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     }
 
     if name == sym::simd_shuffle {
-        // Make sure this is actually an array or SIMD vector, since typeck only checks the length-suffixed
-        // version of this intrinsic.
+        // Make sure this is actually a SIMD vector.
         let idx_ty = args[2].layout.ty;
-        let n: u64 = match idx_ty.kind() {
-            ty::Array(ty, len) if matches!(*ty.kind(), ty::Uint(ty::UintTy::U32)) => {
-                len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
-                    || span_bug!(span, "could not evaluate shuffle index array length"),
-                )
-            }
-            _ if idx_ty.is_simd()
-                && matches!(
-                    idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(),
-                    ty::Uint(ty::UintTy::U32)
-                ) =>
-            {
-                idx_ty.simd_size_and_type(bx.cx.tcx).0
-            }
-            _ => return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }),
+        let n: u64 = if idx_ty.is_simd()
+            && matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
+        {
+            idx_ty.simd_size_and_type(bx.cx.tcx).0
+        } else {
+            return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty })
         };
         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 05fb77a193a..9705dd506b9 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -573,6 +573,8 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     span,
                 ) {
                     Ok(llval) => llval,
+                    // If there was an error, just skip this invocation... we'll abort compilation anyway,
+                    // but we can keep codegen'ing to find more errors.
                     Err(()) => return Ok(()),
                 }
             }
@@ -1290,24 +1292,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     }
 
     if name == sym::simd_shuffle {
-        // Make sure this is actually an array or SIMD vector, since typeck only checks the length-suffixed
-        // version of this intrinsic.
+        // Make sure this is actually a SIMD vector.
         let idx_ty = args[2].layout.ty;
-        let n: u64 = match idx_ty.kind() {
-            ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
-                len.try_eval_target_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(
-                    || span_bug!(span, "could not evaluate shuffle index array length"),
-                )
-            }
-            _ if idx_ty.is_simd()
-                && matches!(
-                    idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(),
-                    ty::Uint(ty::UintTy::U32)
-                ) =>
-            {
-                idx_ty.simd_size_and_type(bx.cx.tcx).0
-            }
-            _ => return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty }),
+        let n: u64 = if idx_ty.is_simd()
+            && matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
+        {
+            idx_ty.simd_size_and_type(bx.cx.tcx).0
+        } else {
+            return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty })
         };
 
         let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn);
@@ -1322,38 +1314,24 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
 
         let total_len = u128::from(in_len) * 2;
 
-        let vector = args[2].immediate();
-
-        let indices: Option<Vec<_>> = (0..n)
-            .map(|i| {
-                let arg_idx = i;
-                let val = bx.const_get_elt(vector, i as u64);
-                match bx.const_to_opt_u128(val, true) {
-                    None => {
-                        bug!("typeck should have already ensured that these are const")
-                    }
-                    Some(idx) if idx >= total_len => {
-                        bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
-                            span,
-                            name,
-                            arg_idx,
-                            total_len,
-                        });
-                        None
-                    }
-                    Some(idx) => Some(bx.const_i32(idx as i32)),
-                }
-            })
-            .collect();
-        let Some(indices) = indices else {
-            return Ok(bx.const_null(llret_ty));
-        };
+        // Check that the indices are in-bounds.
+        let indices = args[2].immediate();
+        for i in 0..n {
+            let val = bx.const_get_elt(indices, i as u64);
+            let idx = bx
+                .const_to_opt_u128(val, true)
+                .unwrap_or_else(|| bug!("typeck should have already ensured that these are const"));
+            if idx >= total_len {
+                return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
+                    span,
+                    name,
+                    arg_idx: i,
+                    total_len,
+                });
+            }
+        }
 
-        return Ok(bx.shuffle_vector(
-            args[0].immediate(),
-            args[1].immediate(),
-            bx.const_vector(&indices),
-        ));
+        return Ok(bx.shuffle_vector(args[0].immediate(), args[1].immediate(), indices));
     }
 
     if name == sym::simd_insert {
@@ -1371,13 +1349,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             .const_to_opt_u128(args[1].immediate(), false)
             .expect("typeck should have ensure that this is a const");
         if idx >= in_len.into() {
-            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
+            return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
                 span,
                 name,
                 arg_idx: 1,
                 total_len: in_len.into(),
             });
-            return Ok(bx.const_null(llret_ty));
         }
         return Ok(bx.insert_element(
             args[0].immediate(),
@@ -1394,13 +1371,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             .const_to_opt_u128(args[1].immediate(), false)
             .expect("typeck should have ensure that this is a const");
         if idx >= in_len.into() {
-            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
+            return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
                 span,
                 name,
                 arg_idx: 1,
                 total_len: in_len.into(),
             });
-            return Ok(bx.const_null(llret_ty));
         }
         return Ok(bx.extract_element(args[0].immediate(), bx.const_i32(idx as i32)));
     }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 8a6a2acd87d..9091602d75b 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -132,7 +132,7 @@ codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `
 
 codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
 
-codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
+codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be a SIMD vector of `u32`, got `{$ty}`
 
 codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 40eb35deea5..8b855bd0dd5 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -3044,7 +3044,7 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootErro
             "iphonesimulator"
                 if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => {
             }
-            "macosx10.15"
+            "macosx"
                 if sdkroot.contains("iPhoneOS.platform")
                     || sdkroot.contains("iPhoneSimulator.platform") => {}
             "watchos"
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 817e2ca72ec..8f96c462240 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -915,32 +915,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     }
                 };
 
-                let args: Vec<_> = args
-                    .iter()
-                    .enumerate()
-                    .map(|(i, arg)| {
-                        // The indices passed to simd_shuffle in the
-                        // third argument must be constant. This is
-                        // checked by the type-checker.
-                        if i == 2 && intrinsic.name == sym::simd_shuffle {
-                            // FIXME: the simd_shuffle argument is actually an array,
-                            // not a vector, so we need this special hack to make sure
-                            // it is passed as an immediate. We should pass the
-                            // shuffle indices as a vector instead to avoid this hack.
-                            if let mir::Operand::Constant(constant) = &arg.node {
-                                let (llval, ty) = self.immediate_const_vector(bx, constant);
-                                return OperandRef {
-                                    val: Immediate(llval),
-                                    layout: bx.layout_of(ty),
-                                };
-                            } else {
-                                span_bug!(span, "shuffle indices must be constant");
-                            }
-                        }
-
-                        self.codegen_operand(bx, &arg.node)
-                    })
-                    .collect();
+                let args: Vec<_> =
+                    args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect();
 
                 if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) {
                     let location = self
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 0aa85b82038..8254fb3d866 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -1,6 +1,6 @@
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::HasTyCtxt;
-use rustc_middle::ty::{self, Ty, ValTree};
+use rustc_middle::ty::{self, Ty};
 use rustc_middle::{bug, mir, span_bug};
 use rustc_target::abi::Abi;
 
@@ -66,15 +66,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         constant: &mir::ConstOperand<'tcx>,
     ) -> (Bx::Value, Ty<'tcx>) {
         let ty = self.monomorphize(constant.ty());
-        let ty_is_simd = ty.is_simd();
-        // FIXME: ideally we'd assert that this is a SIMD type, but simd_shuffle
-        // in its current form relies on a regular array being passed as an
-        // immediate argument. This hack can be removed once that is fixed.
-        let field_ty = if ty_is_simd {
-            ty.simd_size_and_type(bx.tcx()).1
-        } else {
-            ty.builtin_index().unwrap()
-        };
+        assert!(ty.is_simd());
+        let field_ty = ty.simd_size_and_type(bx.tcx()).1;
 
         let val = self
             .eval_unevaluated_mir_constant_to_valtree(constant)
@@ -82,19 +75,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             .map(|x| x.ok())
             .flatten()
             .map(|val| {
-                // Depending on whether this is a SIMD type with an array field
-                // or a type with many fields (one for each elements), the valtree
-                // is either a single branch with N children, or a root node
-                // with exactly one child which then in turn has many children.
-                // So we look at the first child to determine whether it is a
-                // leaf or whether we have to go one more layer down.
-                let branch_or_leaf = val.unwrap_branch();
-                let first = branch_or_leaf.get(0).unwrap();
-                let field_iter = match first {
-                    ValTree::Branch(_) => first.unwrap_branch().iter(),
-                    ValTree::Leaf(_) => branch_or_leaf.iter(),
-                };
-                let values: Vec<_> = field_iter
+                // A SIMD type has a single field, which is an array.
+                let fields = val.unwrap_branch();
+                assert_eq!(fields.len(), 1);
+                let array = fields[0].unwrap_branch();
+                // Iterate over the array elements to obtain the values in the vector.
+                let values: Vec<_> = array
+                    .iter()
                     .map(|field| {
                         if let Some(prim) = field.try_to_scalar() {
                             let layout = bx.layout_of(field_ty);
@@ -107,7 +94,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
                     })
                     .collect();
-                if ty_is_simd { bx.const_vector(&values) } else { bx.const_struct(&values, false) }
+                bx.const_vector(&values)
             })
             .unwrap_or_else(|| {
                 bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 8a6dfb89249..2dc9d57e3b5 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -134,9 +134,6 @@ const_eval_incompatible_return_types =
 const_eval_incompatible_types =
     calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
 
-const_eval_interior_mutability_borrow =
-    cannot borrow here, since the borrowed element may contain interior mutability
-
 const_eval_interior_mutable_data_refer =
     {const_eval_const_context}s cannot refer to interior mutable data
     .label = this borrow of an interior mutable value may end up in the final value
@@ -230,9 +227,6 @@ const_eval_memory_exhausted =
 const_eval_modified_global =
     modifying a static's initial value from another static's initializer
 
-const_eval_mut_deref =
-    mutation through a reference is not allowed in {const_eval_const_context}s
-
 const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
 
 const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
@@ -363,10 +357,6 @@ const_eval_too_generic =
 const_eval_too_many_caller_args =
     calling a function with more arguments than it expected
 
-const_eval_transient_mut_borrow = mutable references are not allowed in {const_eval_const_context}s
-
-const_eval_transient_mut_raw = raw mutable pointers are not allowed in {const_eval_const_context}s
-
 const_eval_try_block_from_output_non_const =
     `try` block cannot convert `{$ty}` to the result in {const_eval_const_context}s
 const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {const_eval_const_context}s
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 8be327a8b56..6d09ed5b4bf 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -11,18 +11,17 @@ use rustc_hir::{self as hir, LangItem};
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::ObligationCause;
-use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::Analysis;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
-use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
 use tracing::{debug, instrument, trace};
 
 use super::ops::{self, NonConstOp, Status};
@@ -166,24 +165,6 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
     }
 }
 
-struct LocalReturnTyVisitor<'ck, 'mir, 'tcx> {
-    kind: LocalKind,
-    checker: &'ck mut Checker<'mir, 'tcx>,
-}
-
-impl<'ck, 'mir, 'tcx> TypeVisitor<TyCtxt<'tcx>> for LocalReturnTyVisitor<'ck, 'mir, 'tcx> {
-    fn visit_ty(&mut self, t: Ty<'tcx>) {
-        match t.kind() {
-            ty::FnPtr(..) => {}
-            ty::Ref(_, _, hir::Mutability::Mut) => {
-                self.checker.check_op(ops::mut_ref::MutRef(self.kind));
-                t.super_visit_with(self)
-            }
-            _ => t.super_visit_with(self),
-        }
-    }
-}
-
 pub struct Checker<'mir, 'tcx> {
     ccx: &'mir ConstCx<'mir, 'tcx>,
     qualifs: Qualifs<'mir, 'tcx>,
@@ -230,25 +211,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             return;
         }
 
-        // The local type and predicate checks are not free and only relevant for `const fn`s.
-        if self.const_kind() == hir::ConstContext::ConstFn {
-            for (idx, local) in body.local_decls.iter_enumerated() {
-                // Handle the return place below.
-                if idx == RETURN_PLACE {
-                    continue;
-                }
-
-                self.span = local.source_info.span;
-                self.check_local_or_return_ty(local.ty, idx);
-            }
-
-            // impl trait is gone in MIR, so check the return type of a const fn by its signature
-            // instead of the type of the return place.
-            self.span = body.local_decls[RETURN_PLACE].source_info.span;
-            let return_ty = self.ccx.fn_sig().output();
-            self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
-        }
-
         if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
             self.visit_body(body);
         }
@@ -358,16 +320,11 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         self.check_op_spanned(ops::StaticAccess, span)
     }
 
-    fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
-        let kind = self.body.local_kind(local);
-
-        let mut visitor = LocalReturnTyVisitor { kind, checker: self };
-
-        visitor.visit_ty(ty);
-    }
-
-    fn check_mut_borrow(&mut self, place: &Place<'_>, kind: hir::BorrowKind) {
-        match self.const_kind() {
+    /// Returns whether this place can possibly escape the evaluation of the current const/static
+    /// initializer. The check assumes that all already existing pointers and references point to
+    /// non-escaping places.
+    fn place_may_escape(&mut self, place: &Place<'_>) -> bool {
+        let is_transient = match self.const_kind() {
             // In a const fn all borrows are transient or point to the places given via
             // references in the arguments (so we already checked them with
             // TransientMutBorrow/MutBorrow as appropriate).
@@ -375,7 +332,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             // NOTE: Once we have heap allocations during CTFE we need to figure out
             // how to prevent `const fn` to create long-lived allocations that point
             // to mutable memory.
-            hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)),
+            hir::ConstContext::ConstFn => true,
             _ => {
                 // For indirect places, we are not creating a new permanent borrow, it's just as
                 // transient as the already existing one. For reborrowing references this is handled
@@ -387,15 +344,16 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                 // value of the constant.
                 // Note: This is only sound if every local that has a `StorageDead` has a
                 // `StorageDead` in every control flow path leading to a `return` terminator.
-                // The good news is that interning will detect if any unexpected mutable
-                // pointer slips through.
-                if place.is_indirect() || self.local_is_transient(place.local) {
-                    self.check_op(ops::TransientMutBorrow(kind));
-                } else {
-                    self.check_op(ops::MutBorrow(kind));
-                }
+                // If anything slips through, there's no safety net -- safe code can create
+                // references to variants of `!Freeze` enums as long as that variant is `Freeze`, so
+                // interning can't protect us here. (There *is* a safety net for mutable references
+                // though, interning will ICE if we miss something here.)
+                place.is_indirect() || self.local_is_transient(place.local)
             }
-        }
+        };
+        // Transient places cannot possibly escape because the place doesn't exist any more at the
+        // end of evaluation.
+        !is_transient
     }
 }
 
@@ -420,47 +378,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
         trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
 
-        // Special-case reborrows to be more like a copy of a reference.
-        // FIXME: this does not actually handle all reborrows. It only detects cases where `*` is the outermost
-        // projection of the borrowed place, it skips deref'ing raw pointers and it skips `static`.
-        // All those cases are handled below with shared/mutable borrows.
-        // Once `const_mut_refs` is stable, we should be able to entirely remove this special case.
-        // (`const_refs_to_cell` is not needed, we already allow all borrows of indirect places anyway.)
-        match *rvalue {
-            Rvalue::Ref(_, kind, place) => {
-                if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
-                    let ctx = match kind {
-                        BorrowKind::Shared => {
-                            PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
-                        }
-                        BorrowKind::Fake(_) => {
-                            PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
-                        }
-                        BorrowKind::Mut { .. } => {
-                            PlaceContext::MutatingUse(MutatingUseContext::Borrow)
-                        }
-                    };
-                    self.visit_local(reborrowed_place_ref.local, ctx, location);
-                    self.visit_projection(reborrowed_place_ref, ctx, location);
-                    return;
-                }
-            }
-            Rvalue::RawPtr(mutbl, place) => {
-                if let Some(reborrowed_place_ref) = place_as_reborrow(self.tcx, self.body, place) {
-                    let ctx = match mutbl {
-                        Mutability::Not => {
-                            PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow)
-                        }
-                        Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::RawBorrow),
-                    };
-                    self.visit_local(reborrowed_place_ref.local, ctx, location);
-                    self.visit_projection(reborrowed_place_ref, ctx, location);
-                    return;
-                }
-            }
-            _ => {}
-        }
-
         self.super_rvalue(rvalue, location);
 
         match rvalue {
@@ -494,15 +411,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 let is_allowed =
                     self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut);
 
-                if !is_allowed {
-                    self.check_mut_borrow(
-                        place,
-                        if matches!(rvalue, Rvalue::Ref(..)) {
-                            hir::BorrowKind::Ref
-                        } else {
-                            hir::BorrowKind::Raw
-                        },
-                    );
+                if !is_allowed && self.place_may_escape(place) {
+                    self.check_op(ops::EscapingMutBorrow(if matches!(rvalue, Rvalue::Ref(..)) {
+                        hir::BorrowKind::Ref
+                    } else {
+                        hir::BorrowKind::Raw
+                    }));
                 }
             }
 
@@ -514,39 +428,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     place.as_ref(),
                 );
 
-                // If the place is indirect, this is basically a reborrow. We have a reborrow
-                // special case above, but for raw pointers and pointers/references to `static` and
-                // when the `*` is not the first projection, `place_as_reborrow` does not recognize
-                // them as such, so we end up here. This should probably be considered a
-                // `TransientCellBorrow` (we consider the equivalent mutable case a
-                // `TransientMutBorrow`), but such reborrows got accidentally stabilized already and
-                // it is too much of a breaking change to take back.
-                if borrowed_place_has_mut_interior && !place.is_indirect() {
-                    match self.const_kind() {
-                        // In a const fn all borrows are transient or point to the places given via
-                        // references in the arguments (so we already checked them with
-                        // TransientCellBorrow/CellBorrow as appropriate).
-                        // The borrow checker guarantees that no new non-transient borrows are created.
-                        // NOTE: Once we have heap allocations during CTFE we need to figure out
-                        // how to prevent `const fn` to create long-lived allocations that point
-                        // to (interior) mutable memory.
-                        hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow),
-                        _ => {
-                            // Locals with StorageDead are definitely not part of the final constant value, and
-                            // it is thus inherently safe to permit such locals to have their
-                            // address taken as we can't end up with a reference to them in the
-                            // final value.
-                            // Note: This is only sound if every local that has a `StorageDead` has a
-                            // `StorageDead` in every control flow path leading to a `return` terminator.
-                            // The good news is that interning will detect if any unexpected mutable
-                            // pointer slips through.
-                            if self.local_is_transient(place.local) {
-                                self.check_op(ops::TransientCellBorrow);
-                            } else {
-                                self.check_op(ops::CellBorrow);
-                            }
-                        }
-                    }
+                if borrowed_place_has_mut_interior && self.place_may_escape(place) {
+                    self.check_op(ops::EscapingCellBorrow);
                 }
             }
 
@@ -635,58 +518,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             }
         }
     }
-    fn visit_projection_elem(
-        &mut self,
-        place_ref: PlaceRef<'tcx>,
-        elem: PlaceElem<'tcx>,
-        context: PlaceContext,
-        location: Location,
-    ) {
-        trace!(
-            "visit_projection_elem: place_ref={:?} elem={:?} \
-            context={:?} location={:?}",
-            place_ref, elem, context, location,
-        );
-
-        self.super_projection_elem(place_ref, elem, context, location);
-
-        match elem {
-            ProjectionElem::Deref => {
-                let base_ty = place_ref.ty(self.body, self.tcx).ty;
-                if base_ty.is_unsafe_ptr() {
-                    if place_ref.projection.is_empty() {
-                        let decl = &self.body.local_decls[place_ref.local];
-                        // If this is a static, then this is not really dereferencing a pointer,
-                        // just directly accessing a static. That is not subject to any feature
-                        // gates (except for the one about whether statics can even be used, but
-                        // that is checked already by `visit_operand`).
-                        if let LocalInfo::StaticRef { .. } = *decl.local_info() {
-                            return;
-                        }
-                    }
-
-                    // `*const T` is stable, `*mut T` is not
-                    if !base_ty.is_mutable_ptr() {
-                        return;
-                    }
-
-                    self.check_op(ops::RawMutPtrDeref);
-                }
-
-                if context.is_mutating_use() {
-                    self.check_op(ops::MutDeref);
-                }
-            }
-
-            ProjectionElem::ConstantIndex { .. }
-            | ProjectionElem::Downcast(..)
-            | ProjectionElem::OpaqueCast(..)
-            | ProjectionElem::Subslice { .. }
-            | ProjectionElem::Subtype(..)
-            | ProjectionElem::Field(..)
-            | ProjectionElem::Index(_) => {}
-        }
-    }
 
     fn visit_source_info(&mut self, source_info: &SourceInfo) {
         trace!("visit_source_info: source_info={:?}", source_info);
@@ -983,40 +814,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
     }
 }
 
-fn place_as_reborrow<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    place: Place<'tcx>,
-) -> Option<PlaceRef<'tcx>> {
-    match place.as_ref().last_projection() {
-        Some((place_base, ProjectionElem::Deref)) => {
-            // FIXME: why do statics and raw pointers get excluded here? This makes
-            // some code involving mutable pointers unstable, but it is unclear
-            // why that code is treated differently from mutable references.
-            // Once TransientMutBorrow and TransientCellBorrow are stable,
-            // this can probably be cleaned up without any behavioral changes.
-
-            // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
-            // that points to the allocation for the static. Don't treat these as reborrows.
-            if body.local_decls[place_base.local].is_ref_to_static() {
-                None
-            } else {
-                // Ensure the type being derefed is a reference and not a raw pointer.
-                // This is sufficient to prevent an access to a `static mut` from being marked as a
-                // reborrow, even if the check above were to disappear.
-                let inner_ty = place_base.ty(body, tcx).ty;
-
-                if let ty::Ref(..) = inner_ty.kind() {
-                    return Some(place_base);
-                } else {
-                    return None;
-                }
-            }
-        }
-        _ => None,
-    }
-}
-
 fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool {
     ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point()
 }
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index e8f10c88408..a52fc6a077b 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -8,7 +8,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
-use rustc_middle::mir::{self, CallSource};
+use rustc_middle::mir::CallSource;
 use rustc_middle::span_bug;
 use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _};
 use rustc_middle::ty::{
@@ -392,26 +392,11 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
 }
 
 #[derive(Debug)]
-/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
-/// the final value of the constant.
-pub(crate) struct TransientCellBorrow;
-impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
-    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
-        Status::Unstable(sym::const_refs_to_cell)
-    }
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
-        ccx.tcx
-            .sess
-            .create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell)
-    }
-}
-
-#[derive(Debug)]
 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
 /// the final value of the constant, and thus we cannot allow this (for now). We may allow
 /// it in the future for static items.
-pub(crate) struct CellBorrow;
-impl<'tcx> NonConstOp<'tcx> for CellBorrow {
+pub(crate) struct EscapingCellBorrow;
+impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow {
     fn importance(&self) -> DiagImportance {
         // Most likely the code will try to do mutation with these borrows, which
         // triggers its own errors. Only show this one if that does not happen.
@@ -431,9 +416,9 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow {
 /// This op is for `&mut` borrows in the trailing expression of a constant
 /// which uses the "enclosing scopes rule" to leak its locals into anonymous
 /// static or const items.
-pub(crate) struct MutBorrow(pub hir::BorrowKind);
+pub(crate) struct EscapingMutBorrow(pub hir::BorrowKind);
 
-impl<'tcx> NonConstOp<'tcx> for MutBorrow {
+impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
     fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Forbidden
     }
@@ -460,49 +445,6 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
     }
 }
 
-#[derive(Debug)]
-pub(crate) struct TransientMutBorrow(pub hir::BorrowKind);
-
-impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
-    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
-        Status::Unstable(sym::const_mut_refs)
-    }
-
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
-        let kind = ccx.const_kind();
-        match self.0 {
-            hir::BorrowKind::Raw => ccx
-                .tcx
-                .sess
-                .create_feature_err(errors::TransientMutRawErr { span, kind }, sym::const_mut_refs),
-            hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err(
-                errors::TransientMutBorrowErr { span, kind },
-                sym::const_mut_refs,
-            ),
-        }
-    }
-}
-
-#[derive(Debug)]
-pub(crate) struct MutDeref;
-impl<'tcx> NonConstOp<'tcx> for MutDeref {
-    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
-        Status::Unstable(sym::const_mut_refs)
-    }
-
-    fn importance(&self) -> DiagImportance {
-        // Usually a side-effect of a `TransientMutBorrow` somewhere.
-        DiagImportance::Secondary
-    }
-
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
-        ccx.tcx.sess.create_feature_err(
-            errors::MutDerefErr { span, kind: ccx.const_kind() },
-            sym::const_mut_refs,
-        )
-    }
-}
-
 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
 #[derive(Debug)]
 pub(crate) struct PanicNonStr;
@@ -524,24 +466,6 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
     }
 }
 
-#[derive(Debug)]
-pub(crate) struct RawMutPtrDeref;
-impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
-        Status::Unstable(sym::const_mut_refs)
-    }
-
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
-        feature_err(
-            &ccx.tcx.sess,
-            sym::const_mut_refs,
-            span,
-            format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
-        )
-    }
-}
-
 /// Casting raw pointer or function pointer to an integer.
 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
 /// allocation base addresses that are not known at compile-time.
@@ -588,33 +512,3 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
         ccx.dcx().create_err(errors::ThreadLocalAccessErr { span })
     }
 }
-
-/// Types that cannot appear in the signature or locals of a `const fn`.
-pub(crate) mod mut_ref {
-    use super::*;
-
-    #[derive(Debug)]
-    pub(crate) struct MutRef(pub mir::LocalKind);
-    impl<'tcx> NonConstOp<'tcx> for MutRef {
-        fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
-            Status::Unstable(sym::const_mut_refs)
-        }
-
-        fn importance(&self) -> DiagImportance {
-            match self.0 {
-                mir::LocalKind::Temp => DiagImportance::Secondary,
-                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => DiagImportance::Primary,
-            }
-        }
-
-        #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
-        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
-            feature_err(
-                &ccx.tcx.sess,
-                sym::const_mut_refs,
-                span,
-                format!("mutable references are not allowed in {}s", ccx.const_kind()),
-            )
-        }
-    }
-}
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index da4173f9032..337eab7a1c2 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -10,7 +10,6 @@ use rustc_middle::traits::Reveal;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{self, Abi};
@@ -18,13 +17,12 @@ use tracing::{debug, instrument, trace};
 
 use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine};
 use crate::const_eval::CheckAlignment;
-use crate::errors::{self, ConstEvalError, DanglingPtrInFinal};
 use crate::interpret::{
     create_static_alloc, eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust,
     CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError,
     InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup,
 };
-use crate::CTRL_C_RECEIVED;
+use crate::{errors, CTRL_C_RECEIVED};
 
 // Returns a pointer to where the result lives
 #[instrument(level = "trace", skip(ecx, body))]
@@ -100,18 +98,15 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
             return Err(ecx
                 .tcx
                 .dcx()
-                .emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
+                .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
                 .into());
         }
         Err(InternResult::FoundBadMutablePointer) => {
-            // only report mutable pointers if there were no dangling pointers
-            let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind };
-            ecx.tcx.emit_node_span_lint(
-                lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
-                ecx.machine.best_lint_scope(*ecx.tcx),
-                err_diag.span,
-                err_diag,
-            )
+            return Err(ecx
+                .tcx
+                .dcx()
+                .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind })
+                .into());
         }
     }
 
@@ -443,7 +438,12 @@ fn report_eval_error<'tcx>(
         error,
         DUMMY_SP,
         || super::get_span_and_frames(ecx.tcx, ecx.stack()),
-        |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames },
+        |span, frames| errors::ConstEvalError {
+            span,
+            error_kind: kind,
+            instance,
+            frame_notes: frames,
+        },
     )
 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 7405ca09342..6a691abae02 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -718,16 +718,29 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
         _kind: mir::RetagKind,
         val: &ImmTy<'tcx, CtfeProvenance>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, CtfeProvenance>> {
-        // If it's a frozen shared reference that's not already immutable, make it immutable.
+        // If it's a frozen shared reference that's not already immutable, potentially make it immutable.
         // (Do nothing on `None` provenance, that cannot store immutability anyway.)
         if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind()
             && *mutbl == Mutability::Not
-            && val.to_scalar_and_meta().0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable())
-            // That next check is expensive, that's why we have all the guards above.
-            && ty.is_freeze(*ecx.tcx, ecx.param_env)
+            && val
+                .to_scalar_and_meta()
+                .0
+                .to_pointer(ecx)?
+                .provenance
+                .is_some_and(|p| !p.immutable())
         {
+            // That next check is expensive, that's why we have all the guards above.
+            let is_immutable = ty.is_freeze(*ecx.tcx, ecx.param_env);
             let place = ecx.ref_to_mplace(val)?;
-            let new_place = place.map_provenance(CtfeProvenance::as_immutable);
+            let new_place = if is_immutable {
+                place.map_provenance(CtfeProvenance::as_immutable)
+            } else {
+                // Even if it is not immutable, remember that it is a shared reference.
+                // This allows it to become part of the final value of the constant.
+                // (See <https://github.com/rust-lang/rust/pull/128543> for why we allow this
+                // even when there is interior mutability.)
+                place.map_provenance(CtfeProvenance::as_shared_ref)
+            };
             Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout))
         } else {
             Ok(val.clone())
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 0b366b43f95..b66b5c0a00a 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -35,13 +35,10 @@ pub(crate) struct NestedStaticInThreadLocal {
     pub span: Span,
 }
 
-#[derive(LintDiagnostic)]
+#[derive(Diagnostic)]
 #[diag(const_eval_mutable_ptr_in_final)]
 pub(crate) struct MutablePtrInFinal {
-    // rust-lang/rust#122153: This was marked as `#[primary_span]` under
-    // `derive(Diagnostic)`. Since we expect we may hard-error in future, we are
-    // keeping the field (and skipping it under `derive(LintDiagnostic)`).
-    #[skip_arg]
+    #[primary_span]
     pub span: Span,
     pub kind: InternKind,
 }
@@ -97,30 +94,6 @@ pub(crate) struct PanicNonStrErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(const_eval_mut_deref, code = E0658)]
-pub(crate) struct MutDerefErr {
-    #[primary_span]
-    pub span: Span,
-    pub kind: ConstContext,
-}
-
-#[derive(Diagnostic)]
-#[diag(const_eval_transient_mut_borrow, code = E0658)]
-pub(crate) struct TransientMutBorrowErr {
-    #[primary_span]
-    pub span: Span,
-    pub kind: ConstContext,
-}
-
-#[derive(Diagnostic)]
-#[diag(const_eval_transient_mut_raw, code = E0658)]
-pub(crate) struct TransientMutRawErr {
-    #[primary_span]
-    pub span: Span,
-    pub kind: ConstContext,
-}
-
-#[derive(Diagnostic)]
 #[diag(const_eval_max_num_nodes_in_const)]
 pub(crate) struct MaxNumNodesInConstErr {
     #[primary_span]
@@ -220,13 +193,6 @@ pub(crate) struct InteriorMutableDataRefer {
     pub teach: bool,
 }
 
-#[derive(Diagnostic)]
-#[diag(const_eval_interior_mutability_borrow)]
-pub(crate) struct InteriorMutabilityBorrow {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(LintDiagnostic)]
 #[diag(const_eval_long_running)]
 #[note]
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 8b0a2afa4d6..5df989b4c1d 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -20,6 +20,7 @@ use rustc_hir as hir;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
 use rustc_middle::query::TyCtxtAt;
+use rustc_middle::span_bug;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::sym;
@@ -223,37 +224,52 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
             continue;
         }
 
-        // Crucially, we check this *before* checking whether the `alloc_id`
-        // has already been interned. The point of this check is to ensure that when
-        // there are multiple pointers to the same allocation, they are *all* immutable.
-        // Therefore it would be bad if we only checked the first pointer to any given
-        // allocation.
+        // Ensure that this is derived from a shared reference. Crucially, we check this *before*
+        // checking whether the `alloc_id` has already been interned. The point of this check is to
+        // ensure that when there are multiple pointers to the same allocation, they are *all*
+        // derived from a shared reference. Therefore it would be bad if we only checked the first
+        // pointer to any given allocation.
         // (It is likely not possible to actually have multiple pointers to the same allocation,
         // so alternatively we could also check that and ICE if there are multiple such pointers.)
+        // See <https://github.com/rust-lang/rust/pull/128543> for why we are checking for "shared
+        // reference" and not "immutable", i.e., for why we are allowing interior-mutable shared
+        // references: they can actually be created in safe code while pointing to apparently
+        // "immutable" values, via promotion or tail expression lifetime extension of
+        // `&None::<Cell<T>>`.
+        // We also exclude promoteds from this as `&mut []` can be promoted, which is a mutable
+        // reference pointing to an immutable (zero-sized) allocation. We rely on the promotion
+        // analysis not screwing up to ensure that it is sound to intern promoteds as immutable.
         if intern_kind != InternKind::Promoted
             && inner_mutability == Mutability::Not
-            && !prov.immutable()
+            && !prov.shared_ref()
         {
-            if ecx.tcx.try_get_global_alloc(alloc_id).is_some()
-                && !just_interned.contains(&alloc_id)
-            {
+            let is_already_global = ecx.tcx.try_get_global_alloc(alloc_id).is_some();
+            if is_already_global && !just_interned.contains(&alloc_id) {
                 // This is a pointer to some memory from another constant. We encounter mutable
                 // pointers to such memory since we do not always track immutability through
                 // these "global" pointers. Allowing them is harmless; the point of these checks
                 // during interning is to justify why we intern the *new* allocations immutably,
-                // so we can completely ignore existing allocations. We also don't need to add
-                // this to the todo list, since after all it is already interned.
+                // so we can completely ignore existing allocations.
+                // We can also skip the rest of this loop iteration, since after all it is already
+                // interned.
                 continue;
             }
-            // Found a mutable pointer inside a const where inner allocations should be
-            // immutable. We exclude promoteds from this, since things like `&mut []` and
-            // `&None::<Cell<i32>>` lead to promotion that can produce mutable pointers. We rely
-            // on the promotion analysis not screwing up to ensure that it is sound to intern
-            // promoteds as immutable.
-            trace!("found bad mutable pointer");
-            // Prefer dangling pointer errors over mutable pointer errors
-            if result.is_ok() {
-                result = Err(InternResult::FoundBadMutablePointer);
+            // If this is a dangling pointer, that's actually fine -- the problematic case is
+            // when there is memory there that someone might expect to be mutable, but we make it immutable.
+            let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id);
+            if !dangling {
+                // Found a mutable reference inside a const where inner allocations should be
+                // immutable.
+                if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
+                    span_bug!(
+                        ecx.tcx.span,
+                        "the static const safety checks accepted mutable references they should not have accepted"
+                    );
+                }
+                // Prefer dangling pointer errors over mutable pointer errors
+                if result.is_ok() {
+                    result = Err(InternResult::FoundBadMutablePointer);
+                }
             }
         }
         if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
@@ -261,7 +277,6 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
             debug_assert!(!ecx.memory.alloc_map.contains_key(&alloc_id));
             continue;
         }
-        just_interned.insert(alloc_id);
         // We always intern with `inner_mutability`, and furthermore we ensured above that if
         // that is "immutable", then there are *no* mutable pointers anywhere in the newly
         // interned memory -- justifying that we can indeed intern immutably. However this also
@@ -272,6 +287,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
         // pointers before deciding which allocations can be made immutable; but for now we are
         // okay with losing some potential for immutability here. This can anyway only affect
         // `static mut`.
+        just_interned.insert(alloc_id);
         match intern_shallow(ecx, alloc_id, inner_mutability) {
             Ok(nested) => todo.extend(nested),
             Err(()) => {
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 8cab3c34eed..67c99934059 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -540,10 +540,29 @@ pub trait Machine<'tcx>: Sized {
         Ok(ReturnAction::Normal)
     }
 
+    /// Called immediately after an "immediate" local variable is read
+    /// (i.e., this is called for reads that do not end up accessing addressable memory).
+    #[inline(always)]
+    fn after_local_read(_ecx: &InterpCx<'tcx, Self>, _local: mir::Local) -> InterpResult<'tcx> {
+        Ok(())
+    }
+
+    /// Called immediately after an "immediate" local variable is assigned a new value
+    /// (i.e., this is called for writes that do not end up in memory).
+    /// `storage_live` indicates whether this is the initial write upon `StorageLive`.
+    #[inline(always)]
+    fn after_local_write(
+        _ecx: &mut InterpCx<'tcx, Self>,
+        _local: mir::Local,
+        _storage_live: bool,
+    ) -> InterpResult<'tcx> {
+        Ok(())
+    }
+
     /// Called immediately after actual memory was allocated for a local
     /// but before the local's stack frame is updated to point to that memory.
     #[inline(always)]
-    fn after_local_allocated(
+    fn after_local_moved_to_memory(
         _ecx: &mut InterpCx<'tcx, Self>,
         _local: mir::Local,
         _mplace: &MPlaceTy<'tcx, Self::Provenance>,
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 7b0b28a470d..b1d1dab7c16 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -7,7 +7,7 @@
 //! short-circuiting the empty case!
 
 use std::assert_matches::assert_matches;
-use std::borrow::Cow;
+use std::borrow::{Borrow, Cow};
 use std::collections::VecDeque;
 use std::{fmt, mem, ptr};
 
@@ -387,12 +387,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         size: Size,
     ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> {
         let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
-        self.check_and_deref_ptr(
+        Self::check_and_deref_ptr(
+            self,
             ptr,
             size,
             CheckInAllocMsg::MemoryAccessTest,
-            |alloc_id, offset, prov| {
-                let (size, align) = self
+            |this, alloc_id, offset, prov| {
+                let (size, align) = this
                     .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
                 Ok((size, align, (alloc_id, offset, prov)))
             },
@@ -409,8 +410,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         msg: CheckInAllocMsg,
     ) -> InterpResult<'tcx> {
         let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
-        self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| {
-            let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
+        Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| {
+            let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?;
             Ok((size, align, ()))
         })?;
         Ok(())
@@ -425,8 +426,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         size: i64,
         msg: CheckInAllocMsg,
     ) -> InterpResult<'tcx> {
-        self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| {
-            let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
+        Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| {
+            let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?;
             Ok((size, align, ()))
         })?;
         Ok(())
@@ -440,12 +441,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// `alloc_size` will only get called for non-zero-sized accesses.
     ///
     /// Returns `None` if and only if the size is 0.
-    fn check_and_deref_ptr<T>(
-        &self,
+    fn check_and_deref_ptr<T, R: Borrow<Self>>(
+        this: R,
         ptr: Pointer<Option<M::Provenance>>,
         size: i64,
         msg: CheckInAllocMsg,
         alloc_size: impl FnOnce(
+            R,
             AllocId,
             Size,
             M::ProvenanceExtra,
@@ -456,13 +458,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return Ok(None);
         }
 
-        Ok(match self.ptr_try_get_alloc_id(ptr, size) {
+        Ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) {
             Err(addr) => {
                 // We couldn't get a proper allocation.
                 throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg });
             }
             Ok((alloc_id, offset, prov)) => {
-                let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?;
+                let tcx = this.borrow().tcx;
+                let (alloc_size, _alloc_align, ret_val) = alloc_size(this, alloc_id, offset, prov)?;
                 let offset = offset.bytes();
                 // Compute absolute begin and end of the range.
                 let (begin, end) = if size >= 0 {
@@ -476,7 +479,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     throw_ub!(PointerOutOfBounds {
                         alloc_id,
                         alloc_size,
-                        ptr_offset: self.sign_extend_to_target_isize(offset),
+                        ptr_offset: tcx.sign_extend_to_target_isize(offset),
                         inbounds_size: size,
                         msg,
                     })
@@ -670,12 +673,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
     {
         let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
-        let ptr_and_alloc = self.check_and_deref_ptr(
+        let ptr_and_alloc = Self::check_and_deref_ptr(
+            self,
             ptr,
             size_i64,
             CheckInAllocMsg::MemoryAccessTest,
-            |alloc_id, offset, prov| {
-                let alloc = self.get_alloc_raw(alloc_id)?;
+            |this, alloc_id, offset, prov| {
+                let alloc = this.get_alloc_raw(alloc_id)?;
                 Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
             },
         )?;
@@ -727,7 +731,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // We have "NLL problem case #3" here, which cannot be worked around without loss of
         // efficiency even for the common case where the key is in the map.
         // <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions>
-        // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.)
+        // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`, and that boils down to
+        // Miri's `adjust_alloc_root_pointer` needing to look up the size of the allocation.
+        // It could be avoided with a totally separate codepath in Miri for handling the absolute address
+        // of global allocations, but that's not worth it.)
         if self.memory.alloc_map.get_mut(id).is_none() {
             // Slow path.
             // Allocation not found locally, go look global.
@@ -763,13 +770,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         size: Size,
     ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
     {
-        let parts = self.get_ptr_access(ptr, size)?;
-        if let Some((alloc_id, offset, prov)) = parts {
-            let tcx = self.tcx;
-            let validation_in_progress = self.memory.validation_in_progress;
-            // FIXME: can we somehow avoid looking up the allocation twice here?
-            // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
-            let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
+        let tcx = self.tcx;
+        let validation_in_progress = self.memory.validation_in_progress;
+
+        let size_i64 = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes
+        let ptr_and_alloc = Self::check_and_deref_ptr(
+            self,
+            ptr,
+            size_i64,
+            CheckInAllocMsg::MemoryAccessTest,
+            |this, alloc_id, offset, prov| {
+                let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?;
+                Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine)))
+            },
+        )?;
+
+        if let Some((alloc_id, offset, prov, alloc, machine)) = ptr_and_alloc {
             let range = alloc_range(offset, size);
             if !validation_in_progress {
                 M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
@@ -1031,6 +1047,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         );
         res
     }
+
+    pub(super) fn validation_in_progress(&self) -> bool {
+        self.memory.validation_in_progress
+    }
 }
 
 #[doc(hidden)]
@@ -1115,7 +1135,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> {
 }
 
 /// Reading and writing.
-impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes>
+impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>
     AllocRefMut<'a, 'tcx, Prov, Extra, Bytes>
 {
     pub fn as_ref<'b>(&'b self) -> AllocRef<'b, 'tcx, Prov, Extra, Bytes> {
@@ -1163,7 +1183,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes>
     }
 }
 
-impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> {
+impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> {
     /// `range` is relative to this allocation reference, not the base of the allocation.
     pub fn read_scalar(
         &self,
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 2e02d1001c8..ead3ef6861a 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -697,6 +697,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         if matches!(op, Operand::Immediate(_)) {
             assert!(!layout.is_unsized());
         }
+        M::after_local_read(self, local)?;
         Ok(OpTy { op, layout })
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 9dd9ca80385..e398c4c0742 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -500,15 +500,13 @@ where
         &self,
         local: mir::Local,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
-        // Other parts of the system rely on `Place::Local` never being unsized.
-        // So we eagerly check here if this local has an MPlace, and if yes we use it.
         let frame = self.frame();
         let layout = self.layout_of_local(frame, local, None)?;
         let place = if layout.is_sized() {
             // We can just always use the `Local` for sized values.
             Place::Local { local, offset: None, locals_addr: frame.locals_addr() }
         } else {
-            // Unsized `Local` isn't okay (we cannot store the metadata).
+            // Other parts of the system rely on `Place::Local` never being unsized.
             match frame.locals[local].access()? {
                 Operand::Immediate(_) => bug!(),
                 Operand::Indirect(mplace) => Place::Ptr(*mplace),
@@ -562,7 +560,10 @@ where
         place: &PlaceTy<'tcx, M::Provenance>,
     ) -> InterpResult<
         'tcx,
-        Either<MPlaceTy<'tcx, M::Provenance>, (&mut Immediate<M::Provenance>, TyAndLayout<'tcx>)>,
+        Either<
+            MPlaceTy<'tcx, M::Provenance>,
+            (&mut Immediate<M::Provenance>, TyAndLayout<'tcx>, mir::Local),
+        >,
     > {
         Ok(match place.to_place().as_mplace_or_local() {
             Left(mplace) => Left(mplace),
@@ -581,7 +582,7 @@ where
                         }
                         Operand::Immediate(local_val) => {
                             // The local still has the optimized representation.
-                            Right((local_val, layout))
+                            Right((local_val, layout, local))
                         }
                     }
                 }
@@ -643,9 +644,13 @@ where
         assert!(dest.layout().is_sized(), "Cannot write unsized immediate data");
 
         match self.as_mplace_or_mutable_local(&dest.to_place())? {
-            Right((local_val, local_layout)) => {
+            Right((local_val, local_layout, local)) => {
                 // Local can be updated in-place.
                 *local_val = src;
+                // Call the machine hook (the data race detector needs to know about this write).
+                if !self.validation_in_progress() {
+                    M::after_local_write(self, local, /*storage_live*/ false)?;
+                }
                 // Double-check that the value we are storing and the local fit to each other.
                 if cfg!(debug_assertions) {
                     src.assert_matches_abi(local_layout.abi, self);
@@ -714,8 +719,12 @@ where
         dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         match self.as_mplace_or_mutable_local(&dest.to_place())? {
-            Right((local_val, _local_layout)) => {
+            Right((local_val, _local_layout, local)) => {
                 *local_val = Immediate::Uninit;
+                // Call the machine hook (the data race detector needs to know about this write).
+                if !self.validation_in_progress() {
+                    M::after_local_write(self, local, /*storage_live*/ false)?;
+                }
             }
             Left(mplace) => {
                 let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else {
@@ -734,8 +743,12 @@ where
         dest: &impl Writeable<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx> {
         match self.as_mplace_or_mutable_local(&dest.to_place())? {
-            Right((local_val, _local_layout)) => {
+            Right((local_val, _local_layout, local)) => {
                 local_val.clear_provenance()?;
+                // Call the machine hook (the data race detector needs to know about this write).
+                if !self.validation_in_progress() {
+                    M::after_local_write(self, local, /*storage_live*/ false)?;
+                }
             }
             Left(mplace) => {
                 let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else {
@@ -941,7 +954,7 @@ where
                                 mplace.mplace,
                             )?;
                         }
-                        M::after_local_allocated(self, local, &mplace)?;
+                        M::after_local_moved_to_memory(self, local, &mplace)?;
                         // Now we can call `access_mut` again, asserting it goes well, and actually
                         // overwrite things. This points to the entire allocation, not just the part
                         // the place refers to, i.e. we do this before we apply `offset`.
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 4e8b66907be..58ce44e4014 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -101,7 +101,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
 }
 
 /// A type representing iteration over the elements of an array.
-pub struct ArrayIterator<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> {
+pub struct ArrayIterator<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> {
     base: &'a P,
     range: Range<u64>,
     stride: Size,
@@ -109,7 +109,7 @@ pub struct ArrayIterator<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>>
     _phantom: PhantomData<Prov>, // otherwise it says `Prov` is never used...
 }
 
-impl<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'tcx, 'a, Prov, P> {
+impl<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'a, 'tcx, Prov, P> {
     /// Should be the same `ecx` on each call, and match the one used to create the iterator.
     pub fn next<M: Machine<'tcx, Provenance = Prov>>(
         &mut self,
@@ -290,7 +290,7 @@ where
     pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>(
         &self,
         base: &'a P,
-    ) -> InterpResult<'tcx, ArrayIterator<'tcx, 'a, M::Provenance, P>> {
+    ) -> InterpResult<'tcx, ArrayIterator<'a, 'tcx, M::Provenance, P>> {
         let abi::FieldsShape::Array { stride, .. } = base.layout().fields else {
             span_bug!(self.cur_span(), "project_array_fields: expected an array layout");
         };
diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs
index b6e83715e39..db418c82f66 100644
--- a/compiler/rustc_const_eval/src/interpret/stack.rs
+++ b/compiler/rustc_const_eval/src/interpret/stack.rs
@@ -534,8 +534,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             let dest_place = self.allocate_dyn(layout, MemoryKind::Stack, meta)?;
             Operand::Indirect(*dest_place.mplace())
         } else {
-            assert!(!meta.has_meta()); // we're dropping the metadata
             // Just make this an efficient immediate.
+            assert!(!meta.has_meta()); // we're dropping the metadata
+            // Make sure the machine knows this "write" is happening. (This is important so that
+            // races involving local variable allocation can be detected by Miri.)
+            M::after_local_write(self, local, /*storage_live*/ true)?;
             // Note that not calling `layout_of` here does have one real consequence:
             // if the type is too big, we'll only notice this when the local is actually initialized,
             // which is a bit too late -- we should ideally notice this already here, when the memory
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index fb24f983ca9..469af35ec1b 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -14,7 +14,6 @@ use hir::def::DefKind;
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_middle::bug;
 use rustc_middle::mir::interpret::ValidationErrorKind::{self, *};
 use rustc_middle::mir::interpret::{
     alloc_range, ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance,
@@ -22,6 +21,7 @@ use rustc_middle::mir::interpret::{
 };
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::{
     Abi, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
@@ -617,6 +617,13 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
                         if ptr_expected_mutbl == Mutability::Mut
                             && alloc_actual_mutbl == Mutability::Not
                         {
+                            if !self.ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you
+                            {
+                                span_bug!(
+                                    self.ecx.tcx.span,
+                                    "the static const safety checks accepted mutable references they should not have accepted"
+                                );
+                            }
                             throw_validation_failure!(self.path, MutableRefToImmutable);
                         }
                         // In a const, everything must be completely immutable.
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 1b7ca61cee8..9d4061d16a1 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -207,17 +207,17 @@ pub fn diagnostics_registry() -> Registry {
 }
 
 /// This is the primary entry point for rustc.
-pub struct RunCompiler<'a, 'b> {
+pub struct RunCompiler<'a> {
     at_args: &'a [String],
-    callbacks: &'b mut (dyn Callbacks + Send),
+    callbacks: &'a mut (dyn Callbacks + Send),
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
     make_codegen_backend:
         Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
     using_internal_features: Arc<std::sync::atomic::AtomicBool>,
 }
 
-impl<'a, 'b> RunCompiler<'a, 'b> {
-    pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
+impl<'a> RunCompiler<'a> {
+    pub fn new(at_args: &'a [String], callbacks: &'a mut (dyn Callbacks + Send)) -> Self {
         Self {
             at_args,
             callbacks,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0764.md b/compiler/rustc_error_codes/src/error_codes/E0764.md
index 152627cf654..4d5091cd954 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0764.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0764.md
@@ -3,8 +3,6 @@ A mutable reference was used in a constant.
 Erroneous code example:
 
 ```compile_fail,E0764
-#![feature(const_mut_refs)]
-
 fn main() {
     const OH_NO: &'static mut usize = &mut 1; // error!
 }
@@ -26,8 +24,6 @@ Remember: you cannot use a function call inside a constant or static. However,
 you can totally use it in constant functions:
 
 ```
-#![feature(const_mut_refs)]
-
 const fn foo(x: usize) -> usize {
     let mut y = 1;
     let z = &mut y;
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 24f631ed5dc..d1dcec0cc15 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -43,9 +43,9 @@ pub struct BangProcMacro {
 }
 
 impl base::BangProcMacro for BangProcMacro {
-    fn expand<'cx>(
+    fn expand(
         &self,
-        ecx: &'cx mut ExtCtxt<'_>,
+        ecx: &mut ExtCtxt<'_>,
         span: Span,
         input: TokenStream,
     ) -> Result<TokenStream, ErrorGuaranteed> {
@@ -73,9 +73,9 @@ pub struct AttrProcMacro {
 }
 
 impl base::AttrProcMacro for AttrProcMacro {
-    fn expand<'cx>(
+    fn expand(
         &self,
-        ecx: &'cx mut ExtCtxt<'_>,
+        ecx: &mut ExtCtxt<'_>,
         span: Span,
         annotation: TokenStream,
         annotated: TokenStream,
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 8949fdffdae..0088a7bbc1e 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -115,6 +115,8 @@ declare_features! (
     (accepted, conservative_impl_trait, "1.26.0", Some(34511)),
     /// Allows calling constructor functions in `const fn`.
     (accepted, const_constructor, "1.40.0", Some(61456)),
+    /// Allows the definition of `const extern fn` and `const unsafe extern fn`.
+    (accepted, const_extern_fn, "CURRENT_RUSTC_VERSION", Some(64926)),
     /// Allows basic arithmetic on floating point types in a `const fn`.
     (accepted, const_fn_floating_point_arithmetic, "1.82.0", Some(57241)),
     /// Allows using and casting function pointers in a `const fn`.
@@ -141,10 +143,14 @@ declare_features! (
     (accepted, const_let, "1.33.0", Some(48821)),
     /// Allows the use of `loop` and `while` in constants.
     (accepted, const_loop, "1.46.0", Some(52000)),
+    /// Allows using `&mut` in constant functions.
+    (accepted, const_mut_refs, "CURRENT_RUSTC_VERSION", Some(57349)),
     /// Allows panicking during const eval (producing compile-time errors).
     (accepted, const_panic, "1.57.0", Some(51999)),
     /// Allows dereferencing raw pointers during const eval.
     (accepted, const_raw_ptr_deref, "1.58.0", Some(51911)),
+    /// Allows references to types with interior mutability within constants
+    (accepted, const_refs_to_cell, "CURRENT_RUSTC_VERSION", Some(80384)),
     /// Allows implementing `Copy` for closures where possible (RFC 2132).
     (accepted, copy_closures, "1.26.0", Some(44490)),
     /// Allows `crate` in paths.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 6ed5ea9f8bb..d0c0460ddfe 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -401,16 +401,10 @@ declare_features! (
     (unstable, const_async_blocks, "1.53.0", Some(85368)),
     /// Allows `const || {}` closures in const contexts.
     (incomplete, const_closures, "1.68.0", Some(106003)),
-    /// Allows the definition of `const extern fn` and `const unsafe extern fn`.
-    (unstable, const_extern_fn, "1.40.0", Some(64926)),
     /// Allows `for _ in _` loops in const contexts.
     (unstable, const_for, "1.56.0", Some(87575)),
-    /// Allows using `&mut` in constant functions.
-    (unstable, const_mut_refs, "1.41.0", Some(57349)),
     /// Be more precise when looking for live drops in a const context.
     (unstable, const_precise_live_drops, "1.46.0", Some(73255)),
-    /// Allows references to types with interior mutability within constants
-    (unstable, const_refs_to_cell, "1.51.0", Some(80384)),
     /// Allows creating pointers and references to `static` items in constants.
     (unstable, const_refs_to_static, "1.78.0", Some(119618)),
     /// Allows `impl const Trait for T` syntax.
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 9863d036449..3dc8759a9ed 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -58,7 +58,7 @@ pub(crate) fn check_legal_trait_for_method_call(
 enum CallStep<'tcx> {
     Builtin(Ty<'tcx>),
     DeferredClosure(LocalDefId, ty::FnSig<'tcx>),
-    /// E.g., enum variant constructors.
+    /// Call overloading when callee implements one of the Fn* traits.
     Overloaded(MethodCallee<'tcx>),
 }
 
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 4d2770d2e50..a692642ccfc 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -711,7 +711,7 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> {
 
 #[derive(Diagnostic)]
 #[diag(hir_typeck_pass_to_variadic_function, code = E0617)]
-pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
+pub(crate) struct PassToVariadicFunction<'a, 'tcx> {
     #[primary_span]
     pub span: Span,
     pub ty: Ty<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 79b02a7f045..7a6ebf15fa9 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -603,12 +603,12 @@ fn compute_unsafe_infer_vars<'a, 'tcx>(
         root_ctxt.tcx.hir().maybe_body_owned_by(body_id).expect("body id must have an owner");
     let mut res = UnordMap::default();
 
-    struct UnsafeInferVarsVisitor<'a, 'tcx, 'r> {
+    struct UnsafeInferVarsVisitor<'a, 'tcx> {
         root_ctxt: &'a TypeckRootCtxt<'tcx>,
-        res: &'r mut UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>,
+        res: &'a mut UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>,
     }
 
-    impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_, '_> {
+    impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_> {
         fn visit_expr(&mut self, ex: &'_ hir::Expr<'_>) {
             let typeck_results = self.root_ctxt.typeck_results.borrow();
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 178dc47aa1f..7318d02d24c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1234,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             infer_args_for_err: &'a FxHashSet<usize>,
             segments: &'tcx [hir::PathSegment<'tcx>],
         }
-        impl<'tcx, 'a> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> {
+        impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> {
             fn args_for_def_id(
                 &mut self,
                 def_id: DefId,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 21b040bd0bc..8348c6e9a16 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -506,6 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 fn_def_id,
                 call_span,
                 call_expr,
+                tuple_arguments,
             );
         }
     }
@@ -520,6 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fn_def_id: Option<DefId>,
         call_span: Span,
         call_expr: &'tcx hir::Expr<'tcx>,
+        tuple_arguments: TupleArgumentsFlag,
     ) -> ErrorGuaranteed {
         // Next, let's construct the error
         let (error_span, call_ident, full_call_span, call_name, is_method) = match &call_expr.kind {
@@ -865,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         &matched_inputs,
                         &formal_and_expected_inputs,
                         is_method,
+                        tuple_arguments,
                     );
                     suggest_confusable(&mut err);
                     return err.emit();
@@ -1001,6 +1004,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 &matched_inputs,
                 &formal_and_expected_inputs,
                 is_method,
+                tuple_arguments,
             );
             suggest_confusable(&mut err);
             return err.emit();
@@ -1448,6 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             &matched_inputs,
             &formal_and_expected_inputs,
             is_method,
+            tuple_arguments,
         );
 
         // And add a suggestion block for all of the parameters
@@ -2219,21 +2224,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
         formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
         is_method: bool,
+        tuple_arguments: TupleArgumentsFlag,
     ) {
         let Some(mut def_id) = callable_def_id else {
             return;
         };
 
+        // If we're calling a method of a Fn/FnMut/FnOnce trait object implicitly
+        // (eg invoking a closure) we want to point at the underlying callable,
+        // not the method implicitly invoked (eg call_once).
         if let Some(assoc_item) = self.tcx.opt_associated_item(def_id)
-            // Possibly points at either impl or trait item, so try to get it
-            // to point to trait item, then get the parent.
-            // This parent might be an impl in the case of an inherent function,
-            // but the next check will fail.
+            // Since this is an associated item, it might point at either an impl or a trait item.
+            // We want it to always point to the trait item.
+            // If we're pointing at an inherent function, we don't need to do anything,
+            // so we fetch the parent and verify if it's a trait item.
             && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id)
             && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id)
             // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
             && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id)
             && let Some(callee_ty) = callee_ty
+            // TupleArguments is set only when this is an implicit call (my_closure(...)) rather than explicit (my_closure.call(...))
+            && tuple_arguments == TupleArguments
         {
             let callee_ty = callee_ty.peel_refs();
             match *callee_ty.kind() {
@@ -2303,166 +2314,173 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             let mut spans: MultiSpan = def_span.into();
 
-            let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
-            let mut generics_with_unmatched_params = Vec::new();
+            if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method)
+            {
+                debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
 
-            let check_for_matched_generics = || {
-                if matched_inputs.iter().any(|x| x.is_some())
-                    && params_with_generics.iter().any(|x| x.0.is_some())
-                {
-                    for (idx, (generic, _)) in params_with_generics.iter().enumerate() {
-                        // Param has to have a generic and be matched to be relevant
-                        if matched_inputs[idx.into()].is_none() {
-                            continue;
-                        }
+                let mut generics_with_unmatched_params = Vec::new();
 
-                        let Some(generic) = generic else {
-                            continue;
-                        };
+                let check_for_matched_generics = || {
+                    if matched_inputs.iter().any(|x| x.is_some())
+                        && params_with_generics.iter().any(|x| x.0.is_some())
+                    {
+                        for (idx, (generic, _)) in params_with_generics.iter().enumerate() {
+                            // Param has to have a generic and be matched to be relevant
+                            if matched_inputs[idx.into()].is_none() {
+                                continue;
+                            }
 
-                        for unmatching_idx in idx + 1..params_with_generics.len() {
-                            if matched_inputs[unmatching_idx.into()].is_none()
-                                && let Some(unmatched_idx_param_generic) =
-                                    params_with_generics[unmatching_idx].0
-                                && unmatched_idx_param_generic.name.ident() == generic.name.ident()
-                            {
-                                // We found a parameter that didn't match that needed to
-                                return true;
+                            let Some(generic) = generic else {
+                                continue;
+                            };
+
+                            for unmatching_idx in idx + 1..params_with_generics.len() {
+                                if matched_inputs[unmatching_idx.into()].is_none()
+                                    && let Some(unmatched_idx_param_generic) =
+                                        params_with_generics[unmatching_idx].0
+                                    && unmatched_idx_param_generic.name.ident()
+                                        == generic.name.ident()
+                                {
+                                    // We found a parameter that didn't match that needed to
+                                    return true;
+                                }
                             }
                         }
                     }
-                }
-                false
-            };
-
-            let check_for_matched_generics = check_for_matched_generics();
-
-            for (idx, (generic_param, param)) in
-                params_with_generics.iter().enumerate().filter(|(idx, _)| {
-                    check_for_matched_generics
-                        || expected_idx.is_none_or(|expected_idx| expected_idx == *idx)
-                })
-            {
-                let Some(generic_param) = generic_param else {
-                    spans.push_span_label(param.span, "");
-                    continue;
+                    false
                 };
 
-                let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics
-                    .iter()
-                    .enumerate()
-                    .filter(|(other_idx, (other_generic_param, _))| {
-                        if *other_idx == idx {
-                            return false;
-                        }
-                        let Some(other_generic_param) = other_generic_param else {
-                            return false;
-                        };
-                        if matched_inputs[idx.into()].is_none()
-                            && matched_inputs[(*other_idx).into()].is_none()
-                        {
-                            return false;
-                        }
-                        if matched_inputs[idx.into()].is_some()
-                            && matched_inputs[(*other_idx).into()].is_some()
-                        {
-                            return false;
-                        }
-                        other_generic_param.name.ident() == generic_param.name.ident()
+                let check_for_matched_generics = check_for_matched_generics();
+
+                for (idx, (generic_param, param)) in
+                    params_with_generics.iter().enumerate().filter(|(idx, _)| {
+                        check_for_matched_generics
+                            || expected_idx.is_none_or(|expected_idx| expected_idx == *idx)
                     })
-                    .map(|(other_idx, (_, other_param))| (other_idx, *other_param))
-                    .collect();
+                {
+                    let Some(generic_param) = generic_param else {
+                        spans.push_span_label(param.span, "");
+                        continue;
+                    };
 
-                if !other_params_matched.is_empty() {
-                    let other_param_matched_names: Vec<String> = other_params_matched
+                    let other_params_matched: Vec<(usize, &hir::Param<'_>)> = params_with_generics
                         .iter()
-                        .map(|(_, other_param)| {
-                            if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind {
-                                format!("`{ident}`")
-                            } else {
-                                "{unknown}".to_string()
+                        .enumerate()
+                        .filter(|(other_idx, (other_generic_param, _))| {
+                            if *other_idx == idx {
+                                return false;
+                            }
+                            let Some(other_generic_param) = other_generic_param else {
+                                return false;
+                            };
+                            if matched_inputs[idx.into()].is_none()
+                                && matched_inputs[(*other_idx).into()].is_none()
+                            {
+                                return false;
                             }
+                            if matched_inputs[idx.into()].is_some()
+                                && matched_inputs[(*other_idx).into()].is_some()
+                            {
+                                return false;
+                            }
+                            other_generic_param.name.ident() == generic_param.name.ident()
                         })
+                        .map(|(other_idx, (_, other_param))| (other_idx, *other_param))
                         .collect();
 
-                    let matched_ty = self
-                        .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
-                        .sort_string(self.tcx);
+                    if !other_params_matched.is_empty() {
+                        let other_param_matched_names: Vec<String> = other_params_matched
+                            .iter()
+                            .map(|(_, other_param)| {
+                                if let hir::PatKind::Binding(_, _, ident, _) = other_param.pat.kind
+                                {
+                                    format!("`{ident}`")
+                                } else {
+                                    "{unknown}".to_string()
+                                }
+                            })
+                            .collect();
 
-                    if matched_inputs[idx.into()].is_some() {
-                        spans.push_span_label(
-                            param.span,
-                            format!(
-                                "{} {} to match the {} type of this parameter",
-                                display_list_with_comma_and(&other_param_matched_names),
+                        let matched_ty = self
+                            .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                            .sort_string(self.tcx);
+
+                        if matched_inputs[idx.into()].is_some() {
+                            spans.push_span_label(
+                                param.span,
                                 format!(
-                                    "need{}",
-                                    pluralize!(if other_param_matched_names.len() == 1 {
-                                        0
-                                    } else {
-                                        1
-                                    })
+                                    "{} {} to match the {} type of this parameter",
+                                    display_list_with_comma_and(&other_param_matched_names),
+                                    format!(
+                                        "need{}",
+                                        pluralize!(if other_param_matched_names.len() == 1 {
+                                            0
+                                        } else {
+                                            1
+                                        })
+                                    ),
+                                    matched_ty,
                                 ),
-                                matched_ty,
-                            ),
-                        );
+                            );
+                        } else {
+                            spans.push_span_label(
+                                param.span,
+                                format!(
+                                    "this parameter needs to match the {} type of {}",
+                                    matched_ty,
+                                    display_list_with_comma_and(&other_param_matched_names),
+                                ),
+                            );
+                        }
+                        generics_with_unmatched_params.push(generic_param);
                     } else {
+                        spans.push_span_label(param.span, "");
+                    }
+                }
+
+                for generic_param in self
+                    .tcx
+                    .hir()
+                    .get_if_local(def_id)
+                    .and_then(|node| node.generics())
+                    .into_iter()
+                    .flat_map(|x| x.params)
+                    .filter(|x| {
+                        generics_with_unmatched_params
+                            .iter()
+                            .any(|y| x.name.ident() == y.name.ident())
+                    })
+                {
+                    let param_idents_matching: Vec<String> = params_with_generics
+                        .iter()
+                        .filter(|(generic, _)| {
+                            if let Some(generic) = generic {
+                                generic.name.ident() == generic_param.name.ident()
+                            } else {
+                                false
+                            }
+                        })
+                        .map(|(_, param)| {
+                            if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
+                                format!("`{ident}`")
+                            } else {
+                                "{unknown}".to_string()
+                            }
+                        })
+                        .collect();
+
+                    if !param_idents_matching.is_empty() {
                         spans.push_span_label(
-                            param.span,
+                            generic_param.span,
                             format!(
-                                "this parameter needs to match the {} type of {}",
-                                matched_ty,
-                                display_list_with_comma_and(&other_param_matched_names),
+                                "{} all reference this parameter {}",
+                                display_list_with_comma_and(&param_idents_matching),
+                                generic_param.name.ident().name,
                             ),
                         );
                     }
-                    generics_with_unmatched_params.push(generic_param);
-                } else {
-                    spans.push_span_label(param.span, "");
                 }
             }
-
-            for generic_param in self
-                .tcx
-                .hir()
-                .get_if_local(def_id)
-                .and_then(|node| node.generics())
-                .into_iter()
-                .flat_map(|x| x.params)
-                .filter(|x| {
-                    generics_with_unmatched_params.iter().any(|y| x.name.ident() == y.name.ident())
-                })
-            {
-                let param_idents_matching: Vec<String> = params_with_generics
-                    .iter()
-                    .filter(|(generic, _)| {
-                        if let Some(generic) = generic {
-                            generic.name.ident() == generic_param.name.ident()
-                        } else {
-                            false
-                        }
-                    })
-                    .map(|(_, param)| {
-                        if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind {
-                            format!("`{ident}`")
-                        } else {
-                            "{unknown}".to_string()
-                        }
-                    })
-                    .collect();
-
-                if !param_idents_matching.is_empty() {
-                    spans.push_span_label(
-                        generic_param.span,
-                        format!(
-                            "{} all reference this parameter {}",
-                            display_list_with_comma_and(&param_idents_matching),
-                            generic_param.name.ident().name,
-                        ),
-                    );
-                }
-            }
-
             err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
         } else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id)
             && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind
@@ -2535,74 +2553,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         };
 
-        let params_with_generics = self.get_hir_params_with_generics(def_id, is_method);
-
-        for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() {
-            if matched_inputs[idx.into()].is_none() {
-                continue;
-            }
+        if let Some(params_with_generics) = self.get_hir_params_with_generics(def_id, is_method) {
+            debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
+            for (idx, (generic_param, _)) in params_with_generics.iter().enumerate() {
+                if matched_inputs[idx.into()].is_none() {
+                    continue;
+                }
 
-            let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else {
-                continue;
-            };
+                let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.into()) else {
+                    continue;
+                };
 
-            let Some(generic_param) = generic_param else {
-                continue;
-            };
+                let Some(generic_param) = generic_param else {
+                    continue;
+                };
 
-            let mut idxs_matched: Vec<usize> = vec![];
-            for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter(
-                |(other_idx, (other_generic_param, _))| {
-                    if *other_idx == idx {
-                        return false;
-                    }
-                    let Some(other_generic_param) = other_generic_param else {
-                        return false;
-                    };
-                    if matched_inputs[(*other_idx).into()].is_some() {
-                        return false;
-                    }
-                    other_generic_param.name.ident() == generic_param.name.ident()
-                },
-            ) {
-                idxs_matched.push(other_idx);
-            }
+                let mut idxs_matched: Vec<usize> = vec![];
+                for (other_idx, (_, _)) in params_with_generics.iter().enumerate().filter(
+                    |(other_idx, (other_generic_param, _))| {
+                        if *other_idx == idx {
+                            return false;
+                        }
+                        let Some(other_generic_param) = other_generic_param else {
+                            return false;
+                        };
+                        if matched_inputs[(*other_idx).into()].is_some() {
+                            return false;
+                        }
+                        other_generic_param.name.ident() == generic_param.name.ident()
+                    },
+                ) {
+                    idxs_matched.push(other_idx);
+                }
 
-            if idxs_matched.is_empty() {
-                continue;
-            }
+                if idxs_matched.is_empty() {
+                    continue;
+                }
 
-            let expected_display_type = self
-                .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
-                .sort_string(self.tcx);
-            let label = if idxs_matched.len() == params_with_generics.len() - 1 {
-                format!(
-                    "expected all arguments to be this {} type because they need to match the type of this parameter",
-                    expected_display_type
-                )
-            } else {
-                format!(
-                    "expected some other arguments to be {} {} type to match the type of this parameter",
-                    a_or_an(&expected_display_type),
-                    expected_display_type,
-                )
-            };
+                let expected_display_type = self
+                    .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                    .sort_string(self.tcx);
+                let label = if idxs_matched.len() == params_with_generics.len() - 1 {
+                    format!(
+                        "expected all arguments to be this {} type because they need to match the type of this parameter",
+                        expected_display_type
+                    )
+                } else {
+                    format!(
+                        "expected some other arguments to be {} {} type to match the type of this parameter",
+                        a_or_an(&expected_display_type),
+                        expected_display_type,
+                    )
+                };
 
-            err.span_label(*matched_arg_span, label);
+                err.span_label(*matched_arg_span, label);
+            }
         }
     }
 
+    /// Returns the parameters of a function, with their generic parameters if those are the full
+    /// type of that parameter. Returns `None` if the function body is unavailable (eg is an instrinsic).
     fn get_hir_params_with_generics(
         &self,
         def_id: DefId,
         is_method: bool,
-    ) -> Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)> {
-        let fn_node = self.tcx.hir().get_if_local(def_id);
+    ) -> Option<Vec<(Option<&hir::GenericParam<'_>>, &hir::Param<'_>)>> {
+        let fn_node = self.tcx.hir().get_if_local(def_id)?;
 
         let generic_params: Vec<Option<&hir::GenericParam<'_>>> = fn_node
-            .and_then(|node| node.fn_decl())
+            .fn_decl()?
+            .inputs
             .into_iter()
-            .flat_map(|decl| decl.inputs)
             .skip(if is_method { 1 } else { 0 })
             .map(|param| {
                 if let hir::TyKind::Path(QPath::Resolved(
@@ -2611,7 +2632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 )) = param.kind
                 {
                     fn_node
-                        .and_then(|node| node.generics())
+                        .generics()
                         .into_iter()
                         .flat_map(|generics| generics.params)
                         .find(|param| &param.def_id.to_def_id() == res_def_id)
@@ -2621,14 +2642,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             })
             .collect();
 
-        let params: Vec<&hir::Param<'_>> = fn_node
-            .and_then(|node| node.body_id())
+        let params: Vec<&hir::Param<'_>> = self
+            .tcx
+            .hir()
+            .body(fn_node.body_id()?)
+            .params
             .into_iter()
-            .flat_map(|id| self.tcx.hir().body(id).params)
             .skip(if is_method { 1 } else { 0 })
             .collect();
 
-        generic_params.into_iter().zip(params).collect()
+        Some(generic_params.into_iter().zip_eq(params).collect())
     }
 }
 
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 25f9340eeb7..c8c95ddcfce 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -83,7 +83,7 @@ struct TopInfo<'tcx> {
 }
 
 #[derive(Copy, Clone)]
-struct PatInfo<'tcx, 'a> {
+struct PatInfo<'a, 'tcx> {
     binding_mode: ByRef,
     max_ref_mutbl: MutblCap,
     top_info: &'a TopInfo<'tcx>,
@@ -222,7 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Outside of this module, `check_pat_top` should always be used.
     /// Conversely, inside this module, `check_pat_top` should never be used.
     #[instrument(level = "debug", skip(self, pat_info))]
-    fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
+    fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) {
         let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
 
         let path_res = match &pat.kind {
@@ -668,7 +668,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ident: Ident,
         sub: Option<&'tcx Pat<'tcx>>,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
 
@@ -981,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fields: &'tcx [hir::PatField<'tcx>],
         has_rest_pat: bool,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         // Resolve the path and check the definition for errors.
         let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
@@ -1184,7 +1184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         subpats: &'tcx [Pat<'tcx>],
         ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let on_error = |e| {
@@ -1441,7 +1441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         elements: &'tcx [Pat<'tcx>],
         ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let mut expected_len = elements.len();
@@ -1479,7 +1479,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         variant: &'tcx ty::VariantDef,
         fields: &'tcx [hir::PatField<'tcx>],
         has_rest_pat: bool,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> Result<(), ErrorGuaranteed> {
         let tcx = self.tcx;
 
@@ -2070,7 +2070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         inner: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let (box_ty, inner_ty) = self
@@ -2096,7 +2096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         inner: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         // Register a `DerefPure` bound, which is required by all `deref!()` pats.
@@ -2137,7 +2137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         inner: &'tcx Pat<'tcx>,
         pat_mutbl: Mutability,
         mut expected: Ty<'tcx>,
-        mut pat_info: PatInfo<'tcx, '_>,
+        mut pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let features = tcx.features();
@@ -2345,7 +2345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         slice: Option<&'tcx Pat<'tcx>>,
         after: &'tcx [Pat<'tcx>],
         expected: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> Ty<'tcx> {
         let expected = self.try_structurally_resolve_type(span, expected);
 
@@ -2517,7 +2517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         span: Span,
         expected_ty: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
+        pat_info: PatInfo<'_, 'tcx>,
     ) -> ErrorGuaranteed {
         let PatInfo { top_info: ti, current_depth, .. } = pat_info;
 
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index c4a38047b5e..b93bc3ed84f 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -788,7 +788,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
     rustc_hir_analysis::check_crate(tcx);
     sess.time("MIR_coroutine_by_move_body", || {
         tcx.hir().par_body_owners(|def_id| {
-            if tcx.needs_coroutine_by_move_body_def_id(def_id) {
+            if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) {
                 tcx.ensure_with_value().coroutine_by_move_body_def_id(def_id);
             }
         });
diff --git a/compiler/rustc_lint/src/async_closures.rs b/compiler/rustc_lint/src/async_closures.rs
index 33cc5738262..2a821b71103 100644
--- a/compiler/rustc_lint/src/async_closures.rs
+++ b/compiler/rustc_lint/src/async_closures.rs
@@ -12,6 +12,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust
+    /// #![feature(async_closure)]
     /// #![warn(closure_returning_async_block)]
     /// let c = |x: &str| async {};
     /// ```
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index a60fc0ffbbb..33b8b7c544b 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -3,8 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::layout::LayoutError;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt};
 use rustc_session::declare_lint;
 use rustc_span::{sym, Span, Symbol};
 use rustc_target::abi::FIRST_VARIANT;
@@ -212,7 +211,17 @@ fn structurally_same_type<'tcx>(
     ckind: types::CItemKind,
 ) -> bool {
     let mut seen_types = UnordSet::default();
-    structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind)
+    let result = structurally_same_type_impl(&mut seen_types, tcx, param_env, a, b, ckind);
+    if cfg!(debug_assertions) && result {
+        // Sanity-check: must have same ABI, size and alignment.
+        // `extern` blocks cannot be generic, so we'll always get a layout here.
+        let a_layout = tcx.layout_of(param_env.and(a)).unwrap();
+        let b_layout = tcx.layout_of(param_env.and(b)).unwrap();
+        assert_eq!(a_layout.abi, b_layout.abi);
+        assert_eq!(a_layout.size, b_layout.size);
+        assert_eq!(a_layout.align, b_layout.align);
+    }
+    result
 }
 
 fn structurally_same_type_impl<'tcx>(
@@ -266,30 +275,21 @@ fn structurally_same_type_impl<'tcx>(
         // Do a full, depth-first comparison between the two.
         use rustc_type_ir::TyKind::*;
 
-        let compare_layouts = |a, b| -> Result<bool, &'tcx LayoutError<'tcx>> {
-            debug!("compare_layouts({:?}, {:?})", a, b);
-            let a_layout = &tcx.layout_of(param_env.and(a))?.layout.abi();
-            let b_layout = &tcx.layout_of(param_env.and(b))?.layout.abi();
-            debug!(
-                "comparing layouts: {:?} == {:?} = {}",
-                a_layout,
-                b_layout,
-                a_layout == b_layout
-            );
-            Ok(a_layout == b_layout)
-        };
-
         let is_primitive_or_pointer =
             |ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind(), RawPtr(..) | Ref(..));
 
         ensure_sufficient_stack(|| {
             match (a.kind(), b.kind()) {
-                (Adt(a_def, _), Adt(b_def, _)) => {
-                    // We can immediately rule out these types as structurally same if
-                    // their layouts differ.
-                    match compare_layouts(a, b) {
-                        Ok(false) => return false,
-                        _ => (), // otherwise, continue onto the full, fields comparison
+                (&Adt(a_def, _), &Adt(b_def, _)) => {
+                    // Only `repr(C)` types can be compared structurally.
+                    if !(a_def.repr().c() && b_def.repr().c()) {
+                        return false;
+                    }
+                    // If the types differ in their packed-ness, align, or simd-ness they conflict.
+                    let repr_characteristica =
+                        |def: AdtDef<'tcx>| (def.repr().pack, def.repr().align, def.repr().simd());
+                    if repr_characteristica(a_def) != repr_characteristica(b_def) {
+                        return false;
                     }
 
                     // Grab a flattened representation of all fields.
@@ -311,9 +311,9 @@ fn structurally_same_type_impl<'tcx>(
                         },
                     )
                 }
-                (Array(a_ty, a_const), Array(b_ty, b_const)) => {
-                    // For arrays, we also check the constness of the type.
-                    a_const.kind() == b_const.kind()
+                (Array(a_ty, a_len), Array(b_ty, b_len)) => {
+                    // For arrays, we also check the length.
+                    a_len == b_len
                         && structurally_same_type_impl(
                             seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
                         )
@@ -357,10 +357,9 @@ fn structurally_same_type_impl<'tcx>(
                             ckind,
                         )
                 }
-                (Tuple(a_args), Tuple(b_args)) => {
-                    a_args.iter().eq_by(b_args.iter(), |a_ty, b_ty| {
-                        structurally_same_type_impl(seen_types, tcx, param_env, a_ty, b_ty, ckind)
-                    })
+                (Tuple(..), Tuple(..)) => {
+                    // Tuples are not `repr(C)` so these cannot be compared structurally.
+                    false
                 }
                 // For these, it's not quite as easy to define structural-sameness quite so easily.
                 // For the purposes of this lint, take the conservative approach and mark them as
@@ -380,24 +379,21 @@ fn structurally_same_type_impl<'tcx>(
                 // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
                 // enum layout optimisation is being applied.
                 (Adt(..), _) if is_primitive_or_pointer(b) => {
-                    if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, a, ckind) {
-                        ty == b
+                    if let Some(a_inner) = types::repr_nullable_ptr(tcx, param_env, a, ckind) {
+                        a_inner == b
                     } else {
-                        compare_layouts(a, b).unwrap_or(false)
+                        false
                     }
                 }
                 (_, Adt(..)) if is_primitive_or_pointer(a) => {
-                    if let Some(ty) = types::repr_nullable_ptr(tcx, param_env, b, ckind) {
-                        ty == a
+                    if let Some(b_inner) = types::repr_nullable_ptr(tcx, param_env, b, ckind) {
+                        b_inner == a
                     } else {
-                        compare_layouts(a, b).unwrap_or(false)
+                        false
                     }
                 }
 
-                // Otherwise, just compare the layouts. This may fail to lint for some
-                // incompatible types, but at the very least, will stop reads into
-                // uninitialised memory.
-                _ => compare_layouts(a, b).unwrap_or(false),
+                _ => false,
             }
         })
     }
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 5b65541bea6..7138d40a48f 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -24,7 +24,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,edition2021
-    /// #![feature(if_let_rescope)]
+    /// #![cfg_attr(not(bootstrap), feature(if_let_rescope))] // Simplify this in bootstrap bump.
     /// #![warn(if_let_rescope)]
     /// #![allow(unused_variables)]
     ///
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 65289de980e..796d66f13d4 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -255,11 +255,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
         intravisit::walk_foreign_item(self, it);
     }
 
-    fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) {
-        // We will call `add_id` when we walk
-        // the `StmtKind`. The outer statement itself doesn't
-        // define the lint levels.
-        intravisit::walk_stmt(self, e);
+    fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
+        self.add_id(s.hir_id);
+        intravisit::walk_stmt(self, s);
     }
 
     fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 0c32157758c..5c67e21687f 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -579,6 +579,10 @@ fn register_builtins(store: &mut LintStore) {
          <https://github.com/rust-lang/rust/issues/107457> for more information",
     );
     store.register_removed("writes_through_immutable_pointer", "converted into hard error");
+    store.register_removed(
+        "const_eval_mutable_ptr_in_final_value",
+        "partially allowed now, otherwise turned into a hard error",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index e49b102cb39..a2ccb93347a 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -267,16 +267,16 @@ pub(crate) struct MacroExprFragment2024 {
     pub suggestion: Span,
 }
 
-pub(crate) struct BuiltinTypeAliasBounds<'a, 'hir> {
+pub(crate) struct BuiltinTypeAliasBounds<'hir> {
     pub in_where_clause: bool,
     pub label: Span,
     pub enable_feat_help: bool,
     pub suggestions: Vec<(Span, String)>,
     pub preds: &'hir [hir::WherePredicate<'hir>],
-    pub ty: Option<&'a hir::Ty<'hir>>,
+    pub ty: Option<&'hir hir::Ty<'hir>>,
 }
 
-impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_, '_> {
+impl<'a> LintDiagnostic<'a, ()> for BuiltinTypeAliasBounds<'_> {
     fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
         diag.primary_message(if self.in_where_clause {
             fluent::lint_builtin_type_alias_bounds_where_clause
diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs
index f9ecc8c9806..91f3e2e3bb6 100644
--- a/compiler/rustc_lint/src/tail_expr_drop_order.rs
+++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs
@@ -143,18 +143,18 @@ impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder {
     }
 }
 
-struct LintVisitor<'tcx, 'a> {
+struct LintVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     // We only record locals that have significant drops
     locals: Vec<Span>,
 }
 
-struct LocalCollector<'tcx, 'a> {
+struct LocalCollector<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     locals: &'a mut Vec<Span>,
 }
 
-impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> {
+impl<'a, 'tcx> Visitor<'tcx> for LocalCollector<'a, 'tcx> {
     type Result = ();
     fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
         if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind {
@@ -171,7 +171,7 @@ impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> {
     }
 }
 
-impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> {
+impl<'a, 'tcx> Visitor<'tcx> for LintVisitor<'a, 'tcx> {
     fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
         let mut locals = <_>::default();
         swap(&mut locals, &mut self.locals);
@@ -183,7 +183,7 @@ impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> {
     }
 }
 
-impl<'tcx, 'a> LintVisitor<'tcx, 'a> {
+impl<'a, 'tcx> LintVisitor<'a, 'tcx> {
     fn check_block_inner(&mut self, block: &Block<'tcx>) {
         if !block.span.at_least_rust_2024() {
             // We only lint for Edition 2024 onwards
@@ -205,13 +205,13 @@ impl<'tcx, 'a> LintVisitor<'tcx, 'a> {
     }
 }
 
-struct LintTailExpr<'tcx, 'a> {
+struct LintTailExpr<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     is_root_tail_expr: bool,
     locals: &'a [Span],
 }
 
-impl<'tcx, 'a> LintTailExpr<'tcx, 'a> {
+impl<'a, 'tcx> LintTailExpr<'a, 'tcx> {
     fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool {
         loop {
             match expr.kind {
@@ -239,7 +239,7 @@ impl<'tcx, 'a> LintTailExpr<'tcx, 'a> {
     }
 }
 
-impl<'tcx, 'a> Visitor<'tcx> for LintTailExpr<'tcx, 'a> {
+impl<'a, 'tcx> Visitor<'tcx> for LintTailExpr<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if self.is_root_tail_expr {
             self.is_root_tail_expr = false;
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index b5e501b92f0..900c496e033 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1713,13 +1713,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         hir_ty: &hir::Ty<'tcx>,
         ty: Ty<'tcx>,
     ) -> Vec<(Ty<'tcx>, Span)> {
-        struct FnPtrFinder<'parent, 'a, 'tcx> {
-            visitor: &'parent ImproperCTypesVisitor<'a, 'tcx>,
+        struct FnPtrFinder<'a, 'b, 'tcx> {
+            visitor: &'a ImproperCTypesVisitor<'b, 'tcx>,
             spans: Vec<Span>,
             tys: Vec<Ty<'tcx>>,
         }
 
-        impl<'parent, 'a, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'parent, 'a, 'tcx> {
+        impl<'a, 'b, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'a, 'b, 'tcx> {
             fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) {
                 debug!(?ty);
                 if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
@@ -1732,7 +1732,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             }
         }
 
-        impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'vis, 'a, 'tcx> {
+        impl<'a, 'b, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'a, 'b, 'tcx> {
             type Result = ControlFlow<Ty<'tcx>>;
 
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
@@ -1746,7 +1746,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             }
         }
 
-        let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() };
+        let mut visitor = FnPtrFinder { visitor: self, spans: Vec::new(), tys: Vec::new() };
         ty.visit_with(&mut visitor);
         hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty);
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 25d33126754..9b6d63c2ef4 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -29,7 +29,6 @@ declare_lint_pass! {
         CENUM_IMPL_DROP_CAST,
         COHERENCE_LEAK_CHECK,
         CONFLICTING_REPR_HINTS,
-        CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
         CONST_EVALUATABLE_UNCHECKED,
         CONST_ITEM_MUTATION,
         DEAD_CODE,
@@ -1871,6 +1870,7 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #[cfg_attr(bootstrap)] compile_error!(); // Remove this in bootstrap bump.
     /// #![deny(elided_named_lifetimes)]
     /// struct Foo;
     /// impl Foo {
@@ -2805,51 +2805,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `const_eval_mutable_ptr_in_final_value` lint detects if a mutable pointer
-    /// has leaked into the final value of a const expression.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// pub enum JsValue {
-    ///     Undefined,
-    ///     Object(std::cell::Cell<bool>),
-    /// }
-    ///
-    /// impl ::std::ops::Drop for JsValue {
-    ///     fn drop(&mut self) {}
-    /// }
-    ///
-    /// const UNDEFINED: &JsValue = &JsValue::Undefined;
-    ///
-    /// fn main() {
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// In the 1.77 release, the const evaluation machinery adopted some
-    /// stricter rules to reject expressions with values that could
-    /// end up holding mutable references to state stored in static memory
-    /// (which is inherently immutable).
-    ///
-    /// This is a [future-incompatible] lint to ease the transition to an error.
-    /// See [issue #122153] for more details.
-    ///
-    /// [issue #122153]: https://github.com/rust-lang/rust/issues/122153
-    /// [future-incompatible]: ../index.md#future-incompatible-lints
-    pub CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
-    Warn,
-    "detects a mutable pointer that has leaked into final value of a const expression",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
-        reference: "issue #122153 <https://github.com/rust-lang/rust/issues/122153>",
-    };
-}
-
-declare_lint! {
     /// The `const_evaluatable_unchecked` lint detects a generic constant used
     /// in a type.
     ///
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 6cfd07d699c..1700b0f02ec 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -80,14 +80,23 @@ pub trait Provenance: Copy + fmt::Debug + 'static {
 }
 
 /// The type of provenance in the compile-time interpreter.
-/// This is a packed representation of an `AllocId` and an `immutable: bool`.
+/// This is a packed representation of:
+/// - an `AllocId` (non-zero)
+/// - an `immutable: bool`
+/// - a `shared_ref: bool`
+///
+/// with the extra invariant that if `immutable` is `true`, then so
+/// is `shared_ref`.
 #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub struct CtfeProvenance(NonZero<u64>);
 
 impl From<AllocId> for CtfeProvenance {
     fn from(value: AllocId) -> Self {
         let prov = CtfeProvenance(value.0);
-        assert!(!prov.immutable(), "`AllocId` with the highest bit set cannot be used in CTFE");
+        assert!(
+            prov.alloc_id() == value,
+            "`AllocId` with the highest bits set cannot be used in CTFE"
+        );
         prov
     }
 }
@@ -103,12 +112,14 @@ impl fmt::Debug for CtfeProvenance {
 }
 
 const IMMUTABLE_MASK: u64 = 1 << 63; // the highest bit
+const SHARED_REF_MASK: u64 = 1 << 62;
+const ALLOC_ID_MASK: u64 = u64::MAX & !IMMUTABLE_MASK & !SHARED_REF_MASK;
 
 impl CtfeProvenance {
     /// Returns the `AllocId` of this provenance.
     #[inline(always)]
     pub fn alloc_id(self) -> AllocId {
-        AllocId(NonZero::new(self.0.get() & !IMMUTABLE_MASK).unwrap())
+        AllocId(NonZero::new(self.0.get() & ALLOC_ID_MASK).unwrap())
     }
 
     /// Returns whether this provenance is immutable.
@@ -117,10 +128,38 @@ impl CtfeProvenance {
         self.0.get() & IMMUTABLE_MASK != 0
     }
 
+    /// Returns whether this provenance is derived from a shared reference.
+    #[inline]
+    pub fn shared_ref(self) -> bool {
+        self.0.get() & SHARED_REF_MASK != 0
+    }
+
+    pub fn into_parts(self) -> (AllocId, bool, bool) {
+        (self.alloc_id(), self.immutable(), self.shared_ref())
+    }
+
+    pub fn from_parts((alloc_id, immutable, shared_ref): (AllocId, bool, bool)) -> Self {
+        let prov = CtfeProvenance::from(alloc_id);
+        if immutable {
+            // This sets both flags, so we don't even have to check `shared_ref`.
+            prov.as_immutable()
+        } else if shared_ref {
+            prov.as_shared_ref()
+        } else {
+            prov
+        }
+    }
+
     /// Returns an immutable version of this provenance.
     #[inline]
     pub fn as_immutable(self) -> Self {
-        CtfeProvenance(self.0 | IMMUTABLE_MASK)
+        CtfeProvenance(self.0 | IMMUTABLE_MASK | SHARED_REF_MASK)
+    }
+
+    /// Returns a "shared reference" (but not necessarily immutable!) version of this provenance.
+    #[inline]
+    pub fn as_shared_ref(self) -> Self {
+        CtfeProvenance(self.0 | SHARED_REF_MASK)
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 22a4b688c51..f5590aa2762 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1094,7 +1094,7 @@ pub struct Place<'tcx> {
     pub projection: &'tcx List<PlaceElem<'tcx>>,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum ProjectionElem<V, T> {
     Deref,
@@ -1468,7 +1468,7 @@ pub enum NullOp<'tcx> {
     UbChecks,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
 pub enum UnOp {
     /// The `!` operator for logical inversion
@@ -1486,7 +1486,7 @@ pub enum UnOp {
     PtrMetadata,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum BinOp {
     /// The `+` operator (addition)
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 46203ee150f..7e533bc4291 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -165,8 +165,7 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId {
 
 impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for CtfeProvenance {
     fn encode(&self, e: &mut E) {
-        self.alloc_id().encode(e);
-        self.immutable().encode(e);
+        self.into_parts().encode(e);
     }
 }
 
@@ -295,10 +294,8 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AllocId {
 
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CtfeProvenance {
     fn decode(decoder: &mut D) -> Self {
-        let alloc_id: AllocId = Decodable::decode(decoder);
-        let prov = CtfeProvenance::from(alloc_id);
-        let immutable: bool = Decodable::decode(decoder);
-        if immutable { prov.as_immutable() } else { prov }
+        let parts = Decodable::decode(decoder);
+        CtfeProvenance::from_parts(parts)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 5ec7e80ee45..cd06d7b8e53 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -3171,7 +3171,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self.impl_trait_header(def_id).map_or(ty::ImplPolarity::Positive, |h| h.polarity)
     }
 
-    pub fn needs_coroutine_by_move_body_def_id(self, def_id: LocalDefId) -> bool {
+    pub fn needs_coroutine_by_move_body_def_id(self, def_id: DefId) -> bool {
         if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure)) =
             self.coroutine_kind(def_id)
             && let ty::Coroutine(_, args) = self.type_of(def_id).instantiate_identity().kind()
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index b5b7b8bcfef..5f6305bb48a 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -75,11 +75,9 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
     }
 }
 
-// CtfeProvenance is an AllocId and a bool.
 impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::CtfeProvenance {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        self.alloc_id().hash_stable(hcx, hasher);
-        self.immutable().hash_stable(hcx, hasher);
+        self.into_parts().hash_stable(hcx, hasher);
     }
 }
 
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 7a10e627ccd..1c4e9fd11cb 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -338,6 +338,7 @@ mir_build_unreachable_pattern = unreachable pattern
     .unreachable_covered_by_catchall = matches any value
     .unreachable_covered_by_one = matches all the relevant values
     .unreachable_covered_by_many = multiple earlier patterns match some of the same values
+    .suggestion = remove the match arm
 
 mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default
 mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 28477e527c7..1e1fa21b5f3 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -134,13 +134,12 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
     MirPhase::parse(dialect, phase)
 }
 
-struct ParseCtxt<'tcx, 'body> {
+struct ParseCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
-    thir: &'body Thir<'tcx>,
+    thir: &'a Thir<'tcx>,
     source_scope: SourceScope,
-
-    body: &'body mut Body<'tcx>,
+    body: &'a mut Body<'tcx>,
     local_map: FxHashMap<LocalVarId, Local>,
     block_map: FxHashMap<LocalVarId, BasicBlock>,
 }
@@ -151,7 +150,7 @@ struct ParseError {
     expected: String,
 }
 
-impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
     fn expr_error(&self, expr: ExprId, expected: &'static str) -> ParseError {
         let expr = &self.thir[expr];
         ParseError {
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index 1f186c8f99a..538068e1fac 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -68,7 +68,7 @@ macro_rules! parse_by_kind {
 }
 pub(crate) use parse_by_kind;
 
-impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
     /// Expressions should only ever be matched on after preparsing them. This removes extra scopes
     /// we don't care about.
     fn preparse(&self, expr_id: ExprId) -> ExprId {
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 0b13ceb574d..0cbd2da10db 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -12,7 +12,7 @@ use super::{parse_by_kind, PResult, ParseCtxt};
 use crate::build::custom::ParseError;
 use crate::build::expr::as_constant::as_constant_inner;
 
-impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
+impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
     pub(crate) fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
         parse_by_kind!(self, expr_id, _, "statement",
             @call(mir_storage_live, args) => {
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 7f9eefd1d52..411e9420914 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -598,6 +598,8 @@ pub(crate) struct UnreachablePattern<'tcx> {
     #[note(mir_build_unreachable_covered_by_many)]
     pub(crate) covered_by_many: Option<MultiSpan>,
     pub(crate) covered_by_many_n_more_count: usize,
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub(crate) suggest_remove: Option<Span>,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 4c066a68ef9..3fde6466d8c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -413,7 +413,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 // Emit lints in the order in which they occur in the file.
                 redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span);
                 for (pat, explanation) in redundant_subpats {
-                    report_unreachable_pattern(cx, arm.arm_data, pat, &explanation)
+                    report_unreachable_pattern(cx, arm.arm_data, pat, &explanation, None)
                 }
             }
         }
@@ -474,7 +474,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             hir::MatchSource::ForLoopDesugar
             | hir::MatchSource::Postfix
             | hir::MatchSource::Normal
-            | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
+            | hir::MatchSource::FormatArgs => {
+                let is_match_arm =
+                    matches!(source, hir::MatchSource::Postfix | hir::MatchSource::Normal);
+                report_arm_reachability(&cx, &report, is_match_arm);
+            }
             // Unreachable patterns in try and await expressions occur when one of
             // the arms are an uninhabited type. Which is OK.
             hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar(_) => {}
@@ -626,7 +630,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
     ) -> Result<RefutableFlag, ErrorGuaranteed> {
         let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
         // Report if the pattern is unreachable, which can only occur when the type is uninhabited.
-        report_arm_reachability(&cx, &report);
+        report_arm_reachability(&cx, &report, false);
         // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
         // irrefutable.
         Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable })
@@ -916,6 +920,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
     hir_id: HirId,
     pat: &DeconstructedPat<'p, 'tcx>,
     explanation: &RedundancyExplanation<'p, 'tcx>,
+    whole_arm_span: Option<Span>,
 ) {
     static CAP_COVERED_BY_MANY: usize = 4;
     let pat_span = pat.data().span;
@@ -928,6 +933,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
         covered_by_one: None,
         covered_by_many: None,
         covered_by_many_n_more_count: 0,
+        suggest_remove: None,
     };
     match explanation.covered_by.as_slice() {
         [] => {
@@ -935,6 +941,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
             lint.span = None; // Don't label the pattern itself
             lint.uninhabited_note = Some(()); // Give a link about empty types
             lint.matches_no_values = Some(pat_span);
+            lint.suggest_remove = whole_arm_span; // Suggest to remove the match arm
             pat.walk(&mut |subpat| {
                 let ty = **subpat.ty();
                 if cx.is_uninhabited(ty) {
@@ -982,10 +989,28 @@ fn report_unreachable_pattern<'p, 'tcx>(
 }
 
 /// Report unreachable arms, if any.
-fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) {
+fn report_arm_reachability<'p, 'tcx>(
+    cx: &PatCtxt<'p, 'tcx>,
+    report: &UsefulnessReport<'p, 'tcx>,
+    is_match_arm: bool,
+) {
+    let sm = cx.tcx.sess.source_map();
     for (arm, is_useful) in report.arm_usefulness.iter() {
         if let Usefulness::Redundant(explanation) = is_useful {
-            report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation)
+            let hir_id = arm.arm_data;
+            let arm_span = cx.tcx.hir().span(hir_id);
+            let whole_arm_span = if is_match_arm {
+                // If the arm is followed by a comma, extend the span to include it.
+                let with_whitespace = sm.span_extend_while_whitespace(arm_span);
+                if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) {
+                    Some(arm_span.to(comma))
+                } else {
+                    Some(arm_span)
+                }
+            } else {
+                None
+            };
+            report_unreachable_pattern(cx, hir_id, arm.pat, explanation, whole_arm_span)
         }
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index d7e738b8829..c4d06cbb1b0 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -155,11 +155,11 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug {
 }
 
 #[derive(Debug)]
-struct DropCtxt<'l, 'b, 'tcx, D>
+struct DropCtxt<'a, 'b, 'tcx, D>
 where
     D: DropElaborator<'b, 'tcx>,
 {
-    elaborator: &'l mut D,
+    elaborator: &'a mut D,
 
     source_info: SourceInfo,
 
@@ -192,7 +192,7 @@ pub fn elaborate_drop<'b, 'tcx, D>(
     DropCtxt { elaborator, source_info, place, path, succ, unwind }.elaborate_drop(bb)
 }
 
-impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
+impl<'a, 'b, 'tcx, D> DropCtxt<'a, 'b, 'tcx, D>
 where
     D: DropElaborator<'b, 'tcx>,
     'tcx: 'b,
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index ba4a7d76511..88a9a78f8ad 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -42,14 +42,14 @@ pub trait Direction {
     ) where
         A: GenKillAnalysis<'tcx>;
 
-    fn visit_results_in_block<'mir, 'tcx, F, R>(
-        state: &mut F,
+    fn visit_results_in_block<'mir, 'tcx, D, R>(
+        state: &mut D,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
         results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
     ) where
-        R: ResultsVisitable<'tcx, FlowState = F>;
+        R: ResultsVisitable<'tcx, Domain = D>;
 
     fn join_state_into_successors_of<'tcx, A>(
         analysis: &mut A,
@@ -186,14 +186,14 @@ impl Direction for Backward {
         analysis.apply_statement_effect(state, statement, location);
     }
 
-    fn visit_results_in_block<'mir, 'tcx, F, R>(
-        state: &mut F,
+    fn visit_results_in_block<'mir, 'tcx, D, R>(
+        state: &mut D,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
         results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
     ) where
-        R: ResultsVisitable<'tcx, FlowState = F>,
+        R: ResultsVisitable<'tcx, Domain = D>,
     {
         results.reset_to_block_entry(state, block);
 
@@ -444,9 +444,9 @@ impl Direction for Forward {
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
         results: &mut R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>,
     ) where
-        R: ResultsVisitable<'tcx, FlowState = F>,
+        R: ResultsVisitable<'tcx, Domain = F>,
     {
         results.reset_to_block_entry(state, block);
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 0bab03b0271..54206501d9f 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -57,7 +57,7 @@ where
         &mut self,
         body: &'mir mir::Body<'tcx>,
         blocks: impl IntoIterator<Item = BasicBlock>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
     ) {
         visit_results(body, blocks, self, vis)
     }
@@ -65,7 +65,7 @@ where
     pub fn visit_reachable_with<'mir>(
         &mut self,
         body: &'mir mir::Body<'tcx>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
     ) {
         let blocks = mir::traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 2e860e2d841..e72dca2c834 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -544,15 +544,15 @@ where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
 {
-    type FlowState = A::Domain;
+    type Domain = A::Domain;
 
-    fn visit_block_start(&mut self, state: &Self::FlowState) {
+    fn visit_block_start(&mut self, state: &Self::Domain) {
         if A::Direction::IS_FORWARD {
             self.prev_state.clone_from(state);
         }
     }
 
-    fn visit_block_end(&mut self, state: &Self::FlowState) {
+    fn visit_block_end(&mut self, state: &Self::Domain) {
         if A::Direction::IS_BACKWARD {
             self.prev_state.clone_from(state);
         }
@@ -561,7 +561,7 @@ where
     fn visit_statement_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -574,7 +574,7 @@ where
     fn visit_statement_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -585,7 +585,7 @@ where
     fn visit_terminator_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
@@ -598,7 +598,7 @@ where
     fn visit_terminator_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, A>,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index 8b8a16bda99..3d6b008a684 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -4,15 +4,15 @@ use super::{Analysis, Direction, Results};
 
 /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
 /// dataflow state at that location.
-pub fn visit_results<'mir, 'tcx, F, R>(
+pub fn visit_results<'mir, 'tcx, D, R>(
     body: &'mir mir::Body<'tcx>,
     blocks: impl IntoIterator<Item = BasicBlock>,
     results: &mut R,
-    vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
+    vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
 ) where
-    R: ResultsVisitable<'tcx, FlowState = F>,
+    R: ResultsVisitable<'tcx, Domain = D>,
 {
-    let mut state = results.new_flow_state(body);
+    let mut state = results.bottom_value(body);
 
     #[cfg(debug_assertions)]
     let reachable_blocks = mir::traversal::reachable_as_bitset(body);
@@ -29,16 +29,16 @@ pub fn visit_results<'mir, 'tcx, F, R>(
 /// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
 /// visited.
 pub trait ResultsVisitor<'mir, 'tcx, R> {
-    type FlowState;
+    type Domain;
 
-    fn visit_block_start(&mut self, _state: &Self::FlowState) {}
+    fn visit_block_start(&mut self, _state: &Self::Domain) {}
 
     /// Called with the `before_statement_effect` of the given statement applied to `state` but not
     /// its `statement_effect`.
     fn visit_statement_before_primary_effect(
         &mut self,
         _results: &mut R,
-        _state: &Self::FlowState,
+        _state: &Self::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -49,7 +49,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
     fn visit_statement_after_primary_effect(
         &mut self,
         _results: &mut R,
-        _state: &Self::FlowState,
+        _state: &Self::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         _location: Location,
     ) {
@@ -60,7 +60,7 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
     fn visit_terminator_before_primary_effect(
         &mut self,
         _results: &mut R,
-        _state: &Self::FlowState,
+        _state: &Self::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
     ) {
@@ -73,13 +73,13 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
     fn visit_terminator_after_primary_effect(
         &mut self,
         _results: &mut R,
-        _state: &Self::FlowState,
+        _state: &Self::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
     ) {
     }
 
-    fn visit_block_end(&mut self, _state: &Self::FlowState) {}
+    fn visit_block_end(&mut self, _state: &Self::Domain) {}
 }
 
 /// Things that can be visited by a `ResultsVisitor`.
@@ -88,40 +88,40 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
 /// simultaneously.
 pub trait ResultsVisitable<'tcx> {
     type Direction: Direction;
-    type FlowState;
+    type Domain;
 
-    /// Creates an empty `FlowState` to hold the transient state for these dataflow results.
+    /// Creates an empty `Domain` to hold the transient state for these dataflow results.
     ///
-    /// The value of the newly created `FlowState` will be overwritten by `reset_to_block_entry`
+    /// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry`
     /// before it can be observed by a `ResultsVisitor`.
-    fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState;
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain;
 
-    fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock);
+    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock);
 
     fn reconstruct_before_statement_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
     );
 
     fn reconstruct_statement_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
     );
 
     fn reconstruct_before_terminator_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
     );
 
     fn reconstruct_terminator_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
     );
@@ -131,21 +131,20 @@ impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    type FlowState = A::Domain;
-
+    type Domain = A::Domain;
     type Direction = A::Direction;
 
-    fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState {
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
         self.analysis.bottom_value(body)
     }
 
-    fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
+    fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
         state.clone_from(self.entry_set_for_block(block));
     }
 
     fn reconstruct_before_statement_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
@@ -154,7 +153,7 @@ where
 
     fn reconstruct_statement_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
@@ -163,7 +162,7 @@ where
 
     fn reconstruct_before_terminator_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         term: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
@@ -172,7 +171,7 @@ where
 
     fn reconstruct_terminator_effect(
         &mut self,
-        state: &mut Self::FlowState,
+        state: &mut Self::Domain,
         term: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index e8e78fb8a89..8b082ef2667 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -11,7 +11,7 @@ use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
 /// At present, this is used as a very limited form of alias analysis. For example,
 /// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
 /// immovable coroutines.
-#[derive(Clone, Copy)]
+#[derive(Clone)]
 pub struct MaybeBorrowedLocals;
 
 impl MaybeBorrowedLocals {
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 24a4b32ceb7..1559c131a37 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -217,7 +217,6 @@ impl DefUse {
 /// This is basically written for dead store elimination and nothing else.
 ///
 /// All of the caveats of `MaybeLiveLocals` apply.
-#[derive(Clone, Copy)]
 pub struct MaybeTransitiveLiveLocals<'a> {
     always_live: &'a BitSet<Local>,
 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 9f2f0187698..34ac5809a2e 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -7,7 +7,6 @@ use rustc_middle::mir::*;
 use super::MaybeBorrowedLocals;
 use crate::{GenKill, ResultsCursor};
 
-#[derive(Clone)]
 pub struct MaybeStorageLive<'a> {
     always_live_locals: Cow<'a, BitSet<Local>>,
 }
@@ -18,7 +17,7 @@ impl<'a> MaybeStorageLive<'a> {
     }
 }
 
-impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
+impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
     type Domain = BitSet<Local>;
 
     const NAME: &'static str = "maybe_storage_live";
@@ -40,7 +39,7 @@ impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
     }
 }
 
-impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
+impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
     type Idx = Local;
 
     fn domain_size(&self, body: &Body<'tcx>) -> usize {
@@ -80,7 +79,6 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
     }
 }
 
-#[derive(Clone)]
 pub struct MaybeStorageDead<'a> {
     always_live_locals: Cow<'a, BitSet<Local>>,
 }
@@ -91,7 +89,7 @@ impl<'a> MaybeStorageDead<'a> {
     }
 }
 
-impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> {
+impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> {
     type Domain = BitSet<Local>;
 
     const NAME: &'static str = "maybe_storage_dead";
@@ -112,7 +110,7 @@ impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> {
     }
 }
 
-impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> {
+impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> {
     type Idx = Local;
 
     fn domain_size(&self, body: &Body<'tcx>) -> usize {
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
index 4be7492366a..adfa94464a0 100644
--- a/compiler/rustc_mir_dataflow/src/points.rs
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -102,7 +102,7 @@ pub fn save_as_intervals<'tcx, N, R>(
 ) -> SparseIntervalMatrix<N, PointIndex>
 where
     N: Idx,
-    R: ResultsVisitable<'tcx, FlowState = BitSet<N>>,
+    R: ResultsVisitable<'tcx, Domain = BitSet<N>>,
 {
     let values = SparseIntervalMatrix::new(elements.num_points());
     let mut visitor = Visitor { elements, values };
@@ -124,12 +124,12 @@ impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
 where
     N: Idx,
 {
-    type FlowState = BitSet<N>;
+    type Domain = BitSet<N>;
 
     fn visit_statement_after_primary_effect(
         &mut self,
         _results: &mut R,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         _statement: &'mir mir::Statement<'tcx>,
         location: Location,
     ) {
@@ -143,7 +143,7 @@ where
     fn visit_terminator_after_primary_effect(
         &mut self,
         _results: &mut R,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         _terminator: &'mir mir::Terminator<'tcx>,
         location: Location,
     ) {
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 8c3e6f49b16..ac9b853f21b 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -229,7 +229,7 @@ trait RustcPeekAt<'tcx>: Analysis<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         place: mir::Place<'tcx>,
-        flow_state: &Self::Domain,
+        state: &Self::Domain,
         call: PeekCall,
     );
 }
@@ -243,12 +243,12 @@ where
         &self,
         tcx: TyCtxt<'tcx>,
         place: mir::Place<'tcx>,
-        flow_state: &Self::Domain,
+        state: &Self::Domain,
         call: PeekCall,
     ) {
         match self.move_data().rev_lookup.find(place.as_ref()) {
             LookupResult::Exact(peek_mpi) => {
-                let bit_state = flow_state.contains(peek_mpi);
+                let bit_state = state.contains(peek_mpi);
                 debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state);
                 if !bit_state {
                     tcx.dcx().emit_err(PeekBitNotSet { span: call.span });
@@ -267,7 +267,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
         &self,
         tcx: TyCtxt<'tcx>,
         place: mir::Place<'tcx>,
-        flow_state: &BitSet<Local>,
+        state: &BitSet<Local>,
         call: PeekCall,
     ) {
         info!(?place, "peek_at");
@@ -276,7 +276,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
             return;
         };
 
-        if !flow_state.contains(local) {
+        if !state.contains(local) {
             tcx.dcx().emit_err(PeekBitNotSet { span: call.span });
         }
     }
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index e1d5152ae51..a9600f77c0b 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -62,14 +62,14 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
     }
 }
 
-struct PointerFinder<'tcx, 'a> {
+struct PointerFinder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     local_decls: &'a mut LocalDecls<'tcx>,
     param_env: ParamEnv<'tcx>,
     pointers: Vec<(Place<'tcx>, Ty<'tcx>)>,
 }
 
-impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> {
+impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> {
     fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
         // We want to only check reads and writes to Places, so we specifically exclude
         // Borrow and RawBorrow.
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 90243cd2910..1fb74f5d82c 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -885,12 +885,12 @@ struct StorageConflictVisitor<'a, 'tcx> {
 impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
     for StorageConflictVisitor<'a, 'tcx>
 {
-    type FlowState = BitSet<Local>;
+    type Domain = BitSet<Local>;
 
     fn visit_statement_before_primary_effect(
         &mut self,
         _results: &mut R,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         _statement: &'a Statement<'tcx>,
         loc: Location,
     ) {
@@ -900,7 +900,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
     fn visit_terminator_before_primary_effect(
         &mut self,
         _results: &mut R,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         _terminator: &'a Terminator<'tcx>,
         loc: Location,
     ) {
@@ -909,13 +909,13 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
 }
 
 impl StorageConflictVisitor<'_, '_> {
-    fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
+    fn apply_state(&mut self, state: &BitSet<Local>, loc: Location) {
         // Ignore unreachable blocks.
         if let TerminatorKind::Unreachable = self.body.basic_blocks[loc.block].terminator().kind {
             return;
         }
 
-        self.eligible_storage_live.clone_from(flow_state);
+        self.eligible_storage_live.clone_from(state);
         self.eligible_storage_live.intersect(&**self.saved_locals);
 
         for local in self.eligible_storage_live.iter() {
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 7ac019ce812..997b8c06a96 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -554,13 +554,13 @@ impl<'tcx> Patch<'tcx> {
     }
 }
 
-struct Collector<'tcx, 'locals> {
+struct Collector<'a, 'tcx> {
     patch: Patch<'tcx>,
-    local_decls: &'locals LocalDecls<'tcx>,
+    local_decls: &'a LocalDecls<'tcx>,
 }
 
-impl<'tcx, 'locals> Collector<'tcx, 'locals> {
-    pub(crate) fn new(tcx: TyCtxt<'tcx>, local_decls: &'locals LocalDecls<'tcx>) -> Self {
+impl<'a, 'tcx> Collector<'a, 'tcx> {
+    pub(crate) fn new(tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>) -> Self {
         Self { patch: Patch::new(tcx), local_decls }
     }
 
@@ -722,15 +722,15 @@ fn try_write_constant<'tcx>(
 
 impl<'mir, 'tcx>
     ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
-    for Collector<'tcx, '_>
+    for Collector<'_, 'tcx>
 {
-    type FlowState = State<FlatSet<Scalar>>;
+    type Domain = State<FlatSet<Scalar>>;
 
     #[instrument(level = "trace", skip(self, results, statement))]
     fn visit_statement_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
@@ -752,7 +752,7 @@ impl<'mir, 'tcx>
     fn visit_statement_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
@@ -777,7 +777,7 @@ impl<'mir, 'tcx>
     fn visit_terminator_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
-        state: &Self::FlowState,
+        state: &Self::Domain,
         terminator: &'mir Terminator<'tcx>,
         location: Location,
     ) {
@@ -839,9 +839,9 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
     }
 }
 
-struct OperandCollector<'a, 'locals, 'tcx> {
+struct OperandCollector<'a, 'b, 'tcx> {
     state: &'a State<FlatSet<Scalar>>,
-    visitor: &'a mut Collector<'tcx, 'locals>,
+    visitor: &'a mut Collector<'b, 'tcx>,
     ecx: &'a mut InterpCx<'tcx, DummyMachine>,
     map: &'a Map<'tcx>,
 }
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index ad204e76d0d..26b28c8c487 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -98,7 +98,7 @@ fn find_duplicates(body: &Body<'_>) -> FxHashMap<BasicBlock, BasicBlock> {
     duplicates
 }
 
-struct BasicBlockHashable<'tcx, 'a> {
+struct BasicBlockHashable<'a, 'tcx> {
     basic_block_data: &'a BasicBlockData<'tcx>,
 }
 
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 367a8c07593..57f7a9ef7f5 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -38,7 +38,7 @@ pub(super) fn build_projection<'tcx>(
     ]
 }
 
-struct ElaborateBoxDerefVisitor<'tcx, 'a> {
+struct ElaborateBoxDerefVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     unique_did: DefId,
     nonnull_did: DefId,
@@ -46,7 +46,7 @@ struct ElaborateBoxDerefVisitor<'tcx, 'a> {
     patch: MirPatch<'tcx>,
 }
 
-impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> {
+impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 9a93c3a72b1..4550ef06315 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -89,7 +89,7 @@ pub(crate) struct FnItemRef {
     pub ident: String,
 }
 
-pub(crate) struct MustNotSupend<'tcx, 'a> {
+pub(crate) struct MustNotSupend<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
     pub yield_sp: Span,
     pub reason: Option<MustNotSuspendReason>,
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 598bf61483d..0f08d920c5e 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -875,6 +875,95 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         None
     }
 
+    fn try_as_place_elem(
+        &mut self,
+        proj: ProjectionElem<VnIndex, Ty<'tcx>>,
+        loc: Location,
+    ) -> Option<PlaceElem<'tcx>> {
+        Some(match proj {
+            ProjectionElem::Deref => ProjectionElem::Deref,
+            ProjectionElem::Field(idx, ty) => ProjectionElem::Field(idx, ty),
+            ProjectionElem::Index(idx) => {
+                let Some(local) = self.try_as_local(idx, loc) else {
+                    return None;
+                };
+                self.reused_locals.insert(local);
+                ProjectionElem::Index(local)
+            }
+            ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                ProjectionElem::ConstantIndex { offset, min_length, from_end }
+            }
+            ProjectionElem::Subslice { from, to, from_end } => {
+                ProjectionElem::Subslice { from, to, from_end }
+            }
+            ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
+            ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
+            ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx),
+        })
+    }
+
+    fn simplify_aggregate_to_copy(
+        &mut self,
+        rvalue: &mut Rvalue<'tcx>,
+        location: Location,
+        fields: &[VnIndex],
+        variant_index: VariantIdx,
+    ) -> Option<VnIndex> {
+        let Some(&first_field) = fields.first() else {
+            return None;
+        };
+        let Value::Projection(copy_from_value, _) = *self.get(first_field) else {
+            return None;
+        };
+        // All fields must correspond one-to-one and come from the same aggregate value.
+        if fields.iter().enumerate().any(|(index, &v)| {
+            if let Value::Projection(pointer, ProjectionElem::Field(from_index, _)) = *self.get(v)
+                && copy_from_value == pointer
+                && from_index.index() == index
+            {
+                return false;
+            }
+            true
+        }) {
+            return None;
+        }
+
+        let mut copy_from_local_value = copy_from_value;
+        if let Value::Projection(pointer, proj) = *self.get(copy_from_value)
+            && let ProjectionElem::Downcast(_, read_variant) = proj
+        {
+            if variant_index == read_variant {
+                // When copying a variant, there is no need to downcast.
+                copy_from_local_value = pointer;
+            } else {
+                // The copied variant must be identical.
+                return None;
+            }
+        }
+
+        let tcx = self.tcx;
+        let mut projection = SmallVec::<[PlaceElem<'tcx>; 1]>::new();
+        loop {
+            if let Some(local) = self.try_as_local(copy_from_local_value, location) {
+                projection.reverse();
+                let place = Place { local, projection: tcx.mk_place_elems(projection.as_slice()) };
+                if rvalue.ty(self.local_decls, tcx) == place.ty(self.local_decls, tcx).ty {
+                    self.reused_locals.insert(local);
+                    *rvalue = Rvalue::Use(Operand::Copy(place));
+                    return Some(copy_from_value);
+                }
+                return None;
+            } else if let Value::Projection(pointer, proj) = *self.get(copy_from_local_value)
+                && let Some(proj) = self.try_as_place_elem(proj, location)
+            {
+                projection.push(proj);
+                copy_from_local_value = pointer;
+            } else {
+                return None;
+            }
+        }
+    }
+
     fn simplify_aggregate(
         &mut self,
         rvalue: &mut Rvalue<'tcx>,
@@ -971,6 +1060,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         }
 
+        if let AggregateTy::Def(_, _) = ty
+            && let Some(value) =
+                self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index)
+        {
+            return Some(value);
+        }
+
         Some(self.insert(Value::Aggregate(ty, variant_index, fields)))
     }
 
@@ -1485,7 +1581,7 @@ impl<'tcx> VnState<'_, 'tcx> {
     }
 
     /// If there is a local which is assigned `index`, and its assignment strictly dominates `loc`,
-    /// return it.
+    /// return it. If you used this local, add it to `reused_locals` to remove storage statements.
     fn try_as_local(&mut self, index: VnIndex, loc: Location) -> Option<Local> {
         let other = self.rev_locals.get(index)?;
         other
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 0b344f29b07..5c8958924fb 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -63,13 +63,13 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
     }
 }
 
-struct InstSimplifyContext<'tcx, 'a> {
+struct InstSimplifyContext<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     local_decls: &'a LocalDecls<'tcx>,
     param_env: ParamEnv<'tcx>,
 }
 
-impl<'tcx> InstSimplifyContext<'tcx, '_> {
+impl<'tcx> InstSimplifyContext<'_, 'tcx> {
     fn should_simplify(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
         self.should_simplify_custom(source_info, "Rvalue", rvalue)
     }
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index d48df59ada8..1810569bc8e 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -117,7 +117,7 @@ struct ThreadingOpportunity {
     target: BasicBlock,
 }
 
-struct TOFinder<'tcx, 'a> {
+struct TOFinder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     ecx: InterpCx<'tcx, DummyMachine>,
@@ -183,7 +183,7 @@ impl<'a> ConditionSet<'a> {
     }
 }
 
-impl<'tcx, 'a> TOFinder<'tcx, 'a> {
+impl<'a, 'tcx> TOFinder<'a, 'tcx> {
     fn is_empty(&self, state: &State<ConditionSet<'a>>) -> bool {
         state.all_bottom()
     }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 84d07d38330..424e7008326 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -330,7 +330,7 @@ fn mir_promoted(
     tcx.ensure_with_value().has_ffi_unwind_calls(def);
 
     // the `by_move_body` query uses the raw mir, so make sure it is run.
-    if tcx.needs_coroutine_by_move_body_def_id(def) {
+    if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) {
         tcx.ensure_with_value().coroutine_by_move_body_def_id(def);
     }
 
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 0f981425cfd..ad3126f66a6 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -295,7 +295,7 @@ struct SimplifyToExp {
 }
 
 #[derive(Clone, Copy)]
-enum ExpectedTransformKind<'tcx, 'a> {
+enum ExpectedTransformKind<'a, 'tcx> {
     /// Identical statements.
     Same(&'a StatementKind<'tcx>),
     /// Assignment statements have the same value.
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index cf8622cadd1..ba64216f9e1 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -235,7 +235,7 @@ impl SsaLocals {
     }
 }
 
-struct SsaVisitor<'tcx, 'a> {
+struct SsaVisitor<'a, 'tcx> {
     body: &'a Body<'tcx>,
     dominators: &'a Dominators<BasicBlock>,
     assignments: IndexVec<Local, Set1<DefLocation>>,
@@ -261,7 +261,7 @@ impl SsaVisitor<'_, '_> {
     }
 }
 
-impl<'tcx> Visitor<'tcx> for SsaVisitor<'tcx, '_> {
+impl<'tcx> Visitor<'tcx> for SsaVisitor<'_, 'tcx> {
     fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) {
         match ctxt {
             PlaceContext::MutatingUse(MutatingUseContext::Projection)
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 3b84755dded..e5837b1b475 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1,7 +1,6 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir as hir;
 use rustc_hir::LangItem;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
@@ -717,10 +716,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             // first place.
                             let layout = if def_id == self.caller_body.source.def_id() {
                                 self.caller_body.coroutine_layout_raw()
-                            } else if let Some(hir::CoroutineKind::Desugared(
-                                _,
-                                hir::CoroutineSource::Closure,
-                            )) = self.tcx.coroutine_kind(def_id)
+                            } else if self.tcx.needs_coroutine_by_move_body_def_id(def_id)
                                 && let ty::ClosureKind::FnOnce =
                                     args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap()
                                 && self.caller_body.source.def_id()
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 2d6edad2977..2d5a1914fa6 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -49,7 +49,7 @@ enum DestructuredFloat {
     /// 1.2 | 1.2e3
     MiddleDot(Symbol, Span, Span, Symbol, Span),
     /// Invalid
-    Error,
+    Error(ErrorGuaranteed),
 }
 
 impl<'a> Parser<'a> {
@@ -1008,7 +1008,7 @@ impl<'a> Parser<'a> {
                             self.mk_expr_tuple_field_access(lo, ident1_span, base, sym1, None);
                         self.mk_expr_tuple_field_access(lo, ident2_span, base1, sym2, suffix)
                     }
-                    DestructuredFloat::Error => base,
+                    DestructuredFloat::Error(_) => base,
                 })
             }
             _ => {
@@ -1018,7 +1018,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn error_unexpected_after_dot(&self) {
+    fn error_unexpected_after_dot(&self) -> ErrorGuaranteed {
         let actual = pprust::token_to_string(&self.token);
         let span = self.token.span;
         let sm = self.psess.source_map();
@@ -1028,17 +1028,19 @@ impl<'a> Parser<'a> {
             }
             _ => (span, actual),
         };
-        self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual });
+        self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual })
     }
 
-    // We need an identifier or integer, but the next token is a float.
-    // Break the float into components to extract the identifier or integer.
+    /// We need an identifier or integer, but the next token is a float.
+    /// Break the float into components to extract the identifier or integer.
+    ///
+    /// See also [`TokenKind::break_two_token_op`] which does similar splitting of `>>` into `>`.
+    //
     // FIXME: With current `TokenCursor` it's hard to break tokens into more than 2
-    // parts unless those parts are processed immediately. `TokenCursor` should either
-    // support pushing "future tokens" (would be also helpful to `break_and_eat`), or
-    // we should break everything including floats into more basic proc-macro style
-    // tokens in the lexer (probably preferable).
-    // See also `TokenKind::break_two_token_op` which does similar splitting of `>>` into `>`.
+    //  parts unless those parts are processed immediately. `TokenCursor` should either
+    //  support pushing "future tokens" (would be also helpful to `break_and_eat`), or
+    //  we should break everything including floats into more basic proc-macro style
+    //  tokens in the lexer (probably preferable).
     fn break_up_float(&self, float: Symbol, span: Span) -> DestructuredFloat {
         #[derive(Debug)]
         enum FloatComponent {
@@ -1078,34 +1080,30 @@ impl<'a> Parser<'a> {
                 DestructuredFloat::Single(Symbol::intern(i), span)
             }
             // 1.
-            [IdentLike(i), Punct('.')] => {
-                let (ident_span, dot_span) = if can_take_span_apart() {
-                    let (span, ident_len) = (span.data(), BytePos::from_usize(i.len()));
-                    let ident_span = span.with_hi(span.lo + ident_len);
-                    let dot_span = span.with_lo(span.lo + ident_len);
-                    (ident_span, dot_span)
+            [IdentLike(left), Punct('.')] => {
+                let (left_span, dot_span) = if can_take_span_apart() {
+                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
+                    let dot_span = span.with_lo(left_span.hi());
+                    (left_span, dot_span)
                 } else {
                     (span, span)
                 };
-                let symbol = Symbol::intern(i);
-                DestructuredFloat::TrailingDot(symbol, ident_span, dot_span)
+                let left = Symbol::intern(left);
+                DestructuredFloat::TrailingDot(left, left_span, dot_span)
             }
             // 1.2 | 1.2e3
-            [IdentLike(i1), Punct('.'), IdentLike(i2)] => {
-                let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() {
-                    let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len()));
-                    let ident1_span = span.with_hi(span.lo + ident1_len);
-                    let dot_span = span
-                        .with_lo(span.lo + ident1_len)
-                        .with_hi(span.lo + ident1_len + BytePos(1));
-                    let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1));
-                    (ident1_span, dot_span, ident2_span)
+            [IdentLike(left), Punct('.'), IdentLike(right)] => {
+                let (left_span, dot_span, right_span) = if can_take_span_apart() {
+                    let left_span = span.with_hi(span.lo() + BytePos::from_usize(left.len()));
+                    let dot_span = span.with_lo(left_span.hi()).with_hi(left_span.hi() + BytePos(1));
+                    let right_span = span.with_lo(dot_span.hi());
+                    (left_span, dot_span, right_span)
                 } else {
                     (span, span, span)
                 };
-                let symbol1 = Symbol::intern(i1);
-                let symbol2 = Symbol::intern(i2);
-                DestructuredFloat::MiddleDot(symbol1, ident1_span, dot_span, symbol2, ident2_span)
+                let left = Symbol::intern(left);
+                let right = Symbol::intern(right);
+                DestructuredFloat::MiddleDot(left, left_span, dot_span, right, right_span)
             }
             // 1e+ | 1e- (recovered)
             [IdentLike(_), Punct('+' | '-')] |
@@ -1116,8 +1114,8 @@ impl<'a> Parser<'a> {
             // 1.2e+3 | 1.2e-3
             [IdentLike(_), Punct('.'), IdentLike(_), Punct('+' | '-'), IdentLike(_)] => {
                 // See the FIXME about `TokenCursor` above.
-                self.error_unexpected_after_dot();
-                DestructuredFloat::Error
+                let guar = self.error_unexpected_after_dot();
+                DestructuredFloat::Error(guar)
             }
             _ => panic!("unexpected components in a float token: {components:?}"),
         }
@@ -1183,7 +1181,7 @@ impl<'a> Parser<'a> {
                                 fields.insert(start_idx, Ident::new(symbol2, span2));
                                 fields.insert(start_idx, Ident::new(symbol1, span1));
                             }
-                            DestructuredFloat::Error => {
+                            DestructuredFloat::Error(_) => {
                                 trailing_dot = None;
                                 fields.insert(start_idx, Ident::new(symbol, self.prev_token.span));
                             }
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index dd1cc75c7ff..66019ffbc0a 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -607,9 +607,6 @@ impl<'a> Parser<'a> {
         let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
         let whole_span = lo.to(self.prev_token.span);
         if let ast::Const::Yes(span) = constness {
-            // If we ever start to allow `const fn()`, then update
-            // feature gating for `#![feature(const_extern_fn)]` to
-            // cover it.
             self.dcx().emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
         }
         if let Some(ast::CoroutineKind::Async { span, .. }) = coroutine_kind {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index a985ecb019a..01052c60e94 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1012,12 +1012,12 @@ pub(crate) struct FeatureStableTwice {
 
 #[derive(Diagnostic)]
 #[diag(passes_feature_previously_declared, code = E0711)]
-pub(crate) struct FeaturePreviouslyDeclared<'a, 'b> {
+pub(crate) struct FeaturePreviouslyDeclared<'a> {
     #[primary_span]
     pub span: Span,
     pub feature: Symbol,
     pub declared: &'a str,
-    pub prev_declared: &'b str,
+    pub prev_declared: &'a str,
 }
 
 pub(crate) struct BreakNonLoop<'a> {
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index c11562ae39e..af932bd69ab 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -9,7 +9,6 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::Session;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::{BytePos, Span};
 use Context::*;
@@ -64,8 +63,7 @@ impl fmt::Display for BreakContextKind {
 }
 
 #[derive(Clone)]
-struct CheckLoopVisitor<'a, 'tcx> {
-    sess: &'a Session,
+struct CheckLoopVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     // Keep track of a stack of contexts, so that suggestions
     // are not made for contexts where it would be incorrect,
@@ -76,12 +74,8 @@ struct CheckLoopVisitor<'a, 'tcx> {
 }
 
 fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
-    let mut check = CheckLoopVisitor {
-        sess: tcx.sess,
-        tcx,
-        cx_stack: vec![Normal],
-        block_breaks: Default::default(),
-    };
+    let mut check =
+        CheckLoopVisitor { tcx, cx_stack: vec![Normal], block_breaks: Default::default() };
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut check);
     check.report_outside_loop_error();
 }
@@ -90,7 +84,7 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_loops, ..*providers };
 }
 
-impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
+impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
     type NestedFilter = nested_filter::OnlyBodies;
 
     fn nested_visit_map(&mut self) -> Self::Map {
@@ -129,7 +123,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
             hir::ExprKind::If(cond, then, else_opt) => {
                 self.visit_expr(cond);
 
-                let get_block = |ck_loop: &CheckLoopVisitor<'a, 'hir>,
+                let get_block = |ck_loop: &CheckLoopVisitor<'hir>,
                                  expr: &hir::Expr<'hir>|
                  -> Option<&hir::Block<'hir>> {
                     if let hir::ExprKind::Block(b, None) = expr.kind
@@ -213,7 +207,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                     Ok(loop_id) => Some(loop_id),
                     Err(hir::LoopIdError::OutsideLoopScope) => None,
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
-                        self.sess.dcx().emit_err(UnlabeledCfInWhileCondition {
+                        self.tcx.dcx().emit_err(UnlabeledCfInWhileCondition {
                             span: e.span,
                             cf_type: "break",
                         });
@@ -248,7 +242,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                                     .label
                                     .map_or_else(String::new, |l| format!(" {}", l.ident))
                             );
-                            self.sess.dcx().emit_err(BreakNonLoop {
+                            self.tcx.dcx().emit_err(BreakNonLoop {
                                 span: e.span,
                                 head,
                                 kind: kind.name(),
@@ -280,14 +274,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                 match destination.target_id {
                     Ok(loop_id) => {
                         if let Node::Block(block) = self.tcx.hir_node(loop_id) {
-                            self.sess.dcx().emit_err(ContinueLabeledBlock {
+                            self.tcx.dcx().emit_err(ContinueLabeledBlock {
                                 span: e.span,
                                 block_span: block.span,
                             });
                         }
                     }
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
-                        self.sess.dcx().emit_err(UnlabeledCfInWhileCondition {
+                        self.tcx.dcx().emit_err(UnlabeledCfInWhileCondition {
                             span: e.span,
                             cf_type: "continue",
                         });
@@ -306,10 +300,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
     }
 }
 
-impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
+impl<'hir> CheckLoopVisitor<'hir> {
     fn with_context<F>(&mut self, cx: Context, f: F)
     where
-        F: FnOnce(&mut CheckLoopVisitor<'a, 'hir>),
+        F: FnOnce(&mut CheckLoopVisitor<'hir>),
     {
         self.cx_stack.push(cx);
         f(self);
@@ -326,7 +320,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
         match self.cx_stack[cx_pos] {
             LabeledBlock | Loop(_) => {}
             Closure(closure_span) => {
-                self.sess.dcx().emit_err(BreakInsideClosure {
+                self.tcx.dcx().emit_err(BreakInsideClosure {
                     span,
                     closure_span,
                     name: &br_cx_kind.to_string(),
@@ -343,7 +337,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
                     hir::CoroutineSource::Closure => "closure",
                     hir::CoroutineSource::Fn => "function",
                 };
-                self.sess.dcx().emit_err(BreakInsideCoroutine {
+                self.tcx.dcx().emit_err(BreakInsideCoroutine {
                     span,
                     coroutine_span,
                     name: &br_cx_kind.to_string(),
@@ -366,7 +360,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
                 self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1);
             }
             Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => {
-                self.sess.dcx().emit_err(OutsideLoop {
+                self.tcx.dcx().emit_err(OutsideLoop {
                     spans: vec![span],
                     name: &br_cx_kind.to_string(),
                     is_break: br_cx_kind == BreakContextKind::Break,
@@ -386,7 +380,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
             && self.cx_stack.last() == Some(&LabeledBlock)
             && label.label.is_none()
         {
-            self.sess.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type });
+            self.tcx.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type });
             return true;
         }
         false
@@ -394,7 +388,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
 
     fn report_outside_loop_error(&self) {
         for (s, block) in &self.block_breaks {
-            self.sess.dcx().emit_err(OutsideLoop {
+            self.tcx.dcx().emit_err(OutsideLoop {
                 spans: block.spans.clone(),
                 name: &block.name,
                 is_break: true,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 572f71d7c77..c7078e1a27a 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -852,12 +852,12 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
 ////////////////////////////////////////////////////////////////////////////////
 /// Visitor, used for EffectiveVisibilities table checking
 ////////////////////////////////////////////////////////////////////////////////
-pub struct TestReachabilityVisitor<'tcx, 'a> {
+pub struct TestReachabilityVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     effective_visibilities: &'a EffectiveVisibilities,
 }
 
-impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
+impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
     fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
         if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) {
             let mut error_msg = String::new();
@@ -878,7 +878,7 @@ impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
     }
 }
 
-impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
+impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         self.effective_visibility_diagnostic(item.owner_id.def_id);
 
@@ -1425,12 +1425,12 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
     }
 }
 
-struct PrivateItemsInPublicInterfacesChecker<'tcx, 'a> {
+struct PrivateItemsInPublicInterfacesChecker<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     effective_visibilities: &'a EffectiveVisibilities,
 }
 
-impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> {
+impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
     fn check(
         &self,
         def_id: LocalDefId,
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 599316d0cad..536044298f0 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -19,18 +19,18 @@ impl QueryKeyStringCache {
     }
 }
 
-struct QueryKeyStringBuilder<'p, 'tcx> {
-    profiler: &'p SelfProfiler,
+struct QueryKeyStringBuilder<'a, 'tcx> {
+    profiler: &'a SelfProfiler,
     tcx: TyCtxt<'tcx>,
-    string_cache: &'p mut QueryKeyStringCache,
+    string_cache: &'a mut QueryKeyStringCache,
 }
 
-impl<'p, 'tcx> QueryKeyStringBuilder<'p, 'tcx> {
+impl<'a, 'tcx> QueryKeyStringBuilder<'a, 'tcx> {
     fn new(
-        profiler: &'p SelfProfiler,
+        profiler: &'a SelfProfiler,
         tcx: TyCtxt<'tcx>,
-        string_cache: &'p mut QueryKeyStringCache,
-    ) -> QueryKeyStringBuilder<'p, 'tcx> {
+        string_cache: &'a mut QueryKeyStringCache,
+    ) -> QueryKeyStringBuilder<'a, 'tcx> {
         QueryKeyStringBuilder { profiler, tcx, string_cache }
     }
 
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index d6c58e9d1be..1db31f5b0a7 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -340,4 +340,8 @@ impl ParseSess {
     pub fn dcx(&self) -> DiagCtxtHandle<'_> {
         self.dcx.handle()
     }
+
+    pub fn set_dcx(&mut self, dcx: DiagCtxt) {
+        self.dcx = dcx;
+    }
 }
diff --git a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
index 042a9a14071..762084291a6 100644
--- a/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv8r_none_eabihf.rs
@@ -21,16 +21,16 @@ pub(crate) fn target() -> Target {
             linker: Some("rust-lld".into()),
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
-            // The Cortex-R52 has two variants with respect to floating-point support:
-            // 1. fp-armv8, SP-only, with 16 DP (32 SP) registers
-            // 2. neon-fp-armv8, SP+DP, with 32 DP registers
-            // Use the lesser of these two options as the default, as it will produce code
-            // compatible with either variant.
+            // Armv8-R requires a minimum set of floating-point features equivalent to:
+            // fp-armv8, SP-only, with 16 DP (32 SP) registers
+            // LLVM defines Armv8-R to include these features automatically.
+            //
+            // The Cortex-R52 supports these default features and optionally includes:
+            // neon-fp-armv8, SP+DP, with 32 DP registers
             //
             // Reference:
             // Arm Cortex-R52 Processor Technical Reference Manual
             // - Chapter 15 Advanced SIMD and floating-point support
-            features: "+fp-armv8,-fp64,-d32".into(),
             max_atomic_width: Some(64),
             emit_debug_gdb_scripts: false,
             // GCC defaults to 8 for arm-none here.
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
index d33c7af92c6..0bcbf655bd8 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{base, Target, TargetOptions};
+use crate::spec::{base, CodeModel, Target, TargetOptions};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -13,6 +13,7 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         arch: "loongarch64".into(),
         options: TargetOptions {
+            code_model: Some(CodeModel::Medium),
             cpu: "generic".into(),
             features: "+f,+d".into(),
             llvm_abiname: "lp64d".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
index 5540e71ad4f..223d979a06f 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{base, Target, TargetOptions};
+use crate::spec::{base, CodeModel, Target, TargetOptions};
 
 pub(crate) fn target() -> Target {
     Target {
@@ -13,6 +13,7 @@ pub(crate) fn target() -> Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
         arch: "loongarch64".into(),
         options: TargetOptions {
+            code_model: Some(CodeModel::Medium),
             cpu: "generic".into(),
             features: "+f,+d".into(),
             llvm_abiname: "lp64d".into(),
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
index 56285190268..db527c8b636 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none.rs
@@ -23,7 +23,7 @@ pub(crate) fn target() -> Target {
             max_atomic_width: Some(64),
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
-            code_model: Some(CodeModel::Small),
+            code_model: Some(CodeModel::Medium),
             ..Default::default()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
index 7e57715ce7a..221ca02fe3e 100644
--- a/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/targets/loongarch64_unknown_none_softfloat.rs
@@ -24,7 +24,7 @@ pub(crate) fn target() -> Target {
             max_atomic_width: Some(64),
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
-            code_model: Some(CodeModel::Small),
+            code_model: Some(CodeModel::Medium),
             ..Default::default()
         },
     }
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 38d06f53fa6..b8ac83e8f96 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -842,14 +842,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         lifetime: Region<'tcx>,
         add_lt_suggs: &mut Vec<(Span, String)>,
     ) -> String {
-        struct LifetimeReplaceVisitor<'tcx, 'a> {
+        struct LifetimeReplaceVisitor<'a, 'tcx> {
             tcx: TyCtxt<'tcx>,
             needle: hir::LifetimeName,
             new_lt: &'a str,
             add_lt_suggs: &'a mut Vec<(Span, String)>,
         }
 
-        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'tcx, '_> {
+        impl<'hir, 'tcx> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_, 'tcx> {
             fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
                 if lt.res == self.needle {
                     self.add_lt_suggs.push(lt.suggestion(self.new_lt));
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 9aa6d1f3d46..752ef729113 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -344,7 +344,8 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
 
     write!(
         w,
-        " {} for {}",
+        " {}{} for {}",
+        tcx.impl_polarity(impl_def_id).as_str(),
         trait_ref.print_only_trait_path(),
         tcx.type_of(impl_def_id).instantiate_identity()
     )
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 b13aede509a..e2796c76412 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -61,9 +61,9 @@ pub enum CoroutineInteriorOrUpvar {
 // This type provides a uniform interface to retrieve data on coroutines, whether it originated from
 // the local crate being compiled or from a foreign crate.
 #[derive(Debug)]
-struct CoroutineData<'tcx, 'a>(&'a TypeckResults<'tcx>);
+struct CoroutineData<'a, 'tcx>(&'a TypeckResults<'tcx>);
 
-impl<'tcx, 'a> CoroutineData<'tcx, 'a> {
+impl<'a, 'tcx> CoroutineData<'a, 'tcx> {
     /// Try to get information about variables captured by the coroutine that matches a type we are
     /// looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
     /// meet an obligation
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index f1b524d1325..525fba69a87 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -25,7 +25,7 @@ use crate::traits::{
 };
 
 #[extension(pub trait QueryNormalizeExt<'tcx>)]
-impl<'cx, 'tcx> At<'cx, 'tcx> {
+impl<'a, 'tcx> At<'a, 'tcx> {
     /// Normalize `value` in the context of the inference context,
     /// yielding a resulting type, or an error if `value` cannot be
     /// normalized. If you don't care about regions, you should prefer
@@ -160,9 +160,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
     }
 }
 
-struct QueryNormalizer<'cx, 'tcx> {
-    infcx: &'cx InferCtxt<'tcx>,
-    cause: &'cx ObligationCause<'tcx>,
+struct QueryNormalizer<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
+    cause: &'a ObligationCause<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     obligations: Vec<PredicateObligation<'tcx>>,
     cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
@@ -170,7 +170,7 @@ struct QueryNormalizer<'cx, 'tcx> {
     universes: Vec<Option<ty::UniverseIndex>>,
 }
 
-impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> {
+impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
     type Error = NoSolution;
 
     fn cx(&self) -> TyCtxt<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 0fb13799e67..99445d03965 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -332,8 +332,8 @@ pub fn with_replaced_escaping_bound_vars<
     }
 }
 
-pub struct BoundVarReplacer<'me, 'tcx> {
-    infcx: &'me InferCtxt<'tcx>,
+pub struct BoundVarReplacer<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
     // These three maps track the bound variable that were replaced by placeholders. It might be
     // nice to remove these since we already have the `kind` in the placeholder; we really just need
     // the `var` (but we *could* bring that into scope if we were to track them as we pass them).
@@ -345,15 +345,15 @@ pub struct BoundVarReplacer<'me, 'tcx> {
     current_index: ty::DebruijnIndex,
     // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
     // we don't actually create a universe until we see a bound var we have to replace.
-    universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
+    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
 }
 
-impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
+impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> {
     /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
     /// use a binding level above `universe_indices.len()`, we fail.
     pub fn replace_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
-        infcx: &'me InferCtxt<'tcx>,
-        universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
+        infcx: &'a InferCtxt<'tcx>,
+        universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
         value: T,
     ) -> (
         T,
@@ -479,22 +479,22 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
 }
 
 /// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came.
-pub struct PlaceholderReplacer<'me, 'tcx> {
-    infcx: &'me InferCtxt<'tcx>,
+pub struct PlaceholderReplacer<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
     mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
     mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
     mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
-    universe_indices: &'me [Option<ty::UniverseIndex>],
+    universe_indices: &'a [Option<ty::UniverseIndex>],
     current_index: ty::DebruijnIndex,
 }
 
-impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
+impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> {
     pub fn replace_placeholders<T: TypeFoldable<TyCtxt<'tcx>>>(
-        infcx: &'me InferCtxt<'tcx>,
+        infcx: &'a InferCtxt<'tcx>,
         mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
         mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
         mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
-        universe_indices: &'me [Option<ty::UniverseIndex>],
+        universe_indices: &'a [Option<ty::UniverseIndex>],
         value: T,
     ) -> T {
         let mut replacer = PlaceholderReplacer {
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index c3fd771b797..b5ce465a173 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -175,7 +175,7 @@ pub(crate) mod rustc {
     use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
     use rustc_span::ErrorGuaranteed;
     use rustc_target::abi::{
-        FieldIdx, FieldsShape, Layout, Size, TyAndLayout, VariantIdx, Variants,
+        FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
     };
 
     use super::Tree;
@@ -319,11 +319,17 @@ pub(crate) mod rustc {
             assert!(def.is_enum());
 
             // Computes the variant of a given index.
-            let layout_of_variant = |index| {
+            let layout_of_variant = |index, encoding: Option<TagEncoding<VariantIdx>>| {
                 let tag = cx.tcx.tag_for_variant((cx.tcx.erase_regions(ty), index));
                 let variant_def = Def::Variant(def.variant(index));
                 let variant_layout = ty_variant(cx, (ty, layout), index);
-                Self::from_variant(variant_def, tag, (ty, variant_layout), layout.size, cx)
+                Self::from_variant(
+                    variant_def,
+                    tag.map(|tag| (tag, index, encoding.unwrap())),
+                    (ty, variant_layout),
+                    layout.size,
+                    cx,
+                )
             };
 
             // We consider three kinds of enums, each demanding a different
@@ -345,9 +351,9 @@ pub(crate) mod rustc {
                 Variants::Single { index } => {
                     // `Variants::Single` on enums with variants denotes that
                     // the enum delegates its layout to the variant at `index`.
-                    layout_of_variant(*index)
+                    layout_of_variant(*index, None)
                 }
-                Variants::Multiple { tag_field, .. } => {
+                Variants::Multiple { tag, tag_encoding, tag_field, .. } => {
                     // `Variants::Multiple` denotes an enum with multiple
                     // variants. The layout of such an enum is the disjunction
                     // of the layouts of its tagged variants.
@@ -359,7 +365,7 @@ pub(crate) mod rustc {
                     let variants = def.discriminants(cx.tcx()).try_fold(
                         Self::uninhabited(),
                         |variants, (idx, ref discriminant)| {
-                            let variant = layout_of_variant(idx)?;
+                            let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?;
                             Result::<Self, Err>::Ok(variants.or(variant))
                         },
                     )?;
@@ -380,7 +386,7 @@ pub(crate) mod rustc {
         /// `0`.
         fn from_variant(
             def: Def<'tcx>,
-            tag: Option<ScalarInt>,
+            tag: Option<(ScalarInt, VariantIdx, TagEncoding<VariantIdx>)>,
             (ty, layout): (Ty<'tcx>, Layout<'tcx>),
             total_size: Size,
             cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
@@ -400,9 +406,18 @@ pub(crate) mod rustc {
             let mut struct_tree = Self::def(def);
 
             // If a `tag` is provided, place it at the start of the layout.
-            if let Some(tag) = tag {
-                size += tag.size();
-                struct_tree = struct_tree.then(Self::from_tag(tag, cx.tcx));
+            if let Some((tag, index, encoding)) = &tag {
+                match encoding {
+                    TagEncoding::Direct => {
+                        size += tag.size();
+                    }
+                    TagEncoding::Niche { niche_variants, .. } => {
+                        if !niche_variants.contains(index) {
+                            size += tag.size();
+                        }
+                    }
+                }
+                struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx));
             }
 
             // Append the fields, in memory order, to the layout.
diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
index 2223aca28d1..8378237fe2f 100644
--- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs
+++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
@@ -28,7 +28,7 @@ pub(super) fn sanity_check_layout<'tcx>(
     }
 
     /// Yields non-ZST fields of the type
-    fn non_zst_fields<'tcx, 'a>(
+    fn non_zst_fields<'a, 'tcx>(
         cx: &'a LayoutCx<'tcx, TyCtxt<'tcx>>,
         layout: &'a TyAndLayout<'tcx>,
     ) -> impl Iterator<Item = (Size, TyAndLayout<'tcx>)> + 'a {
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index b30346ffc53..e4bf1e1379c 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -196,6 +196,17 @@ impl fmt::Display for ImplPolarity {
     }
 }
 
+impl ImplPolarity {
+    /// The polarity marker in front of the impl trait ref if applicable.
+    pub fn as_str(self) -> &'static str {
+        match self {
+            Self::Positive => "",
+            Self::Negative => "!",
+            Self::Reservation => "",
+        }
+    }
+}
+
 /// Polarity for a trait predicate. May either be negative or positive.
 /// Distinguished from [`ImplPolarity`] since we never compute goals with
 /// "reservation" level.