about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2024-11-15 06:29:30 +0000
committerGitHub <noreply@github.com>2024-11-15 06:29:30 +0000
commit3e71ed157037d9f77ff5ca73b015fe14e2b48792 (patch)
tree3efe043e15a6bd9518d8d833eaac2c8f73649f39 /compiler
parent7213a278eb67190fbceac4b4d948906ab49ff635 (diff)
parentb9116571ff44029f457bf6a60c7866fb28267a83 (diff)
Merge pull request #4034 from rust-lang/rustup-2024-11-15
Automatic Rustup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc/Cargo.toml1
-rw-r--r--compiler/rustc_ast/src/ast.rs35
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs1
-rw-r--r--compiler/rustc_ast/src/visit.rs14
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs1
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs16
-rw-r--r--compiler/rustc_attr/src/builtin.rs68
-rw-r--r--compiler/rustc_baked_icu_data/Cargo.toml7
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs368
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs71
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs137
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs13
-rw-r--r--compiler/rustc_codegen_gcc/src/archive.rs25
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs130
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/debuginfo.rs1
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs78
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs20
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs15
-rw-r--r--compiler/rustc_data_structures/Cargo.toml9
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/marker.rs341
-rw-r--r--compiler/rustc_data_structures/src/owned_slice.rs2
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs21
-rw-r--r--compiler/rustc_data_structures/src/sync.rs282
-rw-r--r--compiler/rustc_data_structures/src/sync/freeze.rs5
-rw-r--r--compiler/rustc_data_structures/src/sync/lock.rs309
-rw-r--r--compiler/rustc_data_structures/src/sync/parallel.rs236
-rw-r--r--compiler/rustc_data_structures/src/sync/vec.rs21
-rw-r--r--compiler/rustc_data_structures/src/sync/worker_local.rs44
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml5
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs7
-rw-r--r--compiler/rustc_error_messages/Cargo.toml5
-rw-r--r--compiler/rustc_error_messages/src/lib.rs27
-rw-r--r--compiler/rustc_errors/Cargo.toml5
-rw-r--r--compiler/rustc_errors/src/emitter.rs716
-rw-r--r--compiler/rustc_errors/src/json.rs7
-rw-r--r--compiler/rustc_errors/src/lib.rs19
-rw-r--r--compiler/rustc_errors/src/tests.rs5
-rw-r--r--compiler/rustc_expand/src/base.rs4
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs98
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs95
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs64
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs4
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs136
-rw-r--r--compiler/rustc_interface/Cargo.toml10
-rw-r--r--compiler/rustc_interface/src/passes.rs2
-rw-r--r--compiler/rustc_interface/src/util.rs14
-rw-r--r--compiler/rustc_lint/messages.ftl1
-rw-r--r--compiler/rustc_lint/src/builtin.rs18
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs54
-rw-r--r--compiler/rustc_lint/src/lints.rs3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp15
-rw-r--r--compiler/rustc_metadata/src/creader.rs3
-rw-r--r--compiler/rustc_metadata/src/locator.rs84
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs4
-rw-r--r--compiler/rustc_middle/Cargo.toml3
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs23
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs11
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs18
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs2
-rw-r--r--compiler/rustc_middle/src/thir.rs17
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs59
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs36
-rw-r--r--compiler/rustc_middle/src/ty/context.rs10
-rw-r--r--compiler/rustc_middle/src/ty/context/tls.rs10
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs2
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/list.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs20
-rw-r--r--compiler/rustc_mir_build/src/build/matches/match_pair.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs14
-rw-r--r--compiler/rustc_mir_build/src/errors.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs56
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs62
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs42
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs7
-rw-r--r--compiler/rustc_mir_transform/messages.ftl2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs100
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs10
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs6
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs204
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs34
-rw-r--r--compiler/rustc_monomorphize/messages.ftl11
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs45
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs14
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs2
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/abi_check.rs (renamed from compiler/rustc_monomorphize/src/collector/abi_check.rs)101
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/mod.rs23
-rw-r--r--compiler/rustc_monomorphize/src/mono_checks/move_check.rs (renamed from compiler/rustc_monomorphize/src/collector/move_check.rs)111
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs2
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs4
-rw-r--r--compiler/rustc_parse/src/parser/tests.rs1231
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/check_attr.rs27
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--compiler/rustc_passes/src/stability.rs199
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs20
-rw-r--r--compiler/rustc_query_impl/Cargo.toml5
-rw-r--r--compiler/rustc_query_system/Cargo.toml7
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs13
-rw-r--r--compiler/rustc_query_system/src/query/job.rs49
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs19
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs9
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs29
-rw-r--r--compiler/rustc_session/src/config.rs138
-rw-r--r--compiler/rustc_session/src/filesearch.rs39
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/search_paths.rs59
-rw-r--r--compiler/rustc_session/src/session.rs34
-rw-r--r--compiler/rustc_span/src/hygiene.rs14
-rw-r--r--compiler/rustc_span/src/lib.rs18
-rw-r--r--compiler/rustc_span/src/source_map.rs2
-rw-r--r--compiler/rustc_span/src/span_encoding.rs14
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs11
-rw-r--r--compiler/rustc_target/src/target_features.rs34
-rw-r--r--compiler/rustc_trait_selection/messages.ftl6
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs139
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs52
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs225
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs2
160 files changed, 4596 insertions, 2904 deletions
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index a2fc9d5c408..f85c30ac7ec 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -31,5 +31,4 @@ jemalloc = ['dep:jemalloc-sys']
 llvm = ['rustc_driver_impl/llvm']
 max_level_info = ['rustc_driver_impl/max_level_info']
 rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
-rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler']
 # tidy-alphabetical-end
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 997c44cffff..5f71fb97d76 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1194,7 +1194,7 @@ impl Expr {
     ///
     /// Does not ensure that the path resolves to a const param, the caller should check this.
     pub fn is_potential_trivial_const_arg(&self, strip_identity_block: bool) -> bool {
-        let this = if strip_identity_block { self.maybe_unwrap_block().1 } else { self };
+        let this = if strip_identity_block { self.maybe_unwrap_block() } else { self };
 
         if let ExprKind::Path(None, path) = &this.kind
             && path.is_potential_trivial_const_arg()
@@ -1206,14 +1206,41 @@ impl Expr {
     }
 
     /// Returns an expression with (when possible) *one* outter brace removed
-    pub fn maybe_unwrap_block(&self) -> (bool, &Expr) {
+    pub fn maybe_unwrap_block(&self) -> &Expr {
         if let ExprKind::Block(block, None) = &self.kind
             && let [stmt] = block.stmts.as_slice()
             && let StmtKind::Expr(expr) = &stmt.kind
         {
-            (true, expr)
+            expr
         } else {
-            (false, self)
+            self
+        }
+    }
+
+    /// Determines whether this expression is a macro call optionally wrapped in braces . If
+    /// `already_stripped_block` is set then we do not attempt to peel off a layer of braces.
+    ///
+    /// Returns the [`NodeId`] of the macro call and whether a layer of braces has been peeled
+    /// either before, or part of, this function.
+    pub fn optionally_braced_mac_call(
+        &self,
+        already_stripped_block: bool,
+    ) -> Option<(bool, NodeId)> {
+        match &self.kind {
+            ExprKind::Block(block, None)
+                if let [stmt] = &*block.stmts
+                    && !already_stripped_block =>
+            {
+                match &stmt.kind {
+                    StmtKind::MacCall(_) => Some((true, stmt.id)),
+                    StmtKind::Expr(expr) if let ExprKind::MacCall(_) = &expr.kind => {
+                        Some((true, expr.id))
+                    }
+                    _ => None,
+                }
+            }
+            ExprKind::MacCall(_) => Some((already_stripped_block, self.id)),
+            _ => None,
         }
     }
 
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index d5c2bc1c7f6..0b4bfc0b36a 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -38,7 +38,6 @@ pub enum TokenTree {
 }
 
 // Ensure all fields of `TokenTree` are `DynSend` and `DynSync`.
-#[cfg(parallel_compiler)]
 fn _dummy()
 where
     Token: sync::DynSend + sync::DynSync,
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 2f8115441de..58497d70a24 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -200,8 +200,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) -> Self::Result {
         walk_param_bound(self, bounds)
     }
-    fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) {
-        walk_precise_capturing_arg(self, arg);
+    fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) -> Self::Result {
+        walk_precise_capturing_arg(self, arg)
     }
     fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) -> Self::Result {
         walk_poly_trait_ref(self, t)
@@ -730,14 +730,10 @@ pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericB
 pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>(
     visitor: &mut V,
     arg: &'a PreciseCapturingArg,
-) {
+) -> V::Result {
     match arg {
-        PreciseCapturingArg::Lifetime(lt) => {
-            visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg);
-        }
-        PreciseCapturingArg::Arg(path, id) => {
-            visitor.visit_path(path, *id);
-        }
+        PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg),
+        PreciseCapturingArg::Arg(path, id) => visitor.visit_path(path, *id),
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 3acca94a54b..215e6d84d0f 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -45,6 +45,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     | asm::InlineAsmArch::X86_64
                     | asm::InlineAsmArch::Arm
                     | asm::InlineAsmArch::AArch64
+                    | asm::InlineAsmArch::Arm64EC
                     | asm::InlineAsmArch::RiscV32
                     | asm::InlineAsmArch::RiscV64
                     | asm::InlineAsmArch::LoongArch64
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index d646150a620..be6f2c152a4 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -204,6 +204,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     "meant for internal use only" {
                         keyword => rustdoc_internals
                         fake_variadic => rustdoc_internals
+                        search_unbox => rustdoc_internals
                     }
                 );
             }
@@ -522,9 +523,18 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
         "consider removing `for<...>`"
     );
     gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
-    for &span in spans.get(&sym::yield_expr).iter().copied().flatten() {
-        if !span.at_least_rust_2024() {
-            gate!(&visitor, coroutines, span, "yield syntax is experimental");
+    // yield can be enabled either by `coroutines` or `gen_blocks`
+    if let Some(spans) = spans.get(&sym::yield_expr) {
+        for span in spans {
+            if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines))
+                && (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
+            {
+                #[allow(rustc::untranslatable_diagnostic)]
+                // Don't know which of the two features to include in the
+                // error message, so I am arbitrarily picking one.
+                feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental")
+                    .emit();
+            }
         }
     }
     gate_all!(gen_blocks, "gen blocks are experimental");
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 2753ac529d1..94f9727eb7f 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -16,9 +16,9 @@ use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
 use rustc_session::parse::feature_err;
 use rustc_session::{RustcVersion, Session};
+use rustc_span::Span;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{Symbol, kw, sym};
-use rustc_span::{DUMMY_SP, Span};
 
 use crate::fluent_generated;
 use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -92,9 +92,7 @@ impl Stability {
 #[derive(HashStable_Generic)]
 pub struct ConstStability {
     pub level: StabilityLevel,
-    /// This can be `None` for functions that do not have an explicit const feature.
-    /// We still track them for recursive const stability checks.
-    pub feature: Option<Symbol>,
+    pub feature: Symbol,
     /// This is true iff the `const_stable_indirect` attribute is present.
     pub const_stable_indirect: bool,
     /// whether the function has a `#[rustc_promotable]` attribute
@@ -272,22 +270,19 @@ pub fn find_stability(
 
 /// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
 /// attributes in `attrs`. Returns `None` if no stability attributes are found.
-///
-/// `is_const_fn` indicates whether this is a function marked as `const`.
 pub fn find_const_stability(
     sess: &Session,
     attrs: &[Attribute],
     item_sp: Span,
-    is_const_fn: bool,
 ) -> Option<(ConstStability, Span)> {
     let mut const_stab: Option<(ConstStability, Span)> = None;
     let mut promotable = false;
-    let mut const_stable_indirect = None;
+    let mut const_stable_indirect = false;
 
     for attr in attrs {
         match attr.name_or_empty() {
             sym::rustc_promotable => promotable = true,
-            sym::rustc_const_stable_indirect => const_stable_indirect = Some(attr.span),
+            sym::rustc_const_stable_indirect => const_stable_indirect = true,
             sym::rustc_const_unstable => {
                 if const_stab.is_some() {
                     sess.dcx()
@@ -299,7 +294,7 @@ pub fn find_const_stability(
                     const_stab = Some((
                         ConstStability {
                             level,
-                            feature: Some(feature),
+                            feature,
                             const_stable_indirect: false,
                             promotable: false,
                         },
@@ -317,7 +312,7 @@ pub fn find_const_stability(
                     const_stab = Some((
                         ConstStability {
                             level,
-                            feature: Some(feature),
+                            feature,
                             const_stable_indirect: false,
                             promotable: false,
                         },
@@ -340,7 +335,7 @@ pub fn find_const_stability(
             }
         }
     }
-    if const_stable_indirect.is_some() {
+    if const_stable_indirect {
         match &mut const_stab {
             Some((stab, _)) => {
                 if stab.is_const_unstable() {
@@ -351,36 +346,37 @@ pub fn find_const_stability(
                     })
                 }
             }
-            _ => {}
+            _ => {
+                // This function has no const stability attribute, but has `const_stable_indirect`.
+                // We ignore that; unmarked functions are subject to recursive const stability
+                // checks by default so we do carry out the user's intent.
+            }
         }
     }
-    // Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const
-    // fn` get *some* marker, since we are a staged_api crate and therefore will do recursive const
-    // stability checks for them. We need to do this because the default for whether an unmarked
-    // function enforces recursive stability differs between staged-api crates and force-unmarked
-    // crates: in force-unmarked crates, only functions *explicitly* marked `const_stable_indirect`
-    // enforce recursive stability. Therefore when `lookup_const_stability` is `None`, we have to
-    // assume the function does not have recursive stability. All functions that *do* have recursive
-    // stability must explicitly record this, and so that's what we do for all `const fn` in a
-    // staged_api crate.
-    if (is_const_fn || const_stable_indirect.is_some()) && const_stab.is_none() {
-        let c = ConstStability {
-            feature: None,
-            const_stable_indirect: const_stable_indirect.is_some(),
-            promotable: false,
-            level: StabilityLevel::Unstable {
-                reason: UnstableReason::Default,
-                issue: None,
-                is_soft: false,
-                implied_by: None,
-            },
-        };
-        const_stab = Some((c, const_stable_indirect.unwrap_or(DUMMY_SP)));
-    }
 
     const_stab
 }
 
+/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate
+/// without the `staged_api` feature.
+pub fn unmarked_crate_const_stab(
+    _sess: &Session,
+    attrs: &[Attribute],
+    regular_stab: Stability,
+) -> ConstStability {
+    assert!(regular_stab.level.is_unstable());
+    // The only attribute that matters here is `rustc_const_stable_indirect`.
+    // We enforce recursive const stability rules for those functions.
+    let const_stable_indirect =
+        attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect);
+    ConstStability {
+        feature: regular_stab.feature,
+        const_stable_indirect,
+        promotable: false,
+        level: regular_stab.level,
+    }
+}
+
 /// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
 /// Returns `None` if no stability attributes are found.
 pub fn find_body_stability(
diff --git a/compiler/rustc_baked_icu_data/Cargo.toml b/compiler/rustc_baked_icu_data/Cargo.toml
index e6cfb4887c9..c35556dcf5b 100644
--- a/compiler/rustc_baked_icu_data/Cargo.toml
+++ b/compiler/rustc_baked_icu_data/Cargo.toml
@@ -8,11 +8,6 @@ edition = "2021"
 icu_list = "1.2"
 icu_locid = "1.2"
 icu_locid_transform = "1.3.2"
-icu_provider = "1.2"
+icu_provider = { version = "1.2", features = ["sync"] }
 zerovec = "0.10.0"
 # tidy-alphabetical-end
-
-[features]
-# tidy-alphabetical-start
-rustc_use_parallel_compiler = ['icu_provider/sync']
-# tidy-alphabetical-end
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index e5b28289faa..454fd14ea74 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -27,7 +27,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{
-    self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
+    self, ClauseKind, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
     suggest_constraining_type_params,
 };
 use rustc_middle::util::CallKind;
@@ -39,6 +39,7 @@ use rustc_span::{BytePos, Span, Symbol};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
 use tracing::{debug, instrument};
 
@@ -201,16 +202,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
                 let mut has_suggest_reborrow = false;
                 if !seen_spans.contains(&move_span) {
-                    if !closure {
-                        self.suggest_ref_or_clone(
-                            mpi,
-                            &mut err,
-                            &mut in_pattern,
-                            move_spans,
-                            moved_place.as_ref(),
-                            &mut has_suggest_reborrow,
-                        );
-                    }
+                    self.suggest_ref_or_clone(
+                        mpi,
+                        &mut err,
+                        &mut in_pattern,
+                        move_spans,
+                        moved_place.as_ref(),
+                        &mut has_suggest_reborrow,
+                        closure,
+                    );
 
                     let msg_opt = CapturedMessageOpt {
                         is_partial_move,
@@ -266,27 +266,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 }
             }
 
-            let opt_name = self.describe_place_with_options(place.as_ref(), DescribePlaceOpt {
-                including_downcast: true,
-                including_tuple_field: true,
-            });
-            let note_msg = match opt_name {
-                Some(name) => format!("`{name}`"),
-                None => "value".to_owned(),
-            };
-            if self.suggest_borrow_fn_like(&mut err, ty, &move_site_vec, &note_msg)
-                || if let UseSpans::FnSelfUse { kind, .. } = use_spans
-                    && let CallKind::FnCall { fn_trait_id, self_ty } = kind
-                    && let ty::Param(_) = self_ty.kind()
-                    && ty == self_ty
-                    && self.infcx.tcx.is_lang_item(fn_trait_id, LangItem::FnOnce)
-                {
-                    // this is a type parameter `T: FnOnce()`, don't suggest `T: FnOnce() + Clone`.
-                    true
-                } else {
-                    false
-                }
-            {
+            if self.param_env.caller_bounds().iter().any(|c| {
+                c.as_trait_clause().is_some_and(|pred| {
+                    pred.skip_binder().self_ty() == ty && self.infcx.tcx.is_fn_trait(pred.def_id())
+                })
+            }) {
                 // Suppress the next suggestion since we don't want to put more bounds onto
                 // something that already has `Fn`-like bounds (or is a closure), so we can't
                 // restrict anyways.
@@ -295,6 +279,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 self.suggest_adding_bounds(&mut err, ty, copy_did, span);
             }
 
+            let opt_name = self.describe_place_with_options(place.as_ref(), DescribePlaceOpt {
+                including_downcast: true,
+                including_tuple_field: true,
+            });
+            let note_msg = match opt_name {
+                Some(name) => format!("`{name}`"),
+                None => "value".to_owned(),
+            };
             if needs_note {
                 if let Some(local) = place.as_local() {
                     let span = self.body.local_decls[local].source_info.span;
@@ -341,6 +333,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         move_spans: UseSpans<'tcx>,
         moved_place: PlaceRef<'tcx>,
         has_suggest_reborrow: &mut bool,
+        moved_or_invoked_closure: bool,
     ) {
         let move_span = match move_spans {
             UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
@@ -428,104 +421,76 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 }
                 let typeck = self.infcx.tcx.typeck(self.mir_def_id());
                 let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
-                let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
+                let (def_id, call_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
                     && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
                 {
-                    (typeck.type_dependent_def_id(parent_expr.hir_id), args, 1)
+                    let def_id = typeck.type_dependent_def_id(parent_expr.hir_id);
+                    (def_id, Some(parent_expr.hir_id), args, 1)
                 } else if let hir::Node::Expr(parent_expr) = parent
                     && let hir::ExprKind::Call(call, args) = parent_expr.kind
                     && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
                 {
-                    (Some(*def_id), args, 0)
+                    (Some(*def_id), Some(call.hir_id), args, 0)
                 } else {
-                    (None, &[][..], 0)
+                    (None, None, &[][..], 0)
                 };
+                let ty = place.ty(self.body, self.infcx.tcx).ty;
 
-                // If the moved value is a mut reference, it is used in a
-                // generic function and it's type is a generic param, it can be
-                // reborrowed to avoid moving.
-                // for example:
-                // struct Y(u32);
-                // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
+                let mut can_suggest_clone = true;
                 if let Some(def_id) = def_id
-                    && self.infcx.tcx.def_kind(def_id).is_fn_like()
                     && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
-                    && let Some(arg) = self
-                        .infcx
-                        .tcx
-                        .fn_sig(def_id)
-                        .skip_binder()
-                        .skip_binder()
-                        .inputs()
-                        .get(pos + offset)
-                    && let ty::Param(_) = arg.kind()
                 {
-                    let place = &self.move_data.move_paths[mpi].place;
-                    let ty = place.ty(self.body, self.infcx.tcx).ty;
-                    if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
+                    // The move occurred as one of the arguments to a function call. Is that
+                    // argument generic? `def_id` can't be a closure here, so using `fn_sig` is fine
+                    let arg_param = if self.infcx.tcx.def_kind(def_id).is_fn_like()
+                        && let sig =
+                            self.infcx.tcx.fn_sig(def_id).instantiate_identity().skip_binder()
+                        && let Some(arg_ty) = sig.inputs().get(pos + offset)
+                        && let ty::Param(arg_param) = arg_ty.kind()
+                    {
+                        Some(arg_param)
+                    } else {
+                        None
+                    };
+
+                    // If the moved value is a mut reference, it is used in a
+                    // generic function and it's type is a generic param, it can be
+                    // reborrowed to avoid moving.
+                    // for example:
+                    // struct Y(u32);
+                    // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
+                    if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind()
+                        && arg_param.is_some()
+                    {
                         *has_suggest_reborrow = true;
                         self.suggest_reborrow(err, expr.span, moved_place);
                         return;
                     }
-                }
 
-                let mut can_suggest_clone = true;
-                if let Some(def_id) = def_id
-                    && let Some(local_def_id) = def_id.as_local()
-                    && let node = self.infcx.tcx.hir_node_by_def_id(local_def_id)
-                    && let Some(fn_sig) = node.fn_sig()
-                    && let Some(ident) = node.ident()
-                    && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
-                    && let Some(arg) = fn_sig.decl.inputs.get(pos + offset)
-                {
-                    let mut is_mut = false;
-                    if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = arg.kind
-                        && let Res::Def(DefKind::TyParam, param_def_id) = path.res
-                        && self
-                            .infcx
-                            .tcx
-                            .predicates_of(def_id)
-                            .instantiate_identity(self.infcx.tcx)
-                            .predicates
-                            .into_iter()
-                            .any(|pred| {
-                                if let ty::ClauseKind::Trait(predicate) = pred.kind().skip_binder()
-                                    && [
-                                        self.infcx.tcx.get_diagnostic_item(sym::AsRef),
-                                        self.infcx.tcx.get_diagnostic_item(sym::AsMut),
-                                        self.infcx.tcx.get_diagnostic_item(sym::Borrow),
-                                        self.infcx.tcx.get_diagnostic_item(sym::BorrowMut),
-                                    ]
-                                    .contains(&Some(predicate.def_id()))
-                                    && let ty::Param(param) = predicate.self_ty().kind()
-                                    && let generics = self.infcx.tcx.generics_of(def_id)
-                                    && let param = generics.type_param(*param, self.infcx.tcx)
-                                    && param.def_id == param_def_id
-                                {
-                                    if [
-                                        self.infcx.tcx.get_diagnostic_item(sym::AsMut),
-                                        self.infcx.tcx.get_diagnostic_item(sym::BorrowMut),
-                                    ]
-                                    .contains(&Some(predicate.def_id()))
-                                    {
-                                        is_mut = true;
-                                    }
-                                    true
-                                } else {
-                                    false
-                                }
-                            })
+                    // If the moved place is used generically by the callee and a reference to it
+                    // would still satisfy any bounds on its type, suggest borrowing.
+                    if let Some(&param) = arg_param
+                        && let Some(generic_args) = call_id.and_then(|id| typeck.node_args_opt(id))
+                        && let Some(ref_mutability) = self.suggest_borrow_generic_arg(
+                            err,
+                            def_id,
+                            generic_args,
+                            param,
+                            moved_place,
+                            pos + offset,
+                            ty,
+                            expr.span,
+                        )
                     {
-                        // The type of the argument corresponding to the expression that got moved
-                        // is a type parameter `T`, which is has a `T: AsRef` obligation.
-                        err.span_suggestion_verbose(
-                            expr.span.shrink_to_lo(),
-                            "borrow the value to avoid moving it",
-                            format!("&{}", if is_mut { "mut " } else { "" }),
-                            Applicability::MachineApplicable,
-                        );
-                        can_suggest_clone = is_mut;
-                    } else {
+                        can_suggest_clone = ref_mutability.is_mut();
+                    } else if let Some(local_def_id) = def_id.as_local()
+                        && let node = self.infcx.tcx.hir_node_by_def_id(local_def_id)
+                        && let Some(fn_decl) = node.fn_decl()
+                        && let Some(ident) = node.ident()
+                        && let Some(arg) = fn_decl.inputs.get(pos + offset)
+                    {
+                        // If we can't suggest borrowing in the call, but the function definition
+                        // is local, instead offer changing the function to borrow that argument.
                         let mut span: MultiSpan = arg.span.into();
                         span.push_span_label(
                             arg.span,
@@ -546,8 +511,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         );
                     }
                 }
-                let place = &self.move_data.move_paths[mpi].place;
-                let ty = place.ty(self.body, self.infcx.tcx).ty;
                 if let hir::Node::Expr(parent_expr) = parent
                     && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind
                     && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) =
@@ -557,6 +520,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans
                 {
                     // We already suggest cloning for these cases in `explain_captures`.
+                } else if moved_or_invoked_closure {
+                    // Do not suggest `closure.clone()()`.
                 } else if let UseSpans::ClosureUse {
                     closure_kind:
                         ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)),
@@ -665,6 +630,113 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         );
     }
 
+    /// If a place is used after being moved as an argument to a function, the function is generic
+    /// in that argument, and a reference to the argument's type would still satisfy the function's
+    /// bounds, suggest borrowing. This covers, e.g., borrowing an `impl Fn()` argument being passed
+    /// in an `impl FnOnce()` position.
+    /// Returns `Some(mutability)` when suggesting to borrow with mutability `mutability`, or `None`
+    /// if no suggestion is made.
+    fn suggest_borrow_generic_arg(
+        &self,
+        err: &mut Diag<'_>,
+        callee_did: DefId,
+        generic_args: ty::GenericArgsRef<'tcx>,
+        param: ty::ParamTy,
+        moved_place: PlaceRef<'tcx>,
+        moved_arg_pos: usize,
+        moved_arg_ty: Ty<'tcx>,
+        place_span: Span,
+    ) -> Option<ty::Mutability> {
+        let tcx = self.infcx.tcx;
+        let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
+        let clauses = tcx.predicates_of(callee_did).instantiate_identity(self.infcx.tcx).predicates;
+
+        // First, is there at least one method on one of `param`'s trait bounds?
+        // This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
+        if !clauses.iter().any(|clause| {
+            clause.as_trait_clause().is_some_and(|tc| {
+                tc.self_ty().skip_binder().is_param(param.index)
+                    && tc.polarity() == ty::PredicatePolarity::Positive
+                    && tcx
+                        .supertrait_def_ids(tc.def_id())
+                        .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
+                        .any(|item| item.fn_has_self_parameter)
+            })
+        }) {
+            return None;
+        }
+
+        // Try borrowing a shared reference first, then mutably.
+        if let Some(mutbl) = [ty::Mutability::Not, ty::Mutability::Mut].into_iter().find(|&mutbl| {
+            let re = self.infcx.tcx.lifetimes.re_erased;
+            let ref_ty = Ty::new_ref(self.infcx.tcx, re, moved_arg_ty, mutbl);
+
+            // Ensure that substituting `ref_ty` in the callee's signature doesn't break
+            // other inputs or the return type.
+            let new_args = tcx.mk_args_from_iter(generic_args.iter().enumerate().map(
+                |(i, arg)| {
+                    if i == param.index as usize { ref_ty.into() } else { arg }
+                },
+            ));
+            let can_subst = |ty: Ty<'tcx>| {
+                // Normalize before comparing to see through type aliases and projections.
+                let old_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, generic_args);
+                let new_ty = ty::EarlyBinder::bind(ty).instantiate(tcx, new_args);
+                if let Ok(old_ty) = tcx.try_normalize_erasing_regions(self.param_env, old_ty)
+                    && let Ok(new_ty) = tcx.try_normalize_erasing_regions(self.param_env, new_ty)
+                {
+                    old_ty == new_ty
+                } else {
+                    false
+                }
+            };
+            if !can_subst(sig.output())
+                || sig
+                    .inputs()
+                    .iter()
+                    .enumerate()
+                    .any(|(i, &input_ty)| i != moved_arg_pos && !can_subst(input_ty))
+            {
+                return false;
+            }
+
+            // Test the callee's predicates, substituting a reference in for the self ty
+            // in bounds on `param`.
+            clauses.iter().all(|&clause| {
+                let clause_for_ref = clause.kind().map_bound(|kind| match kind {
+                    ClauseKind::Trait(c) if c.self_ty().is_param(param.index) => {
+                        ClauseKind::Trait(c.with_self_ty(tcx, ref_ty))
+                    }
+                    ClauseKind::Projection(c) if c.self_ty().is_param(param.index) => {
+                        ClauseKind::Projection(c.with_self_ty(tcx, ref_ty))
+                    }
+                    _ => kind,
+                });
+                self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
+                    tcx,
+                    ObligationCause::dummy(),
+                    self.param_env,
+                    ty::EarlyBinder::bind(clause_for_ref).instantiate(tcx, generic_args),
+                ))
+            })
+        }) {
+            let place_desc = if let Some(desc) = self.describe_place(moved_place) {
+                format!("`{desc}`")
+            } else {
+                "here".to_owned()
+            };
+            err.span_suggestion_verbose(
+                place_span.shrink_to_lo(),
+                format!("consider {}borrowing {place_desc}", mutbl.mutably_str()),
+                mutbl.ref_prefix_str(),
+                Applicability::MaybeIncorrect,
+            );
+            Some(mutbl)
+        } else {
+            None
+        }
+    }
+
     fn report_use_of_uninitialized(
         &self,
         mpi: MovePathIndex,
@@ -845,74 +917,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
         );
     }
 
-    fn suggest_borrow_fn_like(
-        &self,
-        err: &mut Diag<'_>,
-        ty: Ty<'tcx>,
-        move_sites: &[MoveSite],
-        value_name: &str,
-    ) -> bool {
-        let tcx = self.infcx.tcx;
-
-        // Find out if the predicates show that the type is a Fn or FnMut
-        let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| {
-            if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
-                && pred.self_ty() == ty
-            {
-                if tcx.is_lang_item(pred.def_id(), LangItem::Fn) {
-                    return Some(hir::Mutability::Not);
-                } else if tcx.is_lang_item(pred.def_id(), LangItem::FnMut) {
-                    return Some(hir::Mutability::Mut);
-                }
-            }
-            None
-        };
-
-        // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
-        // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
-        // These types seem reasonably opaque enough that they could be instantiated with their
-        // borrowed variants in a function body when we see a move error.
-        let borrow_level = match *ty.kind() {
-            ty::Param(_) => tcx
-                .explicit_predicates_of(self.mir_def_id().to_def_id())
-                .predicates
-                .iter()
-                .copied()
-                .find_map(find_fn_kind_from_did),
-            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => tcx
-                .explicit_item_super_predicates(def_id)
-                .iter_instantiated_copied(tcx, args)
-                .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))),
-            ty::Closure(_, args) => match args.as_closure().kind() {
-                ty::ClosureKind::Fn => Some(hir::Mutability::Not),
-                ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
-                _ => None,
-            },
-            _ => None,
-        };
-
-        let Some(borrow_level) = borrow_level else {
-            return false;
-        };
-        let sugg = move_sites
-            .iter()
-            .map(|move_site| {
-                let move_out = self.move_data.moves[(*move_site).moi];
-                let moved_place = &self.move_data.move_paths[move_out.path].place;
-                let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
-                let move_span = move_spans.args_or_use();
-                let suggestion = borrow_level.ref_prefix_str().to_owned();
-                (move_span.shrink_to_lo(), suggestion)
-            })
-            .collect();
-        err.multipart_suggestion_verbose(
-            format!("consider {}borrowing {value_name}", borrow_level.mutably_str()),
-            sugg,
-            Applicability::MaybeIncorrect,
-        );
-        true
-    }
-
     /// In a move error that occurs on a call within a loop, we try to identify cases where cloning
     /// the value would lead to a logic error. We infer these cases by seeing if the moved value is
     /// part of the logic to break the loop, either through an explicit `break` or if the expression
diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
index bfd7e83501c..d77c53a3984 100644
--- a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs
@@ -4,15 +4,16 @@
 use std::ops::ControlFlow;
 
 use either::Either;
+use itertools::Itertools as _;
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{Applicability, Diag};
+use rustc_errors::{Diag, Subdiagnostic};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{self, ConstraintCategory, Location};
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
-use rustc_span::Symbol;
+use rustc_trait_selection::errors::impl_trait_overcapture_suggestion;
 
 use crate::MirBorrowckCtxt;
 use crate::borrow_set::BorrowData;
@@ -61,6 +62,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
             // *does* mention. We'll use that for the `+ use<'a>` suggestion below.
             let mut visitor = CheckExplicitRegionMentionAndCollectGenerics {
                 tcx,
+                generics: tcx.generics_of(opaque_def_id),
                 offending_region_idx,
                 seen_opaques: [opaque_def_id].into_iter().collect(),
                 seen_lifetimes: Default::default(),
@@ -83,34 +85,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         "this call may capture more lifetimes than intended, \
                         because Rust 2024 has adjusted the `impl Trait` lifetime capture rules",
                     );
-                    let mut seen_generics: Vec<_> =
-                        visitor.seen_lifetimes.iter().map(ToString::to_string).collect();
-                    // Capture all in-scope ty/const params.
-                    seen_generics.extend(
-                        ty::GenericArgs::identity_for_item(tcx, opaque_def_id)
-                            .iter()
-                            .filter(|arg| {
-                                matches!(
-                                    arg.unpack(),
-                                    ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_)
-                                )
-                            })
-                            .map(|arg| arg.to_string()),
-                    );
-                    if opaque_def_id.is_local() {
-                        diag.span_suggestion_verbose(
-                            tcx.def_span(opaque_def_id).shrink_to_hi(),
-                            "add a precise capturing bound to avoid overcapturing",
-                            format!(" + use<{}>", seen_generics.join(", ")),
-                            Applicability::MaybeIncorrect,
-                        );
+                    let mut captured_args = visitor.seen_lifetimes;
+                    // Add in all of the type and const params, too.
+                    // Ordering here is kinda strange b/c we're walking backwards,
+                    // but we're trying to provide *a* suggestion, not a nice one.
+                    let mut next_generics = Some(visitor.generics);
+                    let mut any_synthetic = false;
+                    while let Some(generics) = next_generics {
+                        for param in &generics.own_params {
+                            if param.kind.is_ty_or_const() {
+                                captured_args.insert(param.def_id);
+                            }
+                            if param.kind.is_synthetic() {
+                                any_synthetic = true;
+                            }
+                        }
+                        next_generics = generics.parent.map(|def_id| tcx.generics_of(def_id));
+                    }
+
+                    if let Some(opaque_def_id) = opaque_def_id.as_local()
+                        && let hir::OpaqueTyOrigin::FnReturn { parent, .. } =
+                            tcx.hir().expect_opaque_ty(opaque_def_id).origin
+                    {
+                        if let Some(sugg) = impl_trait_overcapture_suggestion(
+                            tcx,
+                            opaque_def_id,
+                            parent,
+                            captured_args,
+                        ) {
+                            sugg.add_to_diag(diag);
+                        }
                     } else {
                         diag.span_help(
                             tcx.def_span(opaque_def_id),
                             format!(
                                 "if you can modify this crate, add a precise \
                                 capturing bound to avoid overcapturing: `+ use<{}>`",
-                                seen_generics.join(", ")
+                                if any_synthetic {
+                                    "/* Args */".to_string()
+                                } else {
+                                    captured_args
+                                        .into_iter()
+                                        .map(|def_id| tcx.item_name(def_id))
+                                        .join(", ")
+                                }
                             ),
                         );
                     }
@@ -182,9 +200,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
 
 struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
     tcx: TyCtxt<'tcx>,
+    generics: &'tcx ty::Generics,
     offending_region_idx: usize,
     seen_opaques: FxIndexSet<DefId>,
-    seen_lifetimes: FxIndexSet<Symbol>,
+    seen_lifetimes: FxIndexSet<DefId>,
 }
 
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> {
@@ -214,7 +233,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGen
                 if param.index as usize == self.offending_region_idx {
                     ControlFlow::Break(())
                 } else {
-                    self.seen_lifetimes.insert(param.name);
+                    self.seen_lifetimes.insert(self.generics.region_param(param, self.tcx).def_id);
                     ControlFlow::Continue(())
                 }
             }
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index b686a8cf935..f419c1e776b 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -39,50 +39,10 @@ pub(crate) fn cfg_eval(
     let features = Some(features);
     CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id })
         .configure_annotatable(annotatable)
-        // Since the item itself has already been configured by the `InvocationCollector`,
-        // we know that fold result vector will contain exactly one element.
-        .unwrap()
 }
 
 struct CfgEval<'a>(StripUnconfigured<'a>);
 
-fn flat_map_annotatable(
-    vis: &mut impl MutVisitor,
-    annotatable: Annotatable,
-) -> Option<Annotatable> {
-    match annotatable {
-        Annotatable::Item(item) => vis.flat_map_item(item).pop().map(Annotatable::Item),
-        Annotatable::AssocItem(item, ctxt) => {
-            Some(Annotatable::AssocItem(vis.flat_map_assoc_item(item, ctxt).pop()?, ctxt))
-        }
-        Annotatable::ForeignItem(item) => {
-            vis.flat_map_foreign_item(item).pop().map(Annotatable::ForeignItem)
-        }
-        Annotatable::Stmt(stmt) => {
-            vis.flat_map_stmt(stmt.into_inner()).pop().map(P).map(Annotatable::Stmt)
-        }
-        Annotatable::Expr(mut expr) => {
-            vis.visit_expr(&mut expr);
-            Some(Annotatable::Expr(expr))
-        }
-        Annotatable::Arm(arm) => vis.flat_map_arm(arm).pop().map(Annotatable::Arm),
-        Annotatable::ExprField(field) => {
-            vis.flat_map_expr_field(field).pop().map(Annotatable::ExprField)
-        }
-        Annotatable::PatField(fp) => vis.flat_map_pat_field(fp).pop().map(Annotatable::PatField),
-        Annotatable::GenericParam(param) => {
-            vis.flat_map_generic_param(param).pop().map(Annotatable::GenericParam)
-        }
-        Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
-        Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
-        Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
-        Annotatable::Crate(mut krate) => {
-            vis.visit_crate(&mut krate);
-            Some(Annotatable::Crate(krate))
-        }
-    }
-}
-
 fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
     struct CfgFinder;
 
@@ -106,14 +66,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
         Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
         Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
         Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
-        Annotatable::Arm(arm) => CfgFinder.visit_arm(arm),
-        Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field),
-        Annotatable::PatField(field) => CfgFinder.visit_pat_field(field),
-        Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param),
-        Annotatable::Param(param) => CfgFinder.visit_param(param),
-        Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field),
-        Annotatable::Variant(variant) => CfgFinder.visit_variant(variant),
-        Annotatable::Crate(krate) => CfgFinder.visit_crate(krate),
+        _ => unreachable!(),
     };
     res.is_break()
 }
@@ -123,11 +76,11 @@ impl CfgEval<'_> {
         self.0.configure(node)
     }
 
-    fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
+    fn configure_annotatable(mut self, annotatable: Annotatable) -> Annotatable {
         // Tokenizing and re-parsing the `Annotatable` can have a significant
         // performance impact, so try to avoid it if possible
         if !has_cfg_or_cfg_attr(&annotatable) {
-            return Some(annotatable);
+            return annotatable;
         }
 
         // The majority of parsed attribute targets will never need to have early cfg-expansion
@@ -140,39 +93,6 @@ impl CfgEval<'_> {
         // the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
         // process is lossless, so this process is invisible to proc-macros.
 
-        let parse_annotatable_with: for<'a> fn(&mut Parser<'a>) -> PResult<'a, _> =
-            match annotatable {
-                Annotatable::Item(_) => {
-                    |parser| Ok(Annotatable::Item(parser.parse_item(ForceCollect::Yes)?.unwrap()))
-                }
-                Annotatable::AssocItem(_, AssocCtxt::Trait) => |parser| {
-                    Ok(Annotatable::AssocItem(
-                        parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap(),
-                        AssocCtxt::Trait,
-                    ))
-                },
-                Annotatable::AssocItem(_, AssocCtxt::Impl) => |parser| {
-                    Ok(Annotatable::AssocItem(
-                        parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap(),
-                        AssocCtxt::Impl,
-                    ))
-                },
-                Annotatable::ForeignItem(_) => |parser| {
-                    Ok(Annotatable::ForeignItem(
-                        parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap(),
-                    ))
-                },
-                Annotatable::Stmt(_) => |parser| {
-                    Ok(Annotatable::Stmt(P(parser
-                        .parse_stmt_without_recovery(false, ForceCollect::Yes)?
-                        .unwrap())))
-                },
-                Annotatable::Expr(_) => {
-                    |parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?))
-                }
-                _ => unreachable!(),
-            };
-
         // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
         // to `None`-delimited groups containing the corresponding tokens. This
         // is normally delayed until the proc-macro server actually needs to
@@ -191,19 +111,56 @@ impl CfgEval<'_> {
         // Re-parse the tokens, setting the `capture_cfg` flag to save extra information
         // to the captured `AttrTokenStream` (specifically, we capture
         // `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
+        //
+        // After that we have our re-parsed `AttrTokenStream`, recursively configuring
+        // our attribute target will correctly configure the tokens as well.
         let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None);
         parser.capture_cfg = true;
-        match parse_annotatable_with(&mut parser) {
-            Ok(a) => annotatable = a,
+        let res: PResult<'_, Annotatable> = try {
+            match annotatable {
+                Annotatable::Item(_) => {
+                    let item = parser.parse_item(ForceCollect::Yes)?.unwrap();
+                    Annotatable::Item(self.flat_map_item(item).pop().unwrap())
+                }
+                Annotatable::AssocItem(_, AssocCtxt::Trait) => {
+                    let item = parser.parse_trait_item(ForceCollect::Yes)?.unwrap().unwrap();
+                    Annotatable::AssocItem(
+                        self.flat_map_assoc_item(item, AssocCtxt::Trait).pop().unwrap(),
+                        AssocCtxt::Trait,
+                    )
+                }
+                Annotatable::AssocItem(_, AssocCtxt::Impl) => {
+                    let item = parser.parse_impl_item(ForceCollect::Yes)?.unwrap().unwrap();
+                    Annotatable::AssocItem(
+                        self.flat_map_assoc_item(item, AssocCtxt::Impl).pop().unwrap(),
+                        AssocCtxt::Impl,
+                    )
+                }
+                Annotatable::ForeignItem(_) => {
+                    let item = parser.parse_foreign_item(ForceCollect::Yes)?.unwrap().unwrap();
+                    Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
+                }
+                Annotatable::Stmt(_) => {
+                    let stmt =
+                        parser.parse_stmt_without_recovery(false, ForceCollect::Yes)?.unwrap();
+                    Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap()))
+                }
+                Annotatable::Expr(_) => {
+                    let mut expr = parser.parse_expr_force_collect()?;
+                    self.visit_expr(&mut expr);
+                    Annotatable::Expr(expr)
+                }
+                _ => unreachable!(),
+            }
+        };
+
+        match res {
+            Ok(ann) => ann,
             Err(err) => {
                 err.emit();
-                return Some(annotatable);
+                annotatable
             }
         }
-
-        // Now that we have our re-parsed `AttrTokenStream`, recursively configuring
-        // our attribute target will correctly configure the tokens as well.
-        flat_map_annotatable(self, annotatable)
     }
 }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 82baaca9a46..79c198ed2d0 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -680,6 +680,12 @@ impl<'a> TraitDef<'a> {
                     param_clone
                 }
             })
+            .map(|mut param| {
+                // Remove all attributes, because there might be helper attributes
+                // from other macros that will not be valid in the expanded implementation.
+                param.attrs.clear();
+                param
+            })
             .collect();
 
         // and similarly for where clauses
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
deleted file mode 100644
index c7725e49c94..00000000000
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-use rustc_codegen_ssa::back::archive::{
-    ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
-};
-use rustc_session::Session;
-
-pub(crate) struct ArArchiveBuilderBuilder;
-
-impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
-    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
-        Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
-    }
-}
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 19a1de53d1d..b506b1f5731 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -43,7 +43,6 @@ use rustc_codegen_ssa::CodegenResults;
 use rustc_codegen_ssa::back::versioned_llvm_target;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::profiling::SelfProfilerRef;
-use rustc_errors::ErrorGuaranteed;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_session::Session;
@@ -56,7 +55,6 @@ use crate::prelude::*;
 mod abi;
 mod allocator;
 mod analyze;
-mod archive;
 mod base;
 mod cast;
 mod codegen_i128;
@@ -249,17 +247,6 @@ impl CodegenBackend for CraneliftCodegenBackend {
             self.config.borrow().as_ref().unwrap(),
         )
     }
-
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
-        use rustc_codegen_ssa::back::link::link_binary;
-
-        link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
-    }
 }
 
 fn target_triple(sess: &Session) -> target_lexicon::Triple {
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
deleted file mode 100644
index 82e98370b37..00000000000
--- a/compiler/rustc_codegen_gcc/src/archive.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use std::path::Path;
-
-use rustc_codegen_ssa::back::archive::{
-    ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
-    ImportLibraryItem,
-};
-use rustc_session::Session;
-
-pub(crate) struct ArArchiveBuilderBuilder;
-
-impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
-    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
-        Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
-    }
-
-    fn create_dll_import_lib(
-        &self,
-        _sess: &Session,
-        _lib_name: &str,
-        _items: Vec<ImportLibraryItem>,
-        _output_path: &Path,
-    ) {
-        unimplemented!("creating dll imports is not yet supported");
-    }
-}
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index 9d62ccc95d5..5d8c5c199b1 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -52,6 +52,10 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
     fn clear_dbg_loc(&mut self) {
         self.location = None;
     }
+
+    fn get_dbg_loc(&self) -> Option<Self::DILocation> {
+        self.location
+    }
 }
 
 /// Generate the `debug_context` in an MIR Body.
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index f70dc94b267..452e92bffa2 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -58,7 +58,6 @@ extern crate rustc_driver;
 
 mod abi;
 mod allocator;
-mod archive;
 mod asm;
 mod attributes;
 mod back;
@@ -103,7 +102,7 @@ use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBacken
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::IntoDynSyncSend;
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
+use rustc_errors::DiagCtxtHandle;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
@@ -261,17 +260,6 @@ impl CodegenBackend for GccCodegenBackend {
             .join(sess)
     }
 
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
-        use rustc_codegen_ssa::back::link::link_binary;
-
-        link_binary(sess, &crate::archive::ArArchiveBuilderBuilder, &codegen_results, outputs)
-    }
-
     fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
         target_features(sess, allow_unstable, &self.target_info)
     }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 751b2235dc8..ac76b781218 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1574,6 +1574,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
                 cfi::typeid_for_fnabi(self.tcx, fn_abi, options)
             };
             let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
+            let dbg_loc = self.get_dbg_loc();
 
             // Test whether the function pointer is associated with the type identifier.
             let cond = self.type_test(llfn, typeid_metadata);
@@ -1582,10 +1583,16 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             self.cond_br(cond, bb_pass, bb_fail);
 
             self.switch_to_block(bb_fail);
+            if let Some(dbg_loc) = dbg_loc {
+                self.set_dbg_loc(dbg_loc);
+            }
             self.abort();
             self.unreachable();
 
             self.switch_to_block(bb_pass);
+            if let Some(dbg_loc) = dbg_loc {
+                self.set_dbg_loc(dbg_loc);
+            }
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index ba863d9d74b..3a7c7efe03b 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -274,8 +274,12 @@ pub(crate) unsafe fn create_module<'ll>(
         }
     }
 
-    // Control Flow Guard is currently only supported by the MSVC linker on Windows.
-    if sess.target.is_like_msvc {
+    // Control Flow Guard is currently only supported by MSVC and LLVM on Windows.
+    if sess.target.is_like_msvc
+        || (sess.target.options.os == "windows"
+            && sess.target.options.env == "gnu"
+            && sess.target.options.abi == "llvm")
+    {
         match sess.opts.cg.control_flow_guard {
             CFGuard::Disabled => {}
             CFGuard::NoChecks => {
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index feac97f3e2b..a6e07ea2a60 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -1,5 +1,7 @@
 use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion};
 
+use crate::coverageinfo::mapgen::LocalFileId;
+
 /// Must match the layout of `LLVMRustCounterKind`.
 #[derive(Copy, Clone, Debug)]
 #[repr(C)]
@@ -137,8 +139,12 @@ pub(crate) struct CoverageSpan {
 }
 
 impl CoverageSpan {
-    pub(crate) fn from_source_region(file_id: u32, code_region: &SourceRegion) -> Self {
-        let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;
+    pub(crate) fn from_source_region(
+        local_file_id: LocalFileId,
+        code_region: &SourceRegion,
+    ) -> Self {
+        let file_id = local_file_id.as_u32();
+        let &SourceRegion { start_line, start_col, end_line, end_col } = code_region;
         // Internally, LLVM uses the high bit of `end_col` to distinguish between
         // code regions and gap regions, so it can't be used by the column number.
         assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}");
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 5ed640b840e..e3c0df27883 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -6,7 +6,6 @@ use rustc_middle::mir::coverage::{
     SourceRegion,
 };
 use rustc_middle::ty::Instance;
-use rustc_span::Symbol;
 use tracing::{debug, instrument};
 
 use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
@@ -180,7 +179,7 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
 }
 
 pub(crate) struct FunctionCoverage<'tcx> {
-    function_coverage_info: &'tcx FunctionCoverageInfo,
+    pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo,
     is_used: bool,
 
     counters_seen: BitSet<CounterId>,
@@ -199,11 +198,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
         if self.is_used { self.function_coverage_info.function_source_hash } else { 0 }
     }
 
-    /// Returns an iterator over all filenames used by this function's mappings.
-    pub(crate) fn all_file_names(&self) -> impl Iterator<Item = Symbol> + Captures<'_> {
-        self.function_coverage_info.mappings.iter().map(|mapping| mapping.source_region.file_name)
-    }
-
     /// Convert this function's coverage expression data into a form that can be
     /// passed through FFI to LLVM.
     pub(crate) fn counter_expressions(
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index bb2f634cb25..b582dd967a7 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -12,8 +12,10 @@ use rustc_index::IndexVec;
 use rustc_middle::mir::coverage::MappingKind;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, mir};
-use rustc_span::Symbol;
+use rustc_session::RemapFileNameExt;
+use rustc_session::config::RemapPathScopeComponents;
 use rustc_span::def_id::DefIdSet;
+use rustc_span::{Span, Symbol};
 use rustc_target::spec::HasTargetSpec;
 use tracing::debug;
 
@@ -70,8 +72,10 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         .map(|(instance, function_coverage)| (instance, function_coverage.into_finished()))
         .collect::<Vec<_>>();
 
-    let all_file_names =
-        function_coverage_entries.iter().flat_map(|(_, fn_cov)| fn_cov.all_file_names());
+    let all_file_names = function_coverage_entries
+        .iter()
+        .map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span)
+        .map(|span| span_file_name(tcx, span));
     let global_file_table = GlobalFileTable::new(all_file_names);
 
     // Encode all filenames referenced by coverage mappings in this CGU.
@@ -96,7 +100,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         let is_used = function_coverage.is_used();
 
         let coverage_mapping_buffer =
-            encode_mappings_for_function(&global_file_table, &function_coverage);
+            encode_mappings_for_function(tcx, &global_file_table, &function_coverage);
 
         if coverage_mapping_buffer.is_empty() {
             if function_coverage.is_used() {
@@ -164,13 +168,13 @@ impl GlobalFileTable {
         Self { raw_file_table }
     }
 
-    fn global_file_id_for_file_name(&self, file_name: Symbol) -> u32 {
+    fn global_file_id_for_file_name(&self, file_name: Symbol) -> GlobalFileId {
         let raw_id = self.raw_file_table.get_index_of(&file_name).unwrap_or_else(|| {
             bug!("file name not found in prepared global file table: {file_name}");
         });
         // The raw file table doesn't include an entry for the working dir
         // (which has ID 0), so add 1 to get the correct ID.
-        (raw_id + 1) as u32
+        GlobalFileId::from_usize(raw_id + 1)
     }
 
     fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> {
@@ -196,19 +200,27 @@ impl GlobalFileTable {
 }
 
 rustc_index::newtype_index! {
-    struct LocalFileId {}
+    /// An index into the CGU's overall list of file paths. The underlying paths
+    /// will be embedded in the `__llvm_covmap` linker section.
+    struct GlobalFileId {}
+}
+rustc_index::newtype_index! {
+    /// An index into a function's list of global file IDs. That underlying list
+    /// of local-to-global mappings will be embedded in the function's record in
+    /// the `__llvm_covfun` linker section.
+    pub(crate) struct LocalFileId {}
 }
 
 /// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU)
 /// file IDs.
 #[derive(Default)]
 struct VirtualFileMapping {
-    local_to_global: IndexVec<LocalFileId, u32>,
-    global_to_local: FxIndexMap<u32, LocalFileId>,
+    local_to_global: IndexVec<LocalFileId, GlobalFileId>,
+    global_to_local: FxIndexMap<GlobalFileId, LocalFileId>,
 }
 
 impl VirtualFileMapping {
-    fn local_id_for_global(&mut self, global_file_id: u32) -> LocalFileId {
+    fn local_id_for_global(&mut self, global_file_id: GlobalFileId) -> LocalFileId {
         *self
             .global_to_local
             .entry(global_file_id)
@@ -216,16 +228,26 @@ impl VirtualFileMapping {
     }
 
     fn into_vec(self) -> Vec<u32> {
-        self.local_to_global.raw
+        // This conversion should be optimized away to ~zero overhead.
+        // In any case, it's probably not hot enough to worry about.
+        self.local_to_global.into_iter().map(|global| global.as_u32()).collect()
     }
 }
 
+fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
+    let source_file = tcx.sess.source_map().lookup_source_file(span.lo());
+    let name =
+        source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy();
+    Symbol::intern(&name)
+}
+
 /// Using the expressions and counter regions collected for a single function,
 /// generate the variable-sized payload of its corresponding `__llvm_covfun`
 /// entry. The payload is returned as a vector of bytes.
 ///
 /// Newly-encountered filenames will be added to the global file table.
 fn encode_mappings_for_function(
+    tcx: TyCtxt<'_>,
     global_file_table: &GlobalFileTable,
     function_coverage: &FunctionCoverage<'_>,
 ) -> Vec<u8> {
@@ -242,53 +264,45 @@ fn encode_mappings_for_function(
     let mut mcdc_branch_regions = vec![];
     let mut mcdc_decision_regions = vec![];
 
-    // Group mappings into runs with the same filename, preserving the order
-    // yielded by `FunctionCoverage`.
-    // Prepare file IDs for each filename, and prepare the mapping data so that
-    // we can pass it through FFI to LLVM.
-    for (file_name, counter_regions_for_file) in
-        &counter_regions.group_by(|(_, region)| region.file_name)
-    {
-        // Look up the global file ID for this filename.
-        let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
-
-        // Associate that global file ID with a local file ID for this function.
-        let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
-        debug!("  file id: {local_file_id:?} => global {global_file_id} = '{file_name:?}'");
-
-        // For each counter/region pair in this function+file, convert it to a
-        // form suitable for FFI.
-        for (mapping_kind, region) in counter_regions_for_file {
-            debug!("Adding counter {mapping_kind:?} to map for {region:?}");
-            let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region);
-            match mapping_kind {
-                MappingKind::Code(term) => {
-                    code_regions
-                        .push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
-                }
-                MappingKind::Branch { true_term, false_term } => {
-                    branch_regions.push(ffi::BranchRegion {
-                        span,
-                        true_counter: ffi::Counter::from_term(true_term),
-                        false_counter: ffi::Counter::from_term(false_term),
-                    });
-                }
-                MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
-                    mcdc_branch_regions.push(ffi::MCDCBranchRegion {
-                        span,
-                        true_counter: ffi::Counter::from_term(true_term),
-                        false_counter: ffi::Counter::from_term(false_term),
-                        mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
-                    });
-                }
-                MappingKind::MCDCDecision(mcdc_decision_params) => {
-                    mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
-                        span,
-                        mcdc_decision_params: ffi::mcdc::DecisionParameters::from(
-                            mcdc_decision_params,
-                        ),
-                    });
-                }
+    // Currently a function's mappings must all be in the same file as its body span.
+    let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span);
+
+    // Look up the global file ID for that filename.
+    let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
+
+    // Associate that global file ID with a local file ID for this function.
+    let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
+    debug!("  file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
+
+    // For each counter/region pair in this function+file, convert it to a
+    // form suitable for FFI.
+    for (mapping_kind, region) in counter_regions {
+        debug!("Adding counter {mapping_kind:?} to map for {region:?}");
+        let span = ffi::CoverageSpan::from_source_region(local_file_id, region);
+        match mapping_kind {
+            MappingKind::Code(term) => {
+                code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
+            }
+            MappingKind::Branch { true_term, false_term } => {
+                branch_regions.push(ffi::BranchRegion {
+                    span,
+                    true_counter: ffi::Counter::from_term(true_term),
+                    false_counter: ffi::Counter::from_term(false_term),
+                });
+            }
+            MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
+                mcdc_branch_regions.push(ffi::MCDCBranchRegion {
+                    span,
+                    true_counter: ffi::Counter::from_term(true_term),
+                    false_counter: ffi::Counter::from_term(false_term),
+                    mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
+                });
+            }
+            MappingKind::MCDCDecision(mcdc_decision_params) => {
+                mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
+                    span,
+                    mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
+                });
             }
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 9e1e5127e80..89492e4b9fe 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -206,6 +206,10 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
         }
     }
 
+    fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
+        unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
+    }
+
     fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
         gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
     }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 49e616b5371..3dfb86d422d 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -382,7 +382,7 @@ impl CodegenBackend for LlvmCodegenBackend {
 
         // Run the linker on any artifacts that resulted from the LLVM run.
         // This should produce either a finished executable or library.
-        link_binary(sess, &LlvmArchiveBuilderBuilder, &codegen_results, outputs)
+        link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs)
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 75a5ec44c22..7f59264824e 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1063,6 +1063,7 @@ unsafe extern "C" {
 
     // Metadata
     pub fn LLVMSetCurrentDebugLocation2<'a>(Builder: &Builder<'a>, Loc: *const Metadata);
+    pub fn LLVMGetCurrentDebugLocation2<'a>(Builder: &Builder<'a>) -> Option<&'a Metadata>;
 
     // Terminators
     pub fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value;
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index c382242d8d0..db2b03d9aed 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -344,15 +344,23 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
         })
     {
         if enabled {
+            // Also add all transitively implied features.
             features.extend(sess.target.implied_target_features(std::iter::once(feature)));
         } else {
+            // Remove transitively reverse-implied features.
+
             // We don't care about the order in `features` since the only thing we use it for is the
             // `features.contains` below.
             #[allow(rustc::potential_query_instability)]
             features.retain(|f| {
-                // Keep a feature if it does not imply `feature`. Or, equivalently,
-                // remove the reverse-dependencies of `feature`.
-                !sess.target.implied_target_features(std::iter::once(*f)).contains(&feature)
+                if sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) {
+                    // If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
+                    // remove `f`. (This is the standard logical contraposition principle.)
+                    false
+                } else {
+                    // We can keep `f`.
+                    true
+                }
             });
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index e83bfa7b70d..d4836eb7a1d 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -304,6 +304,14 @@ pub trait ArchiveBuilder {
     fn build(self: Box<Self>, output: &Path) -> bool;
 }
 
+pub struct ArArchiveBuilderBuilder;
+
+impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
+    fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
+        Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
+    }
+}
+
 #[must_use = "must call build() to finish building the archive"]
 pub struct ArArchiveBuilder<'a> {
     sess: &'a Session,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 3120b5bf0af..fd1126e8528 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -69,7 +69,7 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
 pub fn link_binary(
     sess: &Session,
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
-    codegen_results: &CodegenResults,
+    codegen_results: CodegenResults,
     outputs: &OutputFilenames,
 ) -> Result<(), ErrorGuaranteed> {
     let _timer = sess.timer("link_binary");
@@ -116,7 +116,7 @@ pub fn link_binary(
                     link_rlib(
                         sess,
                         archive_builder_builder,
-                        codegen_results,
+                        &codegen_results,
                         RlibFlavor::Normal,
                         &path,
                     )?
@@ -126,7 +126,7 @@ pub fn link_binary(
                     link_staticlib(
                         sess,
                         archive_builder_builder,
-                        codegen_results,
+                        &codegen_results,
                         &out_filename,
                         &path,
                     )?;
@@ -137,7 +137,7 @@ pub fn link_binary(
                         archive_builder_builder,
                         crate_type,
                         &out_filename,
-                        codegen_results,
+                        &codegen_results,
                         path.as_ref(),
                     )?;
                 }
@@ -1647,7 +1647,7 @@ fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> Pat
             return file_path;
         }
     }
-    for search_path in sess.target_filesearch(PathKind::Native).search_paths() {
+    for search_path in sess.target_filesearch().search_paths(PathKind::Native) {
         let file_path = search_path.dir.join(name);
         if file_path.exists() {
             return file_path;
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 676fb181d67..cbf214763b4 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -16,6 +16,8 @@ use rustc_span::symbol::Symbol;
 
 use super::CodegenObject;
 use super::write::WriteBackendMethods;
+use crate::back::archive::ArArchiveBuilderBuilder;
+use crate::back::link::link_binary;
 use crate::back::write::TargetMachineFactoryFn;
 use crate::{CodegenResults, ModuleCodegen};
 
@@ -87,7 +89,9 @@ pub trait CodegenBackend {
         sess: &Session,
         codegen_results: CodegenResults,
         outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed>;
+    ) -> Result<(), ErrorGuaranteed> {
+        link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs)
+    }
 
     /// Returns `true` if this backend can be safely called from multiple threads.
     ///
diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
index 670433a6c33..fe135e911fb 100644
--- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
@@ -81,6 +81,7 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
     );
     fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
     fn clear_dbg_loc(&mut self);
+    fn get_dbg_loc(&self) -> Option<Self::DILocation>;
     fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
     fn set_var_name(&mut self, value: Self::Value, name: &str);
 }
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 8cd0ecb3e4e..ffe32acb316 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -3,6 +3,7 @@
 use std::assert_matches::assert_matches;
 use std::borrow::Cow;
 use std::mem;
+use std::num::NonZero;
 use std::ops::Deref;
 
 use rustc_attr::{ConstStability, StabilityLevel};
@@ -271,9 +272,18 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
     /// context.
     pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
         let gate = match op.status_in_item(self.ccx) {
-            Status::Unstable { gate, safe_to_expose_on_stable, is_function_call }
-                if self.tcx.features().enabled(gate) =>
-            {
+            Status::Unstable {
+                gate,
+                safe_to_expose_on_stable,
+                is_function_call,
+                gate_already_checked,
+            } if gate_already_checked || self.tcx.features().enabled(gate) => {
+                if gate_already_checked {
+                    assert!(
+                        !safe_to_expose_on_stable,
+                        "setting `gate_already_checked` without `safe_to_expose_on_stable` makes no sense"
+                    );
+                }
                 // Generally this is allowed since the feature gate is enabled -- except
                 // if this function wants to be safe-to-expose-on-stable.
                 if !safe_to_expose_on_stable
@@ -709,6 +719,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                 // Intrinsics are language primitives, not regular calls, so treat them separately.
                 if let Some(intrinsic) = tcx.intrinsic(callee) {
+                    if !tcx.is_const_fn(callee) {
+                        // Non-const intrinsic.
+                        self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
+                        // If we allowed this, we're in miri-unleashed mode, so we might
+                        // as well skip the remaining checks.
+                        return;
+                    }
                     // We use `intrinsic.const_stable` to determine if this can be safely exposed to
                     // stable code, rather than `const_stable_indirect`. This is to make
                     // `#[rustc_const_stable_indirect]` an attribute that is always safe to add.
@@ -716,17 +733,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     // fallback body is safe to expose on stable.
                     let is_const_stable = intrinsic.const_stable
                         || (!intrinsic.must_be_overridden
-                            && tcx.is_const_fn(callee)
                             && is_safe_to_expose_on_stable_const_fn(tcx, callee));
                     match tcx.lookup_const_stability(callee) {
                         None => {
-                            // Non-const intrinsic.
-                            self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
-                        }
-                        Some(ConstStability { feature: None, .. }) => {
-                            // Intrinsic does not need a separate feature gate (we rely on the
-                            // regular stability checker). However, we have to worry about recursive
-                            // const stability.
+                            // This doesn't need a separate const-stability check -- const-stability equals
+                            // regular stability, and regular stability is checked separately.
+                            // However, we *do* have to worry about *recursive* const stability.
                             if !is_const_stable && self.enforce_recursive_const_stability() {
                                 self.dcx().emit_err(errors::UnmarkedIntrinsicExposed {
                                     span: self.span,
@@ -735,14 +747,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             }
                         }
                         Some(ConstStability {
-                            feature: Some(feature),
                             level: StabilityLevel::Unstable { .. },
+                            feature,
                             ..
                         }) => {
                             self.check_op(ops::IntrinsicUnstable {
                                 name: intrinsic.name,
                                 feature,
-                                const_stable: is_const_stable,
+                                const_stable_indirect: is_const_stable,
                             });
                         }
                         Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
@@ -773,7 +785,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
                         // All good.
                     }
-                    None | Some(ConstStability { feature: None, .. }) => {
+                    None => {
                         // This doesn't need a separate const-stability check -- const-stability equals
                         // regular stability, and regular stability is checked separately.
                         // However, we *do* have to worry about *recursive* const stability.
@@ -787,8 +799,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                         }
                     }
                     Some(ConstStability {
-                        feature: Some(feature),
-                        level: StabilityLevel::Unstable { implied_by: implied_feature, .. },
+                        level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
+                        feature,
                         ..
                     }) => {
                         // An unstable const fn with a feature gate.
@@ -797,6 +809,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                         // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` if
                         // the callee is safe to expose, to avoid bypassing recursive stability.
+                        // This is not ideal since it means the user sees an error, not the macro
+                        // author, but that's also the case if one forgets to set
+                        // `#[allow_internal_unstable]` in the first place. Note that this cannot be
+                        // integrated in the check below since we want to enforce
+                        // `callee_safe_to_expose_on_stable` even if
+                        // `!self.enforce_recursive_const_stability()`.
                         if (self.span.allows_unstable(feature)
                             || implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
                             && callee_safe_to_expose_on_stable
@@ -810,16 +828,30 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                         // to allow this.
                         let feature_enabled = callee.is_local()
                             || tcx.features().enabled(feature)
-                            || implied_feature.is_some_and(|f| tcx.features().enabled(f));
-                        // We do *not* honor this if we are in the "danger zone": we have to enforce
-                        // recursive const-stability and the callee is not safe-to-expose. In that
-                        // case we need `check_op` to do the check.
-                        let danger_zone = !callee_safe_to_expose_on_stable
-                            && self.enforce_recursive_const_stability();
-                        if danger_zone || !feature_enabled {
+                            || implied_feature.is_some_and(|f| tcx.features().enabled(f))
+                            || {
+                                // When we're compiling the compiler itself we may pull in
+                                // crates from crates.io, but those crates may depend on other
+                                // crates also pulled in from crates.io. We want to ideally be
+                                // able to compile everything without requiring upstream
+                                // modifications, so in the case that this looks like a
+                                // `rustc_private` crate (e.g., a compiler crate) and we also have
+                                // the `-Z force-unstable-if-unmarked` flag present (we're
+                                // compiling a compiler crate), then let this missing feature
+                                // annotation slide.
+                                // This matches what we do in `eval_stability_allow_unstable` for
+                                // regular stability.
+                                feature == sym::rustc_private
+                                    && issue == NonZero::new(27812)
+                                    && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
+                            };
+                        // Even if the feature is enabled, we still need check_op to double-check
+                        // this if the callee is not safe to expose on stable.
+                        if !feature_enabled || !callee_safe_to_expose_on_stable {
                             self.check_op(ops::FnCallUnstable {
                                 def_id: callee,
                                 feature,
+                                feature_enabled,
                                 safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
                             });
                         }
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index dcdaafaecc2..ebdd55a4f70 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -53,10 +53,11 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
     }
 
     pub fn enforce_recursive_const_stability(&self) -> bool {
-        // We can skip this if `staged_api` is not enabled, since in such crates
-        // `lookup_const_stability` will always be `None`.
+        // We can skip this if neither `staged_api` nor `-Zforce-unstable-if-unmarked` are enabled,
+        // since in such crates `lookup_const_stability` will always be `None`.
         self.const_kind == Some(hir::ConstContext::ConstFn)
-            && self.tcx.features().staged_api()
+            && (self.tcx.features().staged_api()
+                || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked)
             && is_safe_to_expose_on_stable_const_fn(self.tcx, self.def_id().to_def_id())
     }
 
@@ -109,14 +110,15 @@ pub fn is_safe_to_expose_on_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> b
 
     match tcx.lookup_const_stability(def_id) {
         None => {
-            // Only marked functions can be trusted. Note that this may be a function in a
-            // non-staged-API crate where no recursive checks were done!
-            false
+            // In a `staged_api` crate, we do enforce recursive const stability for all unmarked
+            // functions, so we can trust local functions. But in another crate we don't know which
+            // rules were applied, so we can't trust that.
+            def_id.is_local() && tcx.features().staged_api()
         }
         Some(stab) => {
-            // We consider things safe-to-expose if they are stable, if they don't have any explicit
-            // const stability attribute, or if they are marked as `const_stable_indirect`.
-            stab.is_const_stable() || stab.feature.is_none() || stab.const_stable_indirect
+            // We consider things safe-to-expose if they are stable or if they are marked as
+            // `const_stable_indirect`.
+            stab.is_const_stable() || stab.const_stable_indirect
         }
     }
 }
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 036ca763280..ca95e42dd2b 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -28,6 +28,9 @@ pub enum Status {
     Unstable {
         /// The feature that must be enabled to use this operation.
         gate: Symbol,
+        /// Whether the feature gate was already checked (because the logic is a bit more
+        /// complicated than just checking a single gate).
+        gate_already_checked: bool,
         /// Whether it is allowed to use this operation from stable `const fn`.
         /// This will usually be `false`.
         safe_to_expose_on_stable: bool,
@@ -82,6 +85,7 @@ impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
         // We use the `const_trait_impl` gate for all conditionally-const calls.
         Status::Unstable {
             gate: sym::const_trait_impl,
+            gate_already_checked: false,
             safe_to_expose_on_stable: false,
             // We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
             is_function_call: false,
@@ -330,6 +334,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
 pub(crate) struct FnCallUnstable {
     pub def_id: DefId,
     pub feature: Symbol,
+    /// If this is true, then the feature is enabled, but we need to still check if it is safe to
+    /// expose on stable.
+    pub feature_enabled: bool,
     pub safe_to_expose_on_stable: bool,
 }
 
@@ -337,12 +344,14 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
     fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable {
             gate: self.feature,
+            gate_already_checked: self.feature_enabled,
             safe_to_expose_on_stable: self.safe_to_expose_on_stable,
             is_function_call: true,
         }
     }
 
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
+        assert!(!self.feature_enabled);
         let mut err = ccx.dcx().create_err(errors::UnstableConstFn {
             span,
             def_path: ccx.tcx.def_path_str(self.def_id),
@@ -376,14 +385,15 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
 pub(crate) struct IntrinsicUnstable {
     pub name: Symbol,
     pub feature: Symbol,
-    pub const_stable: bool,
+    pub const_stable_indirect: bool,
 }
 
 impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
     fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable {
             gate: self.feature,
-            safe_to_expose_on_stable: self.const_stable,
+            gate_already_checked: false,
+            safe_to_expose_on_stable: self.const_stable_indirect,
             // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
             // that's not a trivial change!
             is_function_call: false,
@@ -410,6 +420,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
         {
             Status::Unstable {
                 gate: sym::const_async_blocks,
+                gate_already_checked: false,
                 safe_to_expose_on_stable: false,
                 is_function_call: false,
             }
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 5a477143a62..c8ecddb046c 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -10,11 +10,11 @@ bitflags = "2.4.1"
 either = "1.0"
 elsa = "=1.7.1"
 ena = "0.14.3"
-indexmap = { version = "2.4.0" }
+indexmap = { version = "2.4.0", features = ["rustc-rayon"] }
 jobserver_crate = { version = "0.1.28", package = "jobserver" }
 measureme = "11"
 rustc-hash = "2.0.0"
-rustc-rayon = { version = "0.5.0", optional = true }
+rustc-rayon = "0.5.0"
 rustc-stable-hash = { version = "0.1.0", features = ["nightly"] }
 rustc_arena = { path = "../rustc_arena" }
 rustc_graphviz = { path = "../rustc_graphviz" }
@@ -53,8 +53,3 @@ memmap2 = "0.2.1"
 
 [target.'cfg(not(target_has_atomic = "64"))'.dependencies]
 portable-atomic = "1.5.1"
-
-[features]
-# tidy-alphabetical-start
-rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "dep:rustc-rayon"]
-# tidy-alphabetical-end
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index afac08ae6f8..bede4c49703 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -10,7 +10,6 @@
 #![allow(internal_features)]
 #![allow(rustc::default_hash_types)]
 #![allow(rustc::potential_query_instability)]
-#![cfg_attr(not(parallel_compiler), feature(cell_leak))]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs
index 83fdaff515b..2b629024bfe 100644
--- a/compiler/rustc_data_structures/src/marker.rs
+++ b/compiler/rustc_data_structures/src/marker.rs
@@ -1,194 +1,162 @@
-cfg_match! {
-    cfg(not(parallel_compiler)) => {
-        pub auto trait DynSend {}
-        pub auto trait DynSync {}
-
-        impl<T> DynSend for T {}
-        impl<T> DynSync for T {}
-    }
-    _ => {
-        #[rustc_on_unimplemented(
-            message = "`{Self}` doesn't implement `DynSend`. \
-            Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`"
-        )]
-        // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
-        // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a
-        // `Send` type in `IntoDynSyncSend` will create a `DynSend` type.
-        pub unsafe auto trait DynSend {}
-
-        #[rustc_on_unimplemented(
-            message = "`{Self}` doesn't implement `DynSync`. \
-            Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`"
-        )]
-        // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()`
-        // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a
-        // `Sync` type in `IntoDynSyncSend` will create a `DynSync` type.
-        pub unsafe auto trait DynSync {}
-
-        // Same with `Sync` and `Send`.
-        unsafe impl<T: DynSync + ?Sized> DynSend for &T {}
-
-        macro_rules! impls_dyn_send_neg {
-            ($([$t1: ty $(where $($generics1: tt)*)?])*) => {
-                $(impl$(<$($generics1)*>)? !DynSend for $t1 {})*
-            };
-        }
-
-        // Consistent with `std`
-        impls_dyn_send_neg!(
-            [std::env::Args]
-            [std::env::ArgsOs]
-            [*const T where T: ?Sized]
-            [*mut T where T: ?Sized]
-            [std::ptr::NonNull<T> where T: ?Sized]
-            [std::rc::Rc<T> where T: ?Sized]
-            [std::rc::Weak<T> where T: ?Sized]
-            [std::sync::MutexGuard<'_, T> where T: ?Sized]
-            [std::sync::RwLockReadGuard<'_, T> where T: ?Sized]
-            [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized]
-            [std::io::StdoutLock<'_>]
-            [std::io::StderrLock<'_>]
-        );
-
-        #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))]
-        // Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms
-        impl !DynSend for std::env::VarsOs {}
-
-        macro_rules! already_send {
-            ($([$ty: ty])*) => {
-                $(unsafe impl DynSend for $ty where $ty: Send {})*
-            };
-        }
-
-        // These structures are already `Send`.
-        already_send!(
-            [std::backtrace::Backtrace]
-            [std::io::Stdout]
-            [std::io::Stderr]
-            [std::io::Error]
-            [std::fs::File]
-            [rustc_arena::DroplessArena]
-            [crate::memmap::Mmap]
-            [crate::profiling::SelfProfiler]
-            [crate::owned_slice::OwnedSlice]
-        );
-
-        macro_rules! impl_dyn_send {
-            ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => {
-                $(unsafe impl<$($generics2)*> DynSend for $ty {})*
-            };
-        }
-
-        impl_dyn_send!(
-            [std::sync::atomic::AtomicPtr<T> where T]
-            [std::sync::Mutex<T> where T: ?Sized+ DynSend]
-            [std::sync::mpsc::Sender<T> where T: DynSend]
-            [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend]
-            [std::sync::LazyLock<T, F> where T: DynSend, F: DynSend]
-            [std::collections::HashSet<K, S> where K: DynSend, S: DynSend]
-            [std::collections::HashMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend]
-            [std::collections::BTreeMap<K, V, A> where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend]
-            [Vec<T, A> where T: DynSend, A: std::alloc::Allocator + DynSend]
-            [Box<T, A> where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend]
-            [crate::sync::RwLock<T> where T: DynSend]
-            [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool]
-            [rustc_arena::TypedArena<T> where T: DynSend]
-            [indexmap::IndexSet<V, S> where V: DynSend, S: DynSend]
-            [indexmap::IndexMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend]
-            [thin_vec::ThinVec<T> where T: DynSend]
-            [smallvec::SmallVec<A> where A: smallvec::Array + DynSend]
-        );
-
-        macro_rules! impls_dyn_sync_neg {
-            ($([$t1: ty $(where $($generics1: tt)*)?])*) => {
-                $(impl$(<$($generics1)*>)? !DynSync for $t1 {})*
-            };
-        }
-
-        // Consistent with `std`
-        impls_dyn_sync_neg!(
-            [std::env::Args]
-            [std::env::ArgsOs]
-            [*const T where T: ?Sized]
-            [*mut T where T: ?Sized]
-            [std::cell::Cell<T> where T: ?Sized]
-            [std::cell::RefCell<T> where T: ?Sized]
-            [std::cell::UnsafeCell<T> where T: ?Sized]
-            [std::ptr::NonNull<T> where T: ?Sized]
-            [std::rc::Rc<T> where T: ?Sized]
-            [std::rc::Weak<T> where T: ?Sized]
-            [std::cell::OnceCell<T> where T]
-            [std::sync::mpsc::Receiver<T> where T]
-            [std::sync::mpsc::Sender<T> where T]
-        );
-
-        #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))]
-        // Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms
-        impl !DynSync for std::env::VarsOs {}
-
-        macro_rules! already_sync {
-            ($([$ty: ty])*) => {
-                $(unsafe impl DynSync for $ty where $ty: Sync {})*
-            };
-        }
+#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
+            Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")]
+// This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
+// is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a
+// `Send` type in `IntoDynSyncSend` will create a `DynSend` type.
+pub unsafe auto trait DynSend {}
+
+#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
+            Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`")]
+// This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()`
+// is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a
+// `Sync` type in `IntoDynSyncSend` will create a `DynSync` type.
+pub unsafe auto trait DynSync {}
+
+// Same with `Sync` and `Send`.
+unsafe impl<T: DynSync + ?Sized> DynSend for &T {}
+
+macro_rules! impls_dyn_send_neg {
+    ($([$t1: ty $(where $($generics1: tt)*)?])*) => {
+        $(impl$(<$($generics1)*>)? !DynSend for $t1 {})*
+    };
+}
 
-        // These structures are already `Sync`.
-        already_sync!(
-            [std::sync::atomic::AtomicBool]
-            [std::sync::atomic::AtomicUsize]
-            [std::sync::atomic::AtomicU8]
-            [std::sync::atomic::AtomicU32]
-            [std::backtrace::Backtrace]
-            [std::io::Error]
-            [std::fs::File]
-            [jobserver_crate::Client]
-            [crate::memmap::Mmap]
-            [crate::profiling::SelfProfiler]
-            [crate::owned_slice::OwnedSlice]
-        );
+// Consistent with `std`
+impls_dyn_send_neg!(
+    [std::env::Args]
+    [std::env::ArgsOs]
+    [*const T where T: ?Sized]
+    [*mut T where T: ?Sized]
+    [std::ptr::NonNull<T> where T: ?Sized]
+    [std::rc::Rc<T> where T: ?Sized]
+    [std::rc::Weak<T> where T: ?Sized]
+    [std::sync::MutexGuard<'_, T> where T: ?Sized]
+    [std::sync::RwLockReadGuard<'_, T> where T: ?Sized]
+    [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized]
+    [std::io::StdoutLock<'_>]
+    [std::io::StderrLock<'_>]
+);
+
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))]
+// Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms
+impl !DynSend for std::env::VarsOs {}
+
+macro_rules! already_send {
+    ($([$ty: ty])*) => {
+        $(unsafe impl DynSend for $ty where $ty: Send {})*
+    };
+}
 
-        // Use portable AtomicU64 for targets without native 64-bit atomics
-        #[cfg(target_has_atomic = "64")]
-        already_sync!(
-            [std::sync::atomic::AtomicU64]
-        );
+// These structures are already `Send`.
+already_send!(
+    [std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File]
+        [rustc_arena::DroplessArena][crate::memmap::Mmap][crate::profiling::SelfProfiler]
+        [crate::owned_slice::OwnedSlice]
+);
+
+macro_rules! impl_dyn_send {
+    ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => {
+        $(unsafe impl<$($generics2)*> DynSend for $ty {})*
+    };
+}
 
-        #[cfg(not(target_has_atomic = "64"))]
-        already_sync!(
-            [portable_atomic::AtomicU64]
-        );
+impl_dyn_send!(
+    [std::sync::atomic::AtomicPtr<T> where T]
+    [std::sync::Mutex<T> where T: ?Sized+ DynSend]
+    [std::sync::mpsc::Sender<T> where T: DynSend]
+    [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend]
+    [std::sync::LazyLock<T, F> where T: DynSend, F: DynSend]
+    [std::collections::HashSet<K, S> where K: DynSend, S: DynSend]
+    [std::collections::HashMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend]
+    [std::collections::BTreeMap<K, V, A> where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend]
+    [Vec<T, A> where T: DynSend, A: std::alloc::Allocator + DynSend]
+    [Box<T, A> where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend]
+    [crate::sync::RwLock<T> where T: DynSend]
+    [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool]
+    [rustc_arena::TypedArena<T> where T: DynSend]
+    [indexmap::IndexSet<V, S> where V: DynSend, S: DynSend]
+    [indexmap::IndexMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend]
+    [thin_vec::ThinVec<T> where T: DynSend]
+    [smallvec::SmallVec<A> where A: smallvec::Array + DynSend]
+);
+
+macro_rules! impls_dyn_sync_neg {
+    ($([$t1: ty $(where $($generics1: tt)*)?])*) => {
+        $(impl$(<$($generics1)*>)? !DynSync for $t1 {})*
+    };
+}
 
-        macro_rules! impl_dyn_sync {
-            ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => {
-                $(unsafe impl<$($generics2)*> DynSync for $ty {})*
-            };
-        }
+// Consistent with `std`
+impls_dyn_sync_neg!(
+    [std::env::Args]
+    [std::env::ArgsOs]
+    [*const T where T: ?Sized]
+    [*mut T where T: ?Sized]
+    [std::cell::Cell<T> where T: ?Sized]
+    [std::cell::RefCell<T> where T: ?Sized]
+    [std::cell::UnsafeCell<T> where T: ?Sized]
+    [std::ptr::NonNull<T> where T: ?Sized]
+    [std::rc::Rc<T> where T: ?Sized]
+    [std::rc::Weak<T> where T: ?Sized]
+    [std::cell::OnceCell<T> where T]
+    [std::sync::mpsc::Receiver<T> where T]
+    [std::sync::mpsc::Sender<T> where T]
+);
+
+#[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))]
+// Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms
+impl !DynSync for std::env::VarsOs {}
+
+macro_rules! already_sync {
+    ($([$ty: ty])*) => {
+        $(unsafe impl DynSync for $ty where $ty: Sync {})*
+    };
+}
 
-        impl_dyn_sync!(
-            [std::sync::atomic::AtomicPtr<T> where T]
-            [std::sync::OnceLock<T> where T: DynSend + DynSync]
-            [std::sync::Mutex<T> where T: ?Sized + DynSend]
-            [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend]
-            [std::sync::LazyLock<T, F> where T: DynSend + DynSync, F: DynSend]
-            [std::collections::HashSet<K, S> where K: DynSync, S: DynSync]
-            [std::collections::HashMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync]
-            [std::collections::BTreeMap<K, V, A> where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync]
-            [Vec<T, A> where T: DynSync, A: std::alloc::Allocator + DynSync]
-            [Box<T, A> where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync]
-            [crate::sync::RwLock<T> where T: DynSend + DynSync]
-            [crate::sync::WorkerLocal<T> where T: DynSend]
-            [crate::intern::Interned<'a, T> where 'a, T: DynSync]
-            [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool]
-            [parking_lot::lock_api::Mutex<R, T> where R: DynSync, T: ?Sized + DynSend]
-            [parking_lot::lock_api::RwLock<R, T> where R: DynSync, T: ?Sized + DynSend + DynSync]
-            [indexmap::IndexSet<V, S> where V: DynSync, S: DynSync]
-            [indexmap::IndexMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync]
-            [smallvec::SmallVec<A> where A: smallvec::Array + DynSync]
-            [thin_vec::ThinVec<T> where T: DynSync]
-        );
-    }
+// These structures are already `Sync`.
+already_sync!(
+    [std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8]
+        [std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File]
+        [jobserver_crate::Client][crate::memmap::Mmap][crate::profiling::SelfProfiler]
+        [crate::owned_slice::OwnedSlice]
+);
+
+// Use portable AtomicU64 for targets without native 64-bit atomics
+#[cfg(target_has_atomic = "64")]
+already_sync!([std::sync::atomic::AtomicU64]);
+
+#[cfg(not(target_has_atomic = "64"))]
+already_sync!([portable_atomic::AtomicU64]);
+
+macro_rules! impl_dyn_sync {
+    ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => {
+        $(unsafe impl<$($generics2)*> DynSync for $ty {})*
+    };
 }
 
+impl_dyn_sync!(
+    [std::sync::atomic::AtomicPtr<T> where T]
+    [std::sync::OnceLock<T> where T: DynSend + DynSync]
+    [std::sync::Mutex<T> where T: ?Sized + DynSend]
+    [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend]
+    [std::sync::LazyLock<T, F> where T: DynSend + DynSync, F: DynSend]
+    [std::collections::HashSet<K, S> where K: DynSync, S: DynSync]
+    [std::collections::HashMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync]
+    [std::collections::BTreeMap<K, V, A> where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync]
+    [Vec<T, A> where T: DynSync, A: std::alloc::Allocator + DynSync]
+    [Box<T, A> where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync]
+    [crate::sync::RwLock<T> where T: DynSend + DynSync]
+    [crate::sync::WorkerLocal<T> where T: DynSend]
+    [crate::intern::Interned<'a, T> where 'a, T: DynSync]
+    [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool]
+    [parking_lot::lock_api::Mutex<R, T> where R: DynSync, T: ?Sized + DynSend]
+    [parking_lot::lock_api::RwLock<R, T> where R: DynSync, T: ?Sized + DynSend + DynSync]
+    [indexmap::IndexSet<V, S> where V: DynSync, S: DynSync]
+    [indexmap::IndexMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync]
+    [smallvec::SmallVec<A> where A: smallvec::Array + DynSync]
+    [thin_vec::ThinVec<T> where T: DynSync]
+);
+
 pub fn assert_dyn_sync<T: ?Sized + DynSync>() {}
 pub fn assert_dyn_send<T: ?Sized + DynSend>() {}
 pub fn assert_dyn_send_val<T: ?Sized + DynSend>(_t: &T) {}
@@ -203,7 +171,6 @@ impl<T> FromDyn<T> {
         // Check that `sync::is_dyn_thread_safe()` is true on creation so we can
         // implement `Send` and `Sync` for this structure when `T`
         // implements `DynSend` and `DynSync` respectively.
-        #[cfg(parallel_compiler)]
         assert!(crate::sync::is_dyn_thread_safe());
         FromDyn(val)
     }
@@ -215,11 +182,9 @@ impl<T> FromDyn<T> {
 }
 
 // `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true.
-#[cfg(parallel_compiler)]
 unsafe impl<T: DynSend> Send for FromDyn<T> {}
 
 // `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true.
-#[cfg(parallel_compiler)]
 unsafe impl<T: DynSync> Sync for FromDyn<T> {}
 
 impl<T> std::ops::Deref for FromDyn<T> {
@@ -237,9 +202,7 @@ impl<T> std::ops::Deref for FromDyn<T> {
 #[derive(Copy, Clone)]
 pub struct IntoDynSyncSend<T: ?Sized>(pub T);
 
-#[cfg(parallel_compiler)]
 unsafe impl<T: ?Sized + Send> DynSend for IntoDynSyncSend<T> {}
-#[cfg(parallel_compiler)]
 unsafe impl<T: ?Sized + Sync> DynSync for IntoDynSyncSend<T> {}
 
 impl<T> std::ops::Deref for IntoDynSyncSend<T> {
diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs
index bbe6691e548..c8be0ab52e9 100644
--- a/compiler/rustc_data_structures/src/owned_slice.rs
+++ b/compiler/rustc_data_structures/src/owned_slice.rs
@@ -139,11 +139,9 @@ impl Borrow<[u8]> for OwnedSlice {
 }
 
 // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send`
-#[cfg(parallel_compiler)]
 unsafe impl sync::Send for OwnedSlice {}
 
 // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
-#[cfg(parallel_compiler)]
 unsafe impl sync::Sync for OwnedSlice {}
 
 #[cfg(test)]
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index d0b6fe2bc6f..65488c73d3c 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -3,27 +3,22 @@ use std::collections::hash_map::RawEntryMut;
 use std::hash::{Hash, Hasher};
 use std::{iter, mem};
 
-#[cfg(parallel_compiler)]
 use either::Either;
 
 use crate::fx::{FxHashMap, FxHasher};
-#[cfg(parallel_compiler)]
-use crate::sync::{CacheAligned, is_dyn_thread_safe};
-use crate::sync::{Lock, LockGuard, Mode};
+use crate::sync::{CacheAligned, Lock, LockGuard, Mode, is_dyn_thread_safe};
 
 // 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
 // but this should be tested on higher core count CPUs. How the `Sharded` type gets used
 // may also affect the ideal number of shards.
 const SHARD_BITS: usize = 5;
 
-#[cfg(parallel_compiler)]
 const SHARDS: usize = 1 << SHARD_BITS;
 
 /// An array of cache-line aligned inner locked structures with convenience methods.
 /// A single field is used when the compiler uses only one thread.
 pub enum Sharded<T> {
     Single(Lock<T>),
-    #[cfg(parallel_compiler)]
     Shards(Box<[CacheAligned<Lock<T>>; SHARDS]>),
 }
 
@@ -37,7 +32,6 @@ impl<T: Default> Default for Sharded<T> {
 impl<T> Sharded<T> {
     #[inline]
     pub fn new(mut value: impl FnMut() -> T) -> Self {
-        #[cfg(parallel_compiler)]
         if is_dyn_thread_safe() {
             return Sharded::Shards(Box::new(
                 [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
@@ -52,7 +46,6 @@ impl<T> Sharded<T> {
     pub fn get_shard_by_value<K: Hash + ?Sized>(&self, _val: &K) -> &Lock<T> {
         match self {
             Self::Single(single) => single,
-            #[cfg(parallel_compiler)]
             Self::Shards(..) => self.get_shard_by_hash(make_hash(_val)),
         }
     }
@@ -66,7 +59,6 @@ impl<T> Sharded<T> {
     pub fn get_shard_by_index(&self, _i: usize) -> &Lock<T> {
         match self {
             Self::Single(single) => single,
-            #[cfg(parallel_compiler)]
             Self::Shards(shards) => {
                 // SAFETY: The index gets ANDed with the shard mask, ensuring it is always inbounds.
                 unsafe { &shards.get_unchecked(_i & (SHARDS - 1)).0 }
@@ -87,7 +79,6 @@ impl<T> Sharded<T> {
                 // `might_be_dyn_thread_safe` was also false.
                 unsafe { single.lock_assume(Mode::NoSync) }
             }
-            #[cfg(parallel_compiler)]
             Self::Shards(..) => self.lock_shard_by_hash(make_hash(_val)),
         }
     }
@@ -110,7 +101,6 @@ impl<T> Sharded<T> {
                 // `might_be_dyn_thread_safe` was also false.
                 unsafe { single.lock_assume(Mode::NoSync) }
             }
-            #[cfg(parallel_compiler)]
             Self::Shards(shards) => {
                 // Synchronization is enabled so use the `lock_assume_sync` method optimized
                 // for that case.
@@ -127,11 +117,7 @@ impl<T> Sharded<T> {
     #[inline]
     pub fn lock_shards(&self) -> impl Iterator<Item = LockGuard<'_, T>> {
         match self {
-            #[cfg(not(parallel_compiler))]
-            Self::Single(single) => iter::once(single.lock()),
-            #[cfg(parallel_compiler)]
             Self::Single(single) => Either::Left(iter::once(single.lock())),
-            #[cfg(parallel_compiler)]
             Self::Shards(shards) => Either::Right(shards.iter().map(|shard| shard.0.lock())),
         }
     }
@@ -139,11 +125,7 @@ impl<T> Sharded<T> {
     #[inline]
     pub fn try_lock_shards(&self) -> impl Iterator<Item = Option<LockGuard<'_, T>>> {
         match self {
-            #[cfg(not(parallel_compiler))]
-            Self::Single(single) => iter::once(single.try_lock()),
-            #[cfg(parallel_compiler)]
             Self::Single(single) => Either::Left(iter::once(single.try_lock())),
-            #[cfg(parallel_compiler)]
             Self::Shards(shards) => Either::Right(shards.iter().map(|shard| shard.0.try_lock())),
         }
     }
@@ -151,7 +133,6 @@ impl<T> Sharded<T> {
 
 #[inline]
 pub fn shards() -> usize {
-    #[cfg(parallel_compiler)]
     if is_dyn_thread_safe() {
         return SHARDS;
     }
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index a3491dbfec7..7a9533031f4 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -54,9 +54,7 @@ mod worker_local;
 pub use worker_local::{Registry, WorkerLocal};
 
 mod parallel;
-#[cfg(parallel_compiler)]
-pub use parallel::scope;
-pub use parallel::{join, par_for_each_in, par_map, parallel_guard, try_par_for_each_in};
+pub use parallel::{join, par_for_each_in, par_map, parallel_guard, scope, try_par_for_each_in};
 pub use vec::{AppendOnlyIndexVec, AppendOnlyVec};
 
 mod vec;
@@ -104,226 +102,66 @@ mod mode {
     }
 }
 
-pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
-
-cfg_match! {
-    cfg(not(parallel_compiler)) => {
-        use std::ops::Add;
-        use std::cell::Cell;
-        use std::sync::atomic::Ordering;
-
-        pub unsafe auto trait Send {}
-        pub unsafe auto trait Sync {}
-
-        unsafe impl<T> Send for T {}
-        unsafe impl<T> Sync for T {}
-
-        /// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
-        /// It has explicit ordering arguments and is only intended for use with
-        /// the native atomic types.
-        /// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases
-        /// as it's not intended to be used separately.
-        #[derive(Debug, Default)]
-        pub struct Atomic<T: Copy>(Cell<T>);
-
-        impl<T: Copy> Atomic<T> {
-            #[inline]
-            pub fn new(v: T) -> Self {
-                Atomic(Cell::new(v))
-            }
-
-            #[inline]
-            pub fn into_inner(self) -> T {
-                self.0.into_inner()
-            }
-
-            #[inline]
-            pub fn load(&self, _: Ordering) -> T {
-                self.0.get()
-            }
-
-            #[inline]
-            pub fn store(&self, val: T, _: Ordering) {
-                self.0.set(val)
-            }
-
-            #[inline]
-            pub fn swap(&self, val: T, _: Ordering) -> T {
-                self.0.replace(val)
-            }
-        }
+// FIXME(parallel_compiler): Get rid of these aliases across the compiler.
 
-        impl Atomic<bool> {
-            pub fn fetch_or(&self, val: bool, _: Ordering) -> bool {
-                let old = self.0.get();
-                self.0.set(val | old);
-                old
-            }
-            pub fn fetch_and(&self, val: bool, _: Ordering) -> bool {
-                let old = self.0.get();
-                self.0.set(val & old);
-                old
-            }
-        }
+pub use std::marker::{Send, Sync};
+// Use portable AtomicU64 for targets without native 64-bit atomics
+#[cfg(target_has_atomic = "64")]
+pub use std::sync::atomic::AtomicU64;
+pub use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize};
+pub use std::sync::{Arc as Lrc, OnceLock, Weak};
 
-        impl<T: Copy + PartialEq> Atomic<T> {
-            #[inline]
-            pub fn compare_exchange(&self,
-                                    current: T,
-                                    new: T,
-                                    _: Ordering,
-                                    _: Ordering)
-                                    -> Result<T, T> {
-                let read = self.0.get();
-                if read == current {
-                    self.0.set(new);
-                    Ok(read)
-                } else {
-                    Err(read)
-                }
-            }
-        }
+pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
+pub use parking_lot::{
+    MappedMutexGuard as MappedLockGuard, MappedRwLockReadGuard as MappedReadGuard,
+    MappedRwLockWriteGuard as MappedWriteGuard, RwLockReadGuard as ReadGuard,
+    RwLockWriteGuard as WriteGuard,
+};
+#[cfg(not(target_has_atomic = "64"))]
+pub use portable_atomic::AtomicU64;
 
-        impl<T: Add<Output=T> + Copy> Atomic<T> {
-            #[inline]
-            pub fn fetch_add(&self, val: T, _: Ordering) -> T {
-                let old = self.0.get();
-                self.0.set(old + val);
-                old
-            }
-        }
+pub type LRef<'a, T> = &'a T;
 
-        pub type AtomicUsize = Atomic<usize>;
-        pub type AtomicBool = Atomic<bool>;
-        pub type AtomicU32 = Atomic<u32>;
-        pub type AtomicU64 = Atomic<u64>;
-
-        pub use std::rc::Rc as Lrc;
-        pub use std::rc::Weak as Weak;
-        #[doc(no_inline)]
-        pub use std::cell::Ref as ReadGuard;
-        #[doc(no_inline)]
-        pub use std::cell::Ref as MappedReadGuard;
-        #[doc(no_inline)]
-        pub use std::cell::RefMut as WriteGuard;
-        #[doc(no_inline)]
-        pub use std::cell::RefMut as MappedWriteGuard;
-        #[doc(no_inline)]
-        pub use std::cell::RefMut as MappedLockGuard;
-
-        pub use std::cell::OnceCell as OnceLock;
-
-        use std::cell::RefCell as InnerRwLock;
-
-        pub type LRef<'a, T> = &'a mut T;
-
-        #[derive(Debug, Default)]
-        pub struct MTLock<T>(T);
-
-        impl<T> MTLock<T> {
-            #[inline(always)]
-            pub fn new(inner: T) -> Self {
-                MTLock(inner)
-            }
-
-            #[inline(always)]
-            pub fn into_inner(self) -> T {
-                self.0
-            }
-
-            #[inline(always)]
-            pub fn get_mut(&mut self) -> &mut T {
-                &mut self.0
-            }
-
-            #[inline(always)]
-            pub fn lock(&self) -> &T {
-                &self.0
-            }
-
-            #[inline(always)]
-            pub fn lock_mut(&mut self) -> &mut T {
-                &mut self.0
-            }
-        }
+#[derive(Debug, Default)]
+pub struct MTLock<T>(Lock<T>);
 
-        // FIXME: Probably a bad idea (in the threaded case)
-        impl<T: Clone> Clone for MTLock<T> {
-            #[inline]
-            fn clone(&self) -> Self {
-                MTLock(self.0.clone())
-            }
-        }
+impl<T> MTLock<T> {
+    #[inline(always)]
+    pub fn new(inner: T) -> Self {
+        MTLock(Lock::new(inner))
     }
-    _ => {
-        pub use std::marker::Send as Send;
-        pub use std::marker::Sync as Sync;
-
-        pub use parking_lot::RwLockReadGuard as ReadGuard;
-        pub use parking_lot::MappedRwLockReadGuard as MappedReadGuard;
-        pub use parking_lot::RwLockWriteGuard as WriteGuard;
-        pub use parking_lot::MappedRwLockWriteGuard as MappedWriteGuard;
-
-        pub use parking_lot::MappedMutexGuard as MappedLockGuard;
 
-        pub use std::sync::OnceLock;
-
-        pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32};
-
-        // Use portable AtomicU64 for targets without native 64-bit atomics
-        #[cfg(target_has_atomic = "64")]
-        pub use std::sync::atomic::AtomicU64;
-
-        #[cfg(not(target_has_atomic = "64"))]
-        pub use portable_atomic::AtomicU64;
-
-        pub use std::sync::Arc as Lrc;
-        pub use std::sync::Weak as Weak;
-
-        pub type LRef<'a, T> = &'a T;
-
-        #[derive(Debug, Default)]
-        pub struct MTLock<T>(Lock<T>);
-
-        impl<T> MTLock<T> {
-            #[inline(always)]
-            pub fn new(inner: T) -> Self {
-                MTLock(Lock::new(inner))
-            }
-
-            #[inline(always)]
-            pub fn into_inner(self) -> T {
-                self.0.into_inner()
-            }
-
-            #[inline(always)]
-            pub fn get_mut(&mut self) -> &mut T {
-                self.0.get_mut()
-            }
-
-            #[inline(always)]
-            pub fn lock(&self) -> LockGuard<'_, T> {
-                self.0.lock()
-            }
+    #[inline(always)]
+    pub fn into_inner(self) -> T {
+        self.0.into_inner()
+    }
 
-            #[inline(always)]
-            pub fn lock_mut(&self) -> LockGuard<'_, T> {
-                self.lock()
-            }
-        }
+    #[inline(always)]
+    pub fn get_mut(&mut self) -> &mut T {
+        self.0.get_mut()
+    }
 
-        use parking_lot::RwLock as InnerRwLock;
+    #[inline(always)]
+    pub fn lock(&self) -> LockGuard<'_, T> {
+        self.0.lock()
+    }
 
-        /// This makes locks panic if they are already held.
-        /// It is only useful when you are running in a single thread
-        const ERROR_CHECKING: bool = false;
+    #[inline(always)]
+    pub fn lock_mut(&self) -> LockGuard<'_, T> {
+        self.lock()
     }
 }
 
+use parking_lot::RwLock as InnerRwLock;
+
+/// This makes locks panic if they are already held.
+/// It is only useful when you are running in a single thread
+const ERROR_CHECKING: bool = false;
+
 pub type MTLockRef<'a, T> = LRef<'a, MTLock<T>>;
 
 #[derive(Default)]
-#[cfg_attr(parallel_compiler, repr(align(64)))]
+#[repr(align(64))]
 pub struct CacheAligned<T>(pub T);
 
 pub trait HashMapExt<K, V> {
@@ -357,14 +195,6 @@ impl<T> RwLock<T> {
         self.0.get_mut()
     }
 
-    #[cfg(not(parallel_compiler))]
-    #[inline(always)]
-    #[track_caller]
-    pub fn read(&self) -> ReadGuard<'_, T> {
-        self.0.borrow()
-    }
-
-    #[cfg(parallel_compiler)]
     #[inline(always)]
     pub fn read(&self) -> ReadGuard<'_, T> {
         if ERROR_CHECKING {
@@ -380,26 +210,11 @@ impl<T> RwLock<T> {
         f(&*self.read())
     }
 
-    #[cfg(not(parallel_compiler))]
-    #[inline(always)]
-    pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
-        self.0.try_borrow_mut().map_err(|_| ())
-    }
-
-    #[cfg(parallel_compiler)]
     #[inline(always)]
     pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
         self.0.try_write().ok_or(())
     }
 
-    #[cfg(not(parallel_compiler))]
-    #[inline(always)]
-    #[track_caller]
-    pub fn write(&self) -> WriteGuard<'_, T> {
-        self.0.borrow_mut()
-    }
-
-    #[cfg(parallel_compiler)]
     #[inline(always)]
     pub fn write(&self) -> WriteGuard<'_, T> {
         if ERROR_CHECKING {
@@ -427,13 +242,6 @@ impl<T> RwLock<T> {
         self.write()
     }
 
-    #[cfg(not(parallel_compiler))]
-    #[inline(always)]
-    pub fn leak(&self) -> &T {
-        ReadGuard::leak(self.read())
-    }
-
-    #[cfg(parallel_compiler)]
     #[inline(always)]
     pub fn leak(&self) -> &T {
         let guard = self.read();
diff --git a/compiler/rustc_data_structures/src/sync/freeze.rs b/compiler/rustc_data_structures/src/sync/freeze.rs
index fad5f583d1c..5236c9fe156 100644
--- a/compiler/rustc_data_structures/src/sync/freeze.rs
+++ b/compiler/rustc_data_structures/src/sync/freeze.rs
@@ -5,9 +5,7 @@ use std::ops::{Deref, DerefMut};
 use std::ptr::NonNull;
 use std::sync::atomic::Ordering;
 
-use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard};
-#[cfg(parallel_compiler)]
-use crate::sync::{DynSend, DynSync};
+use crate::sync::{AtomicBool, DynSend, DynSync, ReadGuard, RwLock, WriteGuard};
 
 /// A type which allows mutation using a lock until
 /// the value is frozen and can be accessed lock-free.
@@ -22,7 +20,6 @@ pub struct FreezeLock<T> {
     lock: RwLock<()>,
 }
 
-#[cfg(parallel_compiler)]
 unsafe impl<T: DynSync + DynSend> DynSync for FreezeLock<T> {}
 
 impl<T> FreezeLock<T> {
diff --git a/compiler/rustc_data_structures/src/sync/lock.rs b/compiler/rustc_data_structures/src/sync/lock.rs
index 012ee7f900e..2ccf06ccd4f 100644
--- a/compiler/rustc_data_structures/src/sync/lock.rs
+++ b/compiler/rustc_data_structures/src/sync/lock.rs
@@ -1,236 +1,177 @@
 //! This module implements a lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
 //! It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync` traits.
-//!
-//! When `cfg(parallel_compiler)` is not set, the lock is instead a wrapper around `RefCell`.
 
 #![allow(dead_code)]
 
 use std::fmt;
 
-#[cfg(parallel_compiler)]
-pub use maybe_sync::*;
-#[cfg(not(parallel_compiler))]
-pub use no_sync::*;
-
 #[derive(Clone, Copy, PartialEq)]
 pub enum Mode {
     NoSync,
     Sync,
 }
 
-mod maybe_sync {
-    use std::cell::{Cell, UnsafeCell};
-    use std::intrinsics::unlikely;
-    use std::marker::PhantomData;
-    use std::mem::ManuallyDrop;
-    use std::ops::{Deref, DerefMut};
+use std::cell::{Cell, UnsafeCell};
+use std::intrinsics::unlikely;
+use std::marker::PhantomData;
+use std::mem::ManuallyDrop;
+use std::ops::{Deref, DerefMut};
 
-    use parking_lot::RawMutex;
-    use parking_lot::lock_api::RawMutex as _;
+use parking_lot::RawMutex;
+use parking_lot::lock_api::RawMutex as _;
 
-    use super::Mode;
-    use crate::sync::mode;
-    #[cfg(parallel_compiler)]
-    use crate::sync::{DynSend, DynSync};
+use crate::sync::{DynSend, DynSync, mode};
 
-    /// A guard holding mutable access to a `Lock` which is in a locked state.
-    #[must_use = "if unused the Lock will immediately unlock"]
-    pub struct LockGuard<'a, T> {
-        lock: &'a Lock<T>,
-        marker: PhantomData<&'a mut T>,
+/// A guard holding mutable access to a `Lock` which is in a locked state.
+#[must_use = "if unused the Lock will immediately unlock"]
+pub struct LockGuard<'a, T> {
+    lock: &'a Lock<T>,
+    marker: PhantomData<&'a mut T>,
 
-        /// The synchronization mode of the lock. This is explicitly passed to let LLVM relate it
-        /// to the original lock operation.
-        mode: Mode,
-    }
+    /// The synchronization mode of the lock. This is explicitly passed to let LLVM relate it
+    /// to the original lock operation.
+    mode: Mode,
+}
 
-    impl<'a, T: 'a> Deref for LockGuard<'a, T> {
-        type Target = T;
-        #[inline]
-        fn deref(&self) -> &T {
-            // SAFETY: We have shared access to the mutable access owned by this type,
-            // so we can give out a shared reference.
-            unsafe { &*self.lock.data.get() }
-        }
+impl<'a, T: 'a> Deref for LockGuard<'a, T> {
+    type Target = T;
+    #[inline]
+    fn deref(&self) -> &T {
+        // SAFETY: We have shared access to the mutable access owned by this type,
+        // so we can give out a shared reference.
+        unsafe { &*self.lock.data.get() }
     }
+}
 
-    impl<'a, T: 'a> DerefMut for LockGuard<'a, T> {
-        #[inline]
-        fn deref_mut(&mut self) -> &mut T {
-            // SAFETY: We have mutable access to the data so we can give out a mutable reference.
-            unsafe { &mut *self.lock.data.get() }
-        }
+impl<'a, T: 'a> DerefMut for LockGuard<'a, T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut T {
+        // SAFETY: We have mutable access to the data so we can give out a mutable reference.
+        unsafe { &mut *self.lock.data.get() }
     }
+}
 
-    impl<'a, T: 'a> Drop for LockGuard<'a, T> {
-        #[inline]
-        fn drop(&mut self) {
-            // SAFETY (union access): We get `self.mode` from the lock operation so it is consistent
-            // with the `lock.mode` state. This means we access the right union fields.
-            match self.mode {
-                Mode::NoSync => {
-                    let cell = unsafe { &self.lock.mode_union.no_sync };
-                    debug_assert!(cell.get());
-                    cell.set(false);
-                }
-                // SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
-                Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() },
+impl<'a, T: 'a> Drop for LockGuard<'a, T> {
+    #[inline]
+    fn drop(&mut self) {
+        // SAFETY (union access): We get `self.mode` from the lock operation so it is consistent
+        // with the `lock.mode` state. This means we access the right union fields.
+        match self.mode {
+            Mode::NoSync => {
+                let cell = unsafe { &self.lock.mode_union.no_sync };
+                debug_assert!(cell.get());
+                cell.set(false);
             }
+            // SAFETY (unlock): We know that the lock is locked as this type is a proof of that.
+            Mode::Sync => unsafe { self.lock.mode_union.sync.unlock() },
         }
     }
+}
 
-    union ModeUnion {
-        /// Indicates if the cell is locked. Only used if `Lock.mode` is `NoSync`.
-        no_sync: ManuallyDrop<Cell<bool>>,
+union ModeUnion {
+    /// Indicates if the cell is locked. Only used if `Lock.mode` is `NoSync`.
+    no_sync: ManuallyDrop<Cell<bool>>,
 
-        /// A lock implementation that's only used if `Lock.mode` is `Sync`.
-        sync: ManuallyDrop<RawMutex>,
-    }
+    /// A lock implementation that's only used if `Lock.mode` is `Sync`.
+    sync: ManuallyDrop<RawMutex>,
+}
 
-    /// The value representing a locked state for the `Cell`.
-    const LOCKED: bool = true;
+/// The value representing a locked state for the `Cell`.
+const LOCKED: bool = true;
 
-    /// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
-    /// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
-    pub struct Lock<T> {
-        /// Indicates if synchronization is used via `mode_union.sync` if it's `Sync`, or if a
-        /// not thread safe cell is used via `mode_union.no_sync` if it's `NoSync`.
-        /// This is set on initialization and never changed.
-        mode: Mode,
+/// A lock which only uses synchronization if `might_be_dyn_thread_safe` is true.
+/// It implements `DynSend` and `DynSync` instead of the typical `Send` and `Sync`.
+pub struct Lock<T> {
+    /// Indicates if synchronization is used via `mode_union.sync` if it's `Sync`, or if a
+    /// not thread safe cell is used via `mode_union.no_sync` if it's `NoSync`.
+    /// This is set on initialization and never changed.
+    mode: Mode,
 
-        mode_union: ModeUnion,
-        data: UnsafeCell<T>,
-    }
+    mode_union: ModeUnion,
+    data: UnsafeCell<T>,
+}
 
-    impl<T> Lock<T> {
-        #[inline(always)]
-        pub fn new(inner: T) -> Self {
-            let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) {
-                // Create the lock with synchronization enabled using the `RawMutex` type.
-                (Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) })
-            } else {
-                // Create the lock with synchronization disabled.
-                (Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) })
-            };
-            Lock { mode, mode_union, data: UnsafeCell::new(inner) }
-        }
+impl<T> Lock<T> {
+    #[inline(always)]
+    pub fn new(inner: T) -> Self {
+        let (mode, mode_union) = if unlikely(mode::might_be_dyn_thread_safe()) {
+            // Create the lock with synchronization enabled using the `RawMutex` type.
+            (Mode::Sync, ModeUnion { sync: ManuallyDrop::new(RawMutex::INIT) })
+        } else {
+            // Create the lock with synchronization disabled.
+            (Mode::NoSync, ModeUnion { no_sync: ManuallyDrop::new(Cell::new(!LOCKED)) })
+        };
+        Lock { mode, mode_union, data: UnsafeCell::new(inner) }
+    }
 
-        #[inline(always)]
-        pub fn into_inner(self) -> T {
-            self.data.into_inner()
-        }
+    #[inline(always)]
+    pub fn into_inner(self) -> T {
+        self.data.into_inner()
+    }
 
-        #[inline(always)]
-        pub fn get_mut(&mut self) -> &mut T {
-            self.data.get_mut()
-        }
+    #[inline(always)]
+    pub fn get_mut(&mut self) -> &mut T {
+        self.data.get_mut()
+    }
 
-        #[inline(always)]
-        pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
-            let mode = self.mode;
-            // SAFETY: This is safe since the union fields are used in accordance with `self.mode`.
-            match mode {
-                Mode::NoSync => {
-                    let cell = unsafe { &self.mode_union.no_sync };
-                    let was_unlocked = cell.get() != LOCKED;
-                    if was_unlocked {
-                        cell.set(LOCKED);
-                    }
-                    was_unlocked
+    #[inline(always)]
+    pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
+        let mode = self.mode;
+        // SAFETY: This is safe since the union fields are used in accordance with `self.mode`.
+        match mode {
+            Mode::NoSync => {
+                let cell = unsafe { &self.mode_union.no_sync };
+                let was_unlocked = cell.get() != LOCKED;
+                if was_unlocked {
+                    cell.set(LOCKED);
                 }
-                Mode::Sync => unsafe { self.mode_union.sync.try_lock() },
+                was_unlocked
             }
-            .then(|| LockGuard { lock: self, marker: PhantomData, mode })
+            Mode::Sync => unsafe { self.mode_union.sync.try_lock() },
         }
+        .then(|| LockGuard { lock: self, marker: PhantomData, mode })
+    }
 
-        /// This acquires the lock assuming synchronization is in a specific mode.
-        ///
-        /// Safety
-        /// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was
-        /// true on lock creation.
-        #[inline(always)]
+    /// This acquires the lock assuming synchronization is in a specific mode.
+    ///
+    /// Safety
+    /// This method must only be called with `Mode::Sync` if `might_be_dyn_thread_safe` was
+    /// true on lock creation.
+    #[inline(always)]
+    #[track_caller]
+    pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> {
+        #[inline(never)]
         #[track_caller]
-        pub unsafe fn lock_assume(&self, mode: Mode) -> LockGuard<'_, T> {
-            #[inline(never)]
-            #[track_caller]
-            #[cold]
-            fn lock_held() -> ! {
-                panic!("lock was already held")
-            }
+        #[cold]
+        fn lock_held() -> ! {
+            panic!("lock was already held")
+        }
 
-            // SAFETY: This is safe since the union fields are used in accordance with `mode`
-            // which also must match `self.mode` due to the safety precondition.
-            unsafe {
-                match mode {
-                    Mode::NoSync => {
-                        if unlikely(self.mode_union.no_sync.replace(LOCKED) == LOCKED) {
-                            lock_held()
-                        }
+        // SAFETY: This is safe since the union fields are used in accordance with `mode`
+        // which also must match `self.mode` due to the safety precondition.
+        unsafe {
+            match mode {
+                Mode::NoSync => {
+                    if unlikely(self.mode_union.no_sync.replace(LOCKED) == LOCKED) {
+                        lock_held()
                     }
-                    Mode::Sync => self.mode_union.sync.lock(),
                 }
+                Mode::Sync => self.mode_union.sync.lock(),
             }
-            LockGuard { lock: self, marker: PhantomData, mode }
-        }
-
-        #[inline(always)]
-        #[track_caller]
-        pub fn lock(&self) -> LockGuard<'_, T> {
-            unsafe { self.lock_assume(self.mode) }
         }
+        LockGuard { lock: self, marker: PhantomData, mode }
     }
 
-    #[cfg(parallel_compiler)]
-    unsafe impl<T: DynSend> DynSend for Lock<T> {}
-    #[cfg(parallel_compiler)]
-    unsafe impl<T: DynSend> DynSync for Lock<T> {}
-}
-
-mod no_sync {
-    use std::cell::RefCell;
-    #[doc(no_inline)]
-    pub use std::cell::RefMut as LockGuard;
-
-    use super::Mode;
-
-    pub struct Lock<T>(RefCell<T>);
-
-    impl<T> Lock<T> {
-        #[inline(always)]
-        pub fn new(inner: T) -> Self {
-            Lock(RefCell::new(inner))
-        }
-
-        #[inline(always)]
-        pub fn into_inner(self) -> T {
-            self.0.into_inner()
-        }
-
-        #[inline(always)]
-        pub fn get_mut(&mut self) -> &mut T {
-            self.0.get_mut()
-        }
-
-        #[inline(always)]
-        pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
-            self.0.try_borrow_mut().ok()
-        }
-
-        #[inline(always)]
-        #[track_caller]
-        // This is unsafe to match the API for the `parallel_compiler` case.
-        pub unsafe fn lock_assume(&self, _mode: Mode) -> LockGuard<'_, T> {
-            self.0.borrow_mut()
-        }
-
-        #[inline(always)]
-        #[track_caller]
-        pub fn lock(&self) -> LockGuard<'_, T> {
-            self.0.borrow_mut()
-        }
+    #[inline(always)]
+    #[track_caller]
+    pub fn lock(&self) -> LockGuard<'_, T> {
+        unsafe { self.lock_assume(self.mode) }
     }
 }
 
+unsafe impl<T: DynSend> DynSend for Lock<T> {}
+unsafe impl<T: DynSend> DynSync for Lock<T> {}
+
 impl<T> Lock<T> {
     #[inline(always)]
     #[track_caller]
diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs
index c7df19842d6..1ba631b8623 100644
--- a/compiler/rustc_data_structures/src/sync/parallel.rs
+++ b/compiler/rustc_data_structures/src/sync/parallel.rs
@@ -6,14 +6,11 @@
 use std::any::Any;
 use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
 
-#[cfg(not(parallel_compiler))]
-pub use disabled::*;
-#[cfg(parallel_compiler)]
-pub use enabled::*;
 use parking_lot::Mutex;
+use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
 
 use crate::FatalErrorMarker;
-use crate::sync::IntoDynSyncSend;
+use crate::sync::{DynSend, DynSync, FromDyn, IntoDynSyncSend, mode};
 
 /// A guard used to hold panics that occur during a parallel section to later by unwound.
 /// This is used for the parallel compiler to prevent fatal errors from non-deterministically
@@ -49,65 +46,23 @@ pub fn parallel_guard<R>(f: impl FnOnce(&ParallelGuard) -> R) -> R {
     ret
 }
 
-mod disabled {
-    use crate::sync::parallel_guard;
-
-    #[macro_export]
-    #[cfg(not(parallel_compiler))]
-    macro_rules! parallel {
-        ($($blocks:block),*) => {{
-            $crate::sync::parallel_guard(|guard| {
-                $(guard.run(|| $blocks);)*
-            });
-        }}
-    }
-
-    pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
-    where
-        A: FnOnce() -> RA,
-        B: FnOnce() -> RB,
-    {
-        let (a, b) = parallel_guard(|guard| {
-            let a = guard.run(oper_a);
-            let b = guard.run(oper_b);
-            (a, b)
-        });
-        (a.unwrap(), b.unwrap())
-    }
-
-    pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item)) {
-        parallel_guard(|guard| {
-            t.into_iter().for_each(|i| {
-                guard.run(|| for_each(i));
-            });
-        })
-    }
-
-    pub fn try_par_for_each_in<T: IntoIterator, E>(
-        t: T,
-        mut for_each: impl FnMut(T::Item) -> Result<(), E>,
-    ) -> Result<(), E> {
-        parallel_guard(|guard| {
-            t.into_iter().filter_map(|i| guard.run(|| for_each(i))).fold(Ok(()), Result::and)
-        })
-    }
-
-    pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
-        t: T,
-        mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
-    ) -> C {
-        parallel_guard(|guard| t.into_iter().filter_map(|i| guard.run(|| map(i))).collect())
-    }
+pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+where
+    A: FnOnce() -> RA,
+    B: FnOnce() -> RB,
+{
+    let (a, b) = parallel_guard(|guard| {
+        let a = guard.run(oper_a);
+        let b = guard.run(oper_b);
+        (a, b)
+    });
+    (a.unwrap(), b.unwrap())
 }
 
-#[cfg(parallel_compiler)]
-mod enabled {
-    use crate::sync::{DynSend, DynSync, FromDyn, mode, parallel_guard};
-
-    /// Runs a list of blocks in parallel. The first block is executed immediately on
-    /// the current thread. Use that for the longest running block.
-    #[macro_export]
-    macro_rules! parallel {
+/// Runs a list of blocks in parallel. The first block is executed immediately on
+/// the current thread. Use that for the longest running block.
+#[macro_export]
+macro_rules! parallel {
         (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => {
             parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
         };
@@ -139,92 +94,89 @@ mod enabled {
         };
     }
 
-    // This function only works when `mode::is_dyn_thread_safe()`.
-    pub fn scope<'scope, OP, R>(op: OP) -> R
-    where
-        OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
-        R: DynSend,
-    {
-        let op = FromDyn::from(op);
-        rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
+// This function only works when `mode::is_dyn_thread_safe()`.
+pub fn scope<'scope, OP, R>(op: OP) -> R
+where
+    OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
+    R: DynSend,
+{
+    let op = FromDyn::from(op);
+    rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
+}
+
+#[inline]
+pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
+where
+    A: FnOnce() -> RA + DynSend,
+    B: FnOnce() -> RB + DynSend,
+{
+    if mode::is_dyn_thread_safe() {
+        let oper_a = FromDyn::from(oper_a);
+        let oper_b = FromDyn::from(oper_b);
+        let (a, b) = parallel_guard(|guard| {
+            rayon::join(
+                move || guard.run(move || FromDyn::from(oper_a.into_inner()())),
+                move || guard.run(move || FromDyn::from(oper_b.into_inner()())),
+            )
+        });
+        (a.unwrap().into_inner(), b.unwrap().into_inner())
+    } else {
+        serial_join(oper_a, oper_b)
     }
+}
 
-    #[inline]
-    pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
-    where
-        A: FnOnce() -> RA + DynSend,
-        B: FnOnce() -> RB + DynSend,
-    {
+pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
+    t: T,
+    for_each: impl Fn(I) + DynSync + DynSend,
+) {
+    parallel_guard(|guard| {
         if mode::is_dyn_thread_safe() {
-            let oper_a = FromDyn::from(oper_a);
-            let oper_b = FromDyn::from(oper_b);
-            let (a, b) = parallel_guard(|guard| {
-                rayon::join(
-                    move || guard.run(move || FromDyn::from(oper_a.into_inner()())),
-                    move || guard.run(move || FromDyn::from(oper_b.into_inner()())),
-                )
+            let for_each = FromDyn::from(for_each);
+            t.into_par_iter().for_each(|i| {
+                guard.run(|| for_each(i));
             });
-            (a.unwrap().into_inner(), b.unwrap().into_inner())
         } else {
-            super::disabled::join(oper_a, oper_b)
+            t.into_iter().for_each(|i| {
+                guard.run(|| for_each(i));
+            });
         }
-    }
-
-    use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
-
-    pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
-        t: T,
-        for_each: impl Fn(I) + DynSync + DynSend,
-    ) {
-        parallel_guard(|guard| {
-            if mode::is_dyn_thread_safe() {
-                let for_each = FromDyn::from(for_each);
-                t.into_par_iter().for_each(|i| {
-                    guard.run(|| for_each(i));
-                });
-            } else {
-                t.into_iter().for_each(|i| {
-                    guard.run(|| for_each(i));
-                });
-            }
-        });
-    }
+    });
+}
 
-    pub fn try_par_for_each_in<
-        T: IntoIterator + IntoParallelIterator<Item = <T as IntoIterator>::Item>,
-        E: Send,
-    >(
-        t: T,
-        for_each: impl Fn(<T as IntoIterator>::Item) -> Result<(), E> + DynSync + DynSend,
-    ) -> Result<(), E> {
-        parallel_guard(|guard| {
-            if mode::is_dyn_thread_safe() {
-                let for_each = FromDyn::from(for_each);
-                t.into_par_iter()
-                    .filter_map(|i| guard.run(|| for_each(i)))
-                    .reduce(|| Ok(()), Result::and)
-            } else {
-                t.into_iter().filter_map(|i| guard.run(|| for_each(i))).fold(Ok(()), Result::and)
-            }
-        })
-    }
+pub fn try_par_for_each_in<
+    T: IntoIterator + IntoParallelIterator<Item = <T as IntoIterator>::Item>,
+    E: Send,
+>(
+    t: T,
+    for_each: impl Fn(<T as IntoIterator>::Item) -> Result<(), E> + DynSync + DynSend,
+) -> Result<(), E> {
+    parallel_guard(|guard| {
+        if mode::is_dyn_thread_safe() {
+            let for_each = FromDyn::from(for_each);
+            t.into_par_iter()
+                .filter_map(|i| guard.run(|| for_each(i)))
+                .reduce(|| Ok(()), Result::and)
+        } else {
+            t.into_iter().filter_map(|i| guard.run(|| for_each(i))).fold(Ok(()), Result::and)
+        }
+    })
+}
 
-    pub fn par_map<
-        I,
-        T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
-        R: std::marker::Send,
-        C: FromIterator<R> + FromParallelIterator<R>,
-    >(
-        t: T,
-        map: impl Fn(I) -> R + DynSync + DynSend,
-    ) -> C {
-        parallel_guard(|guard| {
-            if mode::is_dyn_thread_safe() {
-                let map = FromDyn::from(map);
-                t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect()
-            } else {
-                t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
-            }
-        })
-    }
+pub fn par_map<
+    I,
+    T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
+    R: std::marker::Send,
+    C: FromIterator<R> + FromParallelIterator<R>,
+>(
+    t: T,
+    map: impl Fn(I) -> R + DynSync + DynSend,
+) -> C {
+    parallel_guard(|guard| {
+        if mode::is_dyn_thread_safe() {
+            let map = FromDyn::from(map);
+            t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect()
+        } else {
+            t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()
+        }
+    })
 }
diff --git a/compiler/rustc_data_structures/src/sync/vec.rs b/compiler/rustc_data_structures/src/sync/vec.rs
index 314496ce9f0..21ec5cf6c13 100644
--- a/compiler/rustc_data_structures/src/sync/vec.rs
+++ b/compiler/rustc_data_structures/src/sync/vec.rs
@@ -4,40 +4,23 @@ use rustc_index::Idx;
 
 #[derive(Default)]
 pub struct AppendOnlyIndexVec<I: Idx, T: Copy> {
-    #[cfg(not(parallel_compiler))]
-    vec: elsa::vec::FrozenVec<T>,
-    #[cfg(parallel_compiler)]
     vec: elsa::sync::LockFreeFrozenVec<T>,
     _marker: PhantomData<fn(&I)>,
 }
 
 impl<I: Idx, T: Copy> AppendOnlyIndexVec<I, T> {
     pub fn new() -> Self {
-        Self {
-            #[cfg(not(parallel_compiler))]
-            vec: elsa::vec::FrozenVec::new(),
-            #[cfg(parallel_compiler)]
-            vec: elsa::sync::LockFreeFrozenVec::new(),
-            _marker: PhantomData,
-        }
+        Self { vec: elsa::sync::LockFreeFrozenVec::new(), _marker: PhantomData }
     }
 
     pub fn push(&self, val: T) -> I {
-        #[cfg(not(parallel_compiler))]
-        let i = self.vec.len();
-        #[cfg(not(parallel_compiler))]
-        self.vec.push(val);
-        #[cfg(parallel_compiler)]
         let i = self.vec.push(val);
         I::new(i)
     }
 
     pub fn get(&self, i: I) -> Option<T> {
         let i = i.index();
-        #[cfg(not(parallel_compiler))]
-        return self.vec.get_copy(i);
-        #[cfg(parallel_compiler)]
-        return self.vec.get(i);
+        self.vec.get(i)
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs
index b6efcada10b..d75af009850 100644
--- a/compiler/rustc_data_structures/src/sync/worker_local.rs
+++ b/compiler/rustc_data_structures/src/sync/worker_local.rs
@@ -5,8 +5,9 @@ use std::ptr;
 use std::sync::Arc;
 
 use parking_lot::Mutex;
-#[cfg(parallel_compiler)]
-use {crate::outline, crate::sync::CacheAligned};
+
+use crate::outline;
+use crate::sync::CacheAligned;
 
 /// A pointer to the `RegistryData` which uniquely identifies a registry.
 /// This identifier can be reused if the registry gets freed.
@@ -21,7 +22,6 @@ impl RegistryId {
     ///
     /// Note that there's a race possible where the identifier in `THREAD_DATA` could be reused
     /// so this can succeed from a different registry.
-    #[cfg(parallel_compiler)]
     fn verify(self) -> usize {
         let (id, index) = THREAD_DATA.with(|data| (data.registry_id.get(), data.index.get()));
 
@@ -102,11 +102,7 @@ impl Registry {
 /// worker local value through the `Deref` impl on the registry associated with the thread it was
 /// created on. It will panic otherwise.
 pub struct WorkerLocal<T> {
-    #[cfg(not(parallel_compiler))]
-    local: T,
-    #[cfg(parallel_compiler)]
     locals: Box<[CacheAligned<T>]>,
-    #[cfg(parallel_compiler)]
     registry: Registry,
 }
 
@@ -114,7 +110,6 @@ pub struct WorkerLocal<T> {
 // or it will panic for threads without an associated local. So there isn't a need for `T` to do
 // it's own synchronization. The `verify` method on `RegistryId` has an issue where the id
 // can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse.
-#[cfg(parallel_compiler)]
 unsafe impl<T: Send> Sync for WorkerLocal<T> {}
 
 impl<T> WorkerLocal<T> {
@@ -122,33 +117,17 @@ impl<T> WorkerLocal<T> {
     /// value this worker local should take for each thread in the registry.
     #[inline]
     pub fn new<F: FnMut(usize) -> T>(mut initial: F) -> WorkerLocal<T> {
-        #[cfg(parallel_compiler)]
-        {
-            let registry = Registry::current();
-            WorkerLocal {
-                locals: (0..registry.0.thread_limit.get())
-                    .map(|i| CacheAligned(initial(i)))
-                    .collect(),
-                registry,
-            }
-        }
-        #[cfg(not(parallel_compiler))]
-        {
-            WorkerLocal { local: initial(0) }
+        let registry = Registry::current();
+        WorkerLocal {
+            locals: (0..registry.0.thread_limit.get()).map(|i| CacheAligned(initial(i))).collect(),
+            registry,
         }
     }
 
     /// Returns the worker-local values for each thread
     #[inline]
     pub fn into_inner(self) -> impl Iterator<Item = T> {
-        #[cfg(parallel_compiler)]
-        {
-            self.locals.into_vec().into_iter().map(|local| local.0)
-        }
-        #[cfg(not(parallel_compiler))]
-        {
-            std::iter::once(self.local)
-        }
+        self.locals.into_vec().into_iter().map(|local| local.0)
     }
 }
 
@@ -156,13 +135,6 @@ impl<T> Deref for WorkerLocal<T> {
     type Target = T;
 
     #[inline(always)]
-    #[cfg(not(parallel_compiler))]
-    fn deref(&self) -> &T {
-        &self.local
-    }
-
-    #[inline(always)]
-    #[cfg(parallel_compiler)]
     fn deref(&self) -> &T {
         // This is safe because `verify` will only return values less than
         // `self.registry.thread_limit` which is the size of the `self.locals` array.
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 74da0d11e4b..81f15ebcbf8 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -77,9 +77,4 @@ rustc_randomized_layouts = [
     'rustc_index/rustc_randomized_layouts',
     'rustc_middle/rustc_randomized_layouts'
 ]
-rustc_use_parallel_compiler = [
-    'rustc_data_structures/rustc_use_parallel_compiler',
-    'rustc_interface/rustc_use_parallel_compiler',
-    'rustc_middle/rustc_use_parallel_compiler'
-]
 # tidy-alphabetical-end
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 78ba841d89f..b6f7abed6f3 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -934,9 +934,12 @@ pub fn version_at_macro_invocation(
 }
 
 fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
-    let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
     let mut options = getopts::Options::new();
-    for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
+    for option in config::rustc_optgroups()
+        .iter()
+        .filter(|x| verbose || !x.is_verbose_help_only)
+        .filter(|x| include_unstable_options || x.is_stable())
+    {
         option.apply(&mut options);
     }
     let message = "Usage: rustc [OPTIONS] INPUT";
diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml
index 5b6b8b3f183..6974c12f994 100644
--- a/compiler/rustc_error_messages/Cargo.toml
+++ b/compiler/rustc_error_messages/Cargo.toml
@@ -19,8 +19,3 @@ rustc_span = { path = "../rustc_span" }
 tracing = "0.1"
 unic-langid = { version = "0.9.0", features = ["macros"] }
 # tidy-alphabetical-end
-
-[features]
-# tidy-alphabetical-start
-rustc_use_parallel_compiler = ['rustc_baked_icu_data/rustc_use_parallel_compiler']
-# tidy-alphabetical-end
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 2ede7d805fa..74b6d63365a 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -8,12 +8,9 @@
 // tidy-alphabetical-end
 
 use std::borrow::Cow;
-#[cfg(not(parallel_compiler))]
-use std::cell::LazyCell as Lazy;
 use std::error::Error;
 use std::path::{Path, PathBuf};
-#[cfg(parallel_compiler)]
-use std::sync::LazyLock as Lazy;
+use std::sync::LazyLock;
 use std::{fmt, fs, io};
 
 use fluent_bundle::FluentResource;
@@ -21,9 +18,6 @@ pub use fluent_bundle::types::FluentType;
 pub use fluent_bundle::{self, FluentArgs, FluentError, FluentValue};
 use fluent_syntax::parser::ParserError;
 use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker};
-#[cfg(not(parallel_compiler))]
-use intl_memoizer::IntlLangMemoizer;
-#[cfg(parallel_compiler)]
 use intl_memoizer::concurrent::IntlLangMemoizer;
 use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
 use rustc_macros::{Decodable, Encodable};
@@ -34,12 +28,6 @@ pub use unic_langid::{LanguageIdentifier, langid};
 pub type FluentBundle =
     IntoDynSyncSend<fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>>;
 
-#[cfg(not(parallel_compiler))]
-fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle {
-    IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new(locales))
-}
-
-#[cfg(parallel_compiler)]
 fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle {
     IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new_concurrent(locales))
 }
@@ -217,7 +205,7 @@ fn register_functions(bundle: &mut FluentBundle) {
 
 /// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily
 /// evaluated fluent bundle.
-pub type LazyFallbackBundle = Lrc<Lazy<FluentBundle, impl FnOnce() -> FluentBundle>>;
+pub type LazyFallbackBundle = Lrc<LazyLock<FluentBundle, impl FnOnce() -> FluentBundle>>;
 
 /// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
 #[instrument(level = "trace", skip(resources))]
@@ -225,7 +213,7 @@ pub fn fallback_fluent_bundle(
     resources: Vec<&'static str>,
     with_directionality_markers: bool,
 ) -> LazyFallbackBundle {
-    Lrc::new(Lazy::new(move || {
+    Lrc::new(LazyLock::new(move || {
         let mut fallback_bundle = new_bundle(vec![langid!("en-US")]);
 
         register_functions(&mut fallback_bundle);
@@ -548,15 +536,6 @@ pub fn fluent_value_from_str_list_sep_by_and(l: Vec<Cow<'_, str>>) -> FluentValu
             Cow::Owned(result)
         }
 
-        #[cfg(not(parallel_compiler))]
-        fn as_string_threadsafe(
-            &self,
-            _intls: &intl_memoizer::concurrent::IntlLangMemoizer,
-        ) -> Cow<'static, str> {
-            unreachable!("`as_string_threadsafe` is not used in non-parallel rustc")
-        }
-
-        #[cfg(parallel_compiler)]
         fn as_string_threadsafe(
             &self,
             intls: &intl_memoizer::concurrent::IntlLangMemoizer,
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 41ebe4ae267..06bae57638f 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -36,8 +36,3 @@ features = [
     "Win32_Security",
     "Win32_System_Threading",
 ]
-
-[features]
-# tidy-alphabetical-start
-rustc_use_parallel_compiler = ['rustc_error_messages/rustc_use_parallel_compiler']
-# tidy-alphabetical-end
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 6552cf224ea..a386129e814 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -22,7 +22,7 @@ use rustc_error_messages::{FluentArgs, SpanLabel};
 use rustc_lint_defs::pluralize;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
-use rustc_span::{FileLines, FileName, SourceFile, Span, char_width};
+use rustc_span::{FileLines, FileName, SourceFile, Span, char_width, str_width};
 use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
 use tracing::{debug, instrument, trace, warn};
 
@@ -44,6 +44,7 @@ const DEFAULT_COLUMN_WIDTH: usize = 140;
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum HumanReadableErrorType {
     Default,
+    Unicode,
     AnnotateSnippet,
     Short,
 }
@@ -112,8 +113,12 @@ impl Margin {
     fn was_cut_right(&self, line_len: usize) -> bool {
         let right =
             if self.computed_right == self.span_right || self.computed_right == self.label_right {
+                // FIXME: This comment refers to the only callsite of this method.
+                //        Rephrase it or refactor it, so it can stand on its own.
                 // Account for the "..." padding given above. Otherwise we end up with code lines
                 // that do fit but end in "..." as if they were trimmed.
+                // FIXME: Don't hard-code this offset. Is this meant to represent
+                //        `2 * str_width(self.margin())`?
                 self.computed_right - 6
             } else {
                 self.computed_right
@@ -595,6 +600,12 @@ impl ColorConfig {
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum OutputTheme {
+    Ascii,
+    Unicode,
+}
+
 /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
 #[derive(Setters)]
 pub struct HumanEmitter {
@@ -613,6 +624,7 @@ pub struct HumanEmitter {
     macro_backtrace: bool,
     track_diagnostics: bool,
     terminal_url: TerminalUrl,
+    theme: OutputTheme,
 }
 
 #[derive(Debug)]
@@ -637,6 +649,7 @@ impl HumanEmitter {
             macro_backtrace: false,
             track_diagnostics: false,
             terminal_url: TerminalUrl::No,
+            theme: OutputTheme::Ascii,
         }
     }
 
@@ -664,6 +677,7 @@ impl HumanEmitter {
         // Create the source line we will highlight.
         let left = margin.left(line_len);
         let right = margin.right(line_len);
+        // FIXME: The following code looks fishy. See #132860.
         // On long lines, we strip the source line, accounting for unicode.
         let mut taken = 0;
         let code: String = source_string
@@ -680,17 +694,19 @@ impl HumanEmitter {
             })
             .collect();
         buffer.puts(line_offset, code_offset, &code, Style::Quotation);
+        let placeholder = self.margin();
         if margin.was_cut_left() {
             // We have stripped some code/whitespace from the beginning, make it clear.
-            buffer.puts(line_offset, code_offset, "...", Style::LineNumber);
+            buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber);
         }
         if margin.was_cut_right(line_len) {
+            let padding = str_width(placeholder);
             // We have stripped some code after the rightmost span end, make it clear we did so.
-            buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber);
+            buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber);
         }
         buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber);
 
-        draw_col_separator_no_space(buffer, line_offset, width_offset - 2);
+        self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2);
     }
 
     #[instrument(level = "trace", skip(self), ret)]
@@ -702,6 +718,7 @@ impl HumanEmitter {
         width_offset: usize,
         code_offset: usize,
         margin: Margin,
+        close_window: bool,
     ) -> Vec<(usize, Style)> {
         // Draw:
         //
@@ -732,6 +749,7 @@ impl HumanEmitter {
         // Left trim
         let left = margin.left(source_string.len());
 
+        // FIXME: This looks fishy. See #132860.
         // Account for unicode characters of width !=0 that were removed.
         let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum();
 
@@ -767,13 +785,10 @@ impl HumanEmitter {
         for ann in &line.annotations {
             if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
                 if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) {
-                    let style = if ann.is_primary {
-                        Style::UnderlinePrimary
-                    } else {
-                        Style::UnderlineSecondary
-                    };
-                    annotations.push((depth, style));
-                    buffer_ops.push((line_offset, width_offset + depth - 1, '/', style));
+                    let uline = self.underline(ann.is_primary);
+                    let chr = uline.multiline_whole_line;
+                    annotations.push((depth, uline.style));
+                    buffer_ops.push((line_offset, width_offset + depth - 1, chr, uline.style));
                 } else {
                     short_start = false;
                     break;
@@ -970,7 +985,7 @@ impl HumanEmitter {
             // 3 │       X0 Y0 Z0
             //   │ ┏━━━━━┛  │  │     < We are writing these lines
             //   │ ┃┌───────┘  │     < by reverting the "depth" of
-            //   │ ┃│┌─────────┘     < their multilne spans.
+            //   │ ┃│┌─────────┘     < their multiline spans.
             // 4 │ ┃││   X1 Y1 Z1
             // 5 │ ┃││   X2 Y2 Z2
             //   │ ┃│└────╿──│──┘ `Z` label
@@ -997,7 +1012,10 @@ impl HumanEmitter {
         // 4 |   }
         //   |
         for pos in 0..=line_len {
-            draw_col_separator_no_space(buffer, line_offset + pos + 1, width_offset - 2);
+            self.draw_col_separator_no_space(buffer, line_offset + pos + 1, width_offset - 2);
+        }
+        if close_window {
+            self.draw_col_separator_end(buffer, line_offset + line_len + 1, width_offset - 2);
         }
 
         // Write the horizontal lines for multiline annotations
@@ -1013,21 +1031,17 @@ impl HumanEmitter {
         // 4 |   }
         //   |  _
         for &(pos, annotation) in &annotations_position {
-            let style = if annotation.is_primary {
-                Style::UnderlinePrimary
-            } else {
-                Style::UnderlineSecondary
-            };
+            let underline = self.underline(annotation.is_primary);
             let pos = pos + 1;
             match annotation.annotation_type {
                 AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => {
-                    draw_range(
+                    self.draw_range(
                         buffer,
-                        '_',
+                        underline.multiline_horizontal,
                         line_offset + pos,
                         width_offset + depth,
                         (code_offset + annotation.start_col.display).saturating_sub(left),
-                        style,
+                        underline.style,
                     );
                 }
                 _ if self.teach => {
@@ -1035,7 +1049,7 @@ impl HumanEmitter {
                         line_offset,
                         (code_offset + annotation.start_col.display).saturating_sub(left),
                         (code_offset + annotation.end_col.display).saturating_sub(left),
-                        style,
+                        underline.style,
                         annotation.is_primary,
                     );
                 }
@@ -1055,11 +1069,7 @@ impl HumanEmitter {
         // 4 | | }
         //   | |_
         for &(pos, annotation) in &annotations_position {
-            let style = if annotation.is_primary {
-                Style::UnderlinePrimary
-            } else {
-                Style::UnderlineSecondary
-            };
+            let underline = self.underline(annotation.is_primary);
             let pos = pos + 1;
 
             if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
@@ -1067,21 +1077,64 @@ impl HumanEmitter {
                     buffer.putc(
                         p,
                         (code_offset + annotation.start_col.display).saturating_sub(left),
-                        '|',
-                        style,
+                        match annotation.annotation_type {
+                            AnnotationType::MultilineLine(_) => underline.multiline_vertical,
+                            _ => underline.vertical_text_line,
+                        },
+                        underline.style,
+                    );
+                }
+                if let AnnotationType::MultilineStart(_) = annotation.annotation_type {
+                    buffer.putc(
+                        line_offset + pos,
+                        (code_offset + annotation.start_col.display).saturating_sub(left),
+                        underline.bottom_right,
+                        underline.style,
+                    );
+                }
+                if let AnnotationType::MultilineEnd(_) = annotation.annotation_type
+                    && annotation.has_label()
+                {
+                    buffer.putc(
+                        line_offset + pos,
+                        (code_offset + annotation.start_col.display).saturating_sub(left),
+                        underline.multiline_bottom_right_with_text,
+                        underline.style,
                     );
                 }
             }
             match annotation.annotation_type {
                 AnnotationType::MultilineStart(depth) => {
+                    buffer.putc(
+                        line_offset + pos,
+                        width_offset + depth - 1,
+                        underline.top_left,
+                        underline.style,
+                    );
                     for p in line_offset + pos + 1..line_offset + line_len + 2 {
-                        buffer.putc(p, width_offset + depth - 1, '|', style);
+                        buffer.putc(
+                            p,
+                            width_offset + depth - 1,
+                            underline.multiline_vertical,
+                            underline.style,
+                        );
                     }
                 }
                 AnnotationType::MultilineEnd(depth) => {
-                    for p in line_offset..=line_offset + pos {
-                        buffer.putc(p, width_offset + depth - 1, '|', style);
+                    for p in line_offset..line_offset + pos {
+                        buffer.putc(
+                            p,
+                            width_offset + depth - 1,
+                            underline.multiline_vertical,
+                            underline.style,
+                        );
                     }
+                    buffer.putc(
+                        line_offset + pos,
+                        width_offset + depth - 1,
+                        underline.bottom_left,
+                        underline.style,
+                    );
                 }
                 _ => (),
             }
@@ -1102,7 +1155,11 @@ impl HumanEmitter {
             let style =
                 if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary };
             let (pos, col) = if pos == 0 {
-                (pos + 1, (annotation.end_col.display + 1).saturating_sub(left))
+                if annotation.end_col.display == 0 {
+                    (pos + 1, (annotation.end_col.display + 2).saturating_sub(left))
+                } else {
+                    (pos + 1, (annotation.end_col.display + 1).saturating_sub(left))
+                }
             } else {
                 (pos + 2, annotation.start_col.display.saturating_sub(left))
             };
@@ -1135,18 +1192,60 @@ impl HumanEmitter {
         // 3 |
         // 4 |   }
         //   |  _^  test
-        for &(_, annotation) in &annotations_position {
-            let (underline, style) = if annotation.is_primary {
-                ('^', Style::UnderlinePrimary)
-            } else {
-                ('-', Style::UnderlineSecondary)
-            };
+        for &(pos, annotation) in &annotations_position {
+            let uline = self.underline(annotation.is_primary);
             for p in annotation.start_col.display..annotation.end_col.display {
+                // The default span label underline.
                 buffer.putc(
                     line_offset + 1,
                     (code_offset + p).saturating_sub(left),
-                    underline,
-                    style,
+                    uline.underline,
+                    uline.style,
+                );
+            }
+
+            if pos == 0
+                && matches!(
+                    annotation.annotation_type,
+                    AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
+                )
+            {
+                // The beginning of a multiline span with its leftward moving line on the same line.
+                buffer.putc(
+                    line_offset + 1,
+                    (code_offset + annotation.start_col.display).saturating_sub(left),
+                    match annotation.annotation_type {
+                        AnnotationType::MultilineStart(_) => uline.top_right_flat,
+                        AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line,
+                        _ => panic!("unexpected annotation type: {annotation:?}"),
+                    },
+                    uline.style,
+                );
+            } else if pos != 0
+                && matches!(
+                    annotation.annotation_type,
+                    AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
+                )
+            {
+                // The beginning of a multiline span with its leftward moving line on another line,
+                // so we start going down first.
+                buffer.putc(
+                    line_offset + 1,
+                    (code_offset + annotation.start_col.display).saturating_sub(left),
+                    match annotation.annotation_type {
+                        AnnotationType::MultilineStart(_) => uline.multiline_start_down,
+                        AnnotationType::MultilineEnd(_) => uline.multiline_end_up,
+                        _ => panic!("unexpected annotation type: {annotation:?}"),
+                    },
+                    uline.style,
+                );
+            } else if pos != 0 && annotation.has_label() {
+                // The beginning of a span label with an actual label, we'll point down.
+                buffer.putc(
+                    line_offset + 1,
+                    (code_offset + annotation.start_col.display).saturating_sub(left),
+                    uline.label_start,
+                    uline.style,
                 );
             }
         }
@@ -1217,7 +1316,7 @@ impl HumanEmitter {
         padding: usize,
         label: &str,
         override_style: Option<Style>,
-    ) {
+    ) -> usize {
         // The extra 5 ` ` is padding that's always needed to align to the `note: `:
         //
         //   error: message
@@ -1281,6 +1380,7 @@ impl HumanEmitter {
                 buffer.append(line_number, text, style_or_override(*style, override_style));
             }
         }
+        line_number
     }
 
     #[instrument(level = "trace", skip(self, args), ret)]
@@ -1294,6 +1394,7 @@ impl HumanEmitter {
         max_line_num_len: usize,
         is_secondary: bool,
         emitted_at: Option<&DiagLocation>,
+        is_cont: bool,
     ) -> io::Result<()> {
         let mut buffer = StyledBuffer::new();
 
@@ -1303,12 +1404,29 @@ impl HumanEmitter {
             for _ in 0..max_line_num_len {
                 buffer.prepend(0, " ", Style::NoStyle);
             }
-            draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
+            self.draw_note_separator(&mut buffer, 0, max_line_num_len + 1, is_cont);
             if *level != Level::FailureNote {
                 buffer.append(0, level.to_str(), Style::MainHeaderMsg);
                 buffer.append(0, ": ", Style::NoStyle);
             }
-            self.msgs_to_buffer(&mut buffer, msgs, args, max_line_num_len, "note", None);
+            let printed_lines =
+                self.msgs_to_buffer(&mut buffer, msgs, args, max_line_num_len, "note", None);
+            if is_cont && matches!(self.theme, OutputTheme::Unicode) {
+                // There's another note after this one, associated to the subwindow above.
+                // We write additional vertical lines to join them:
+                //   ╭▸ test.rs:3:3
+                //   │
+                // 3 │   code
+                //   │   ━━━━
+                //   │
+                //   ├ note: foo
+                //   │       bar
+                //   ╰ note: foo
+                //           bar
+                for i in 1..=printed_lines {
+                    self.draw_col_separator_no_space(&mut buffer, i, max_line_num_len + 1);
+                }
+            }
         } else {
             let mut label_width = 0;
             // The failure note level itself does not provide any useful diagnostic information
@@ -1439,9 +1557,13 @@ impl HumanEmitter {
                                 Style::LineAndColumn,
                             );
                             if annotation_id == 0 {
-                                buffer.prepend(line_idx, "--> ", Style::LineNumber);
+                                buffer.prepend(line_idx, self.file_start(), Style::LineNumber);
                             } else {
-                                buffer.prepend(line_idx, "::: ", Style::LineNumber);
+                                buffer.prepend(
+                                    line_idx,
+                                    self.secondary_file_start(),
+                                    Style::LineNumber,
+                                );
                             }
                             for _ in 0..max_line_num_len {
                                 buffer.prepend(line_idx, " ", Style::NoStyle);
@@ -1454,12 +1576,14 @@ impl HumanEmitter {
                             } else {
                                 Style::LabelSecondary
                             };
-                            buffer.prepend(line_idx, " |", Style::LineNumber);
+                            let pipe = self.col_separator();
+                            buffer.prepend(line_idx, &format!(" {pipe}"), Style::LineNumber);
                             for _ in 0..max_line_num_len {
                                 buffer.prepend(line_idx, " ", Style::NoStyle);
                             }
                             line_idx += 1;
-                            buffer.append(line_idx, " = note: ", style);
+                            let chr = self.note_separator();
+                            buffer.append(line_idx, &format!(" {chr} note: "), style);
                             for _ in 0..max_line_num_len {
                                 buffer.prepend(line_idx, " ", Style::NoStyle);
                             }
@@ -1480,7 +1604,7 @@ impl HumanEmitter {
                     // remember where we are in the output buffer for easy reference
                     let buffer_msg_line_offset = buffer.num_lines();
 
-                    buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
+                    buffer.prepend(buffer_msg_line_offset, self.file_start(), Style::LineNumber);
                     buffer.append(
                         buffer_msg_line_offset,
                         &format!(
@@ -1510,15 +1634,28 @@ impl HumanEmitter {
                 // remember where we are in the output buffer for easy reference
                 let buffer_msg_line_offset = buffer.num_lines();
 
-                // Add spacing line
-                draw_col_separator_no_space(
+                // Add spacing line, as shown:
+                //   --> $DIR/file:54:15
+                //    |
+                // LL |         code
+                //    |         ^^^^
+                //    | (<- It prints *this* line)
+                //   ::: $DIR/other_file.rs:15:5
+                //    |
+                // LL |     code
+                //    |     ----
+                self.draw_col_separator_no_space(
                     &mut buffer,
                     buffer_msg_line_offset,
                     max_line_num_len + 1,
                 );
 
                 // Then, the secondary file indicator
-                buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
+                buffer.prepend(
+                    buffer_msg_line_offset + 1,
+                    self.secondary_file_start(),
+                    Style::LineNumber,
+                );
                 let loc = if let Some(first_line) = annotated_file.lines.first() {
                     let col = if let Some(first_annotation) = first_line.annotations.first() {
                         format!(":{}", first_annotation.start_col.file + 1)
@@ -1543,7 +1680,7 @@ impl HumanEmitter {
             if !self.short_message {
                 // Put in the spacer between the location and annotated source
                 let buffer_msg_line_offset = buffer.num_lines();
-                draw_col_separator_no_space(
+                self.draw_col_separator_no_space(
                     &mut buffer,
                     buffer_msg_line_offset,
                     max_line_num_len + 1,
@@ -1651,6 +1788,7 @@ impl HumanEmitter {
                         width_offset,
                         code_offset,
                         margin,
+                        !is_cont && line_idx + 1 == annotated_file.lines.len(),
                     );
 
                     let mut to_add = FxHashMap::default();
@@ -1666,7 +1804,13 @@ impl HumanEmitter {
                     // the code in this line.
                     for (depth, style) in &multilines {
                         for line in previous_buffer_line..buffer.num_lines() {
-                            draw_multiline_line(&mut buffer, line, width_offset, *depth, *style);
+                            self.draw_multiline_line(
+                                &mut buffer,
+                                line,
+                                width_offset,
+                                *depth,
+                                *style,
+                            );
                         }
                     }
                     // check to see if we need to print out or elide lines that come between
@@ -1676,11 +1820,15 @@ impl HumanEmitter {
                             - annotated_file.lines[line_idx].line_index;
                         if line_idx_delta > 2 {
                             let last_buffer_line_num = buffer.num_lines();
-                            buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber);
+                            self.draw_line_separator(
+                                &mut buffer,
+                                last_buffer_line_num,
+                                width_offset,
+                            );
 
                             // Set the multiline annotation vertical lines on `...` bridging line.
                             for (depth, style) in &multilines {
-                                draw_multiline_line(
+                                self.draw_multiline_line(
                                     &mut buffer,
                                     last_buffer_line_num,
                                     width_offset,
@@ -1695,7 +1843,7 @@ impl HumanEmitter {
                                         // In the case where we have elided the entire start of the
                                         // multispan because those lines were empty, we still need
                                         // to draw the `|`s across the `...`.
-                                        draw_multiline_line(
+                                        self.draw_multiline_line(
                                             &mut buffer,
                                             last_buffer_line_num,
                                             width_offset,
@@ -1728,7 +1876,7 @@ impl HumanEmitter {
                             );
 
                             for (depth, style) in &multilines {
-                                draw_multiline_line(
+                                self.draw_multiline_line(
                                     &mut buffer,
                                     last_buffer_line_num,
                                     width_offset,
@@ -1740,7 +1888,7 @@ impl HumanEmitter {
                                 for ann in &line.annotations {
                                     if let AnnotationType::MultilineStart(pos) = ann.annotation_type
                                     {
-                                        draw_multiline_line(
+                                        self.draw_multiline_line(
                                             &mut buffer,
                                             last_buffer_line_num,
                                             width_offset,
@@ -1824,13 +1972,24 @@ impl HumanEmitter {
         );
 
         let mut row_num = 2;
-        draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
-        for (complete, parts, highlights, _) in suggestions.iter().take(MAX_SUGGESTIONS) {
+        for (i, (complete, parts, highlights, _)) in
+            suggestions.iter().enumerate().take(MAX_SUGGESTIONS)
+        {
             debug!(?complete, ?parts, ?highlights);
 
             let has_deletion = parts.iter().any(|p| p.is_deletion(sm));
             let is_multiline = complete.lines().count() > 1;
 
+            if i == 0 {
+                self.draw_col_separator_start(&mut buffer, row_num - 1, max_line_num_len + 1);
+            } else {
+                buffer.puts(
+                    row_num - 1,
+                    max_line_num_len + 1,
+                    self.multi_suggestion_separator(),
+                    Style::LineNumber,
+                );
+            }
             if let Some(span) = span.primary_span() {
                 // Compare the primary span of the diagnostic with the span of the suggestion
                 // being emitted. If they belong to the same file, we don't *need* to show the
@@ -1838,7 +1997,9 @@ impl HumanEmitter {
                 // telling users to make a change but not clarifying *where*.
                 let loc = sm.lookup_char_pos(parts[0].span.lo());
                 if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() {
-                    let arrow = "--> ";
+                    // --> file.rs:line:col
+                    //  |
+                    let arrow = self.file_start();
                     buffer.puts(row_num - 1, 0, arrow, Style::LineNumber);
                     let filename = sm.filename_for_diagnostics(&loc.file.name);
                     let offset = sm.doctest_offset_line(&loc.file.name, loc.line);
@@ -1852,6 +2013,7 @@ impl HumanEmitter {
                     for _ in 0..max_line_num_len {
                         buffer.prepend(row_num - 1, " ", Style::NoStyle);
                     }
+                    self.draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
                     row_num += 1;
                 }
             }
@@ -1882,7 +2044,6 @@ impl HumanEmitter {
             assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
 
             let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
-            draw_col_separator_no_space(&mut buffer, row_num - 1, max_line_num_len + 1);
             let mut lines = complete.lines();
             if lines.clone().next().is_none() {
                 // Account for a suggestion to completely remove a line(s) with whitespace (#94192).
@@ -1972,7 +2133,14 @@ impl HumanEmitter {
                             )
                         }
 
-                        buffer.puts(row_num, 0, "...", Style::LineNumber);
+                        let placeholder = self.margin();
+                        let padding = str_width(placeholder);
+                        buffer.puts(
+                            row_num,
+                            max_line_num_len.saturating_sub(padding),
+                            placeholder,
+                            Style::LineNumber,
+                        );
                         row_num += 1;
 
                         if let Some((p, l)) = last_line {
@@ -2040,7 +2208,6 @@ impl HumanEmitter {
             if let DisplaySuggestion::Diff | DisplaySuggestion::Underline | DisplaySuggestion::Add =
                 show_code_change
             {
-                draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
                 for part in parts {
                     let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
                     let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display;
@@ -2057,11 +2224,11 @@ impl HumanEmitter {
                     };
                     // ...or trailing spaces. Account for substitutions containing unicode
                     // characters.
-                    let sub_len: usize =
-                        if is_whitespace_addition { &part.snippet } else { part.snippet.trim() }
-                            .chars()
-                            .map(|ch| char_width(ch))
-                            .sum();
+                    let sub_len: usize = str_width(if is_whitespace_addition {
+                        &part.snippet
+                    } else {
+                        part.snippet.trim()
+                    });
 
                     let offset: isize = offsets
                         .iter()
@@ -2082,7 +2249,7 @@ impl HumanEmitter {
                             buffer.putc(
                                 row_num,
                                 (padding as isize + p) as usize,
-                                if part.is_addition(sm) { '+' } else { '~' },
+                                if part.is_addition(sm) { '+' } else { self.diff() },
                                 Style::Addition,
                             );
                         }
@@ -2099,8 +2266,7 @@ impl HumanEmitter {
                     }
 
                     // length of the code after substitution
-                    let full_sub_len =
-                        part.snippet.chars().map(|ch| char_width(ch)).sum::<usize>() as isize;
+                    let full_sub_len = str_width(&part.snippet) as isize;
 
                     // length of the code to be substituted
                     let snippet_len = span_end_pos as isize - span_start_pos as isize;
@@ -2114,10 +2280,23 @@ impl HumanEmitter {
 
             // if we elided some lines, add an ellipsis
             if lines.next().is_some() {
-                buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
-            } else if let DisplaySuggestion::None = show_code_change {
-                draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
-                row_num += 1;
+                let placeholder = self.margin();
+                let padding = str_width(placeholder);
+                buffer.puts(
+                    row_num,
+                    max_line_num_len.saturating_sub(padding),
+                    placeholder,
+                    Style::LineNumber,
+                );
+            } else {
+                let row = match show_code_change {
+                    DisplaySuggestion::Diff
+                    | DisplaySuggestion::Add
+                    | DisplaySuggestion::Underline => row_num - 1,
+                    DisplaySuggestion::None => row_num,
+                };
+                self.draw_col_separator_end(&mut buffer, row, max_line_num_len + 1);
+                row_num = row + 1;
             }
         }
         if suggestions.len() > MAX_SUGGESTIONS {
@@ -2125,6 +2304,7 @@ impl HumanEmitter {
             let msg = format!("and {} other candidate{}", others, pluralize!(others));
             buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle);
         }
+
         emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
         Ok(())
     }
@@ -2157,6 +2337,8 @@ impl HumanEmitter {
             max_line_num_len,
             false,
             emitted_at,
+            !children.is_empty()
+                || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden),
         ) {
             Ok(()) => {
                 if !children.is_empty()
@@ -2164,7 +2346,15 @@ impl HumanEmitter {
                 {
                     let mut buffer = StyledBuffer::new();
                     if !self.short_message {
-                        draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
+                        if let Some(child) = children.iter().next()
+                            && child.span.primary_spans().is_empty()
+                        {
+                            // We'll continue the vertical bar to point into the next note.
+                            self.draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1);
+                        } else {
+                            // We'll close the vertical bar to visually end the code window.
+                            self.draw_col_separator_end(&mut buffer, 0, max_line_num_len + 1);
+                        }
                     }
                     if let Err(e) = emit_to_destination(
                         &buffer.render(),
@@ -2176,9 +2366,14 @@ impl HumanEmitter {
                     }
                 }
                 if !self.short_message {
-                    for child in children {
+                    for (i, child) in children.iter().enumerate() {
                         assert!(child.level.can_be_subdiag());
                         let span = &child.span;
+                        // FIXME: audit that this behaves correctly with suggestions.
+                        let should_close = match children.get(i + 1) {
+                            Some(c) => !c.span.primary_spans().is_empty(),
+                            None => i + 1 == children.len(),
+                        };
                         if let Err(err) = self.emit_messages_default_inner(
                             span,
                             &child.messages,
@@ -2188,11 +2383,12 @@ impl HumanEmitter {
                             max_line_num_len,
                             true,
                             None,
+                            !should_close,
                         ) {
                             panic!("failed to emit error: {err}");
                         }
                     }
-                    for sugg in suggestions {
+                    for (i, sugg) in suggestions.iter().enumerate() {
                         match sugg.style {
                             SuggestionStyle::CompletelyHidden => {
                                 // do not display this suggestion, it is meant only for tools
@@ -2207,6 +2403,9 @@ impl HumanEmitter {
                                     max_line_num_len,
                                     true,
                                     None,
+                                    // FIXME: this needs to account for the suggestion type,
+                                    //        some don't take any space.
+                                    i + 1 != suggestions.len(),
                                 ) {
                                     panic!("failed to emit error: {e}");
                                 }
@@ -2323,10 +2522,17 @@ impl HumanEmitter {
                     buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
                 }
                 [] => {
-                    draw_col_separator_no_space(buffer, *row_num, max_line_num_len + 1);
+                    // FIXME: needed? Doesn't get excercised in any test.
+                    self.draw_col_separator_no_space(buffer, *row_num, max_line_num_len + 1);
                 }
                 _ => {
-                    buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition);
+                    let diff = self.diff();
+                    buffer.puts(
+                        *row_num,
+                        max_line_num_len + 1,
+                        &format!("{diff} "),
+                        Style::Addition,
+                    );
                 }
             }
             //   LL | line_to_add
@@ -2346,7 +2552,7 @@ impl HumanEmitter {
             buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
         } else {
             buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
-            draw_col_separator(buffer, *row_num, max_line_num_len + 1);
+            self.draw_col_separator(buffer, *row_num, max_line_num_len + 1);
             buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
         }
 
@@ -2374,6 +2580,306 @@ impl HumanEmitter {
         }
         *row_num += 1;
     }
+
+    fn underline(&self, is_primary: bool) -> UnderlineParts {
+        //               X0 Y0
+        // label_start > ┯━━━━ < underline
+        //               │ < vertical_text_line
+        //               text
+
+        //    multiline_start_down ⤷ X0 Y0
+        //            top_left > ┌───╿──┘ < top_right_flat
+        //           top_left > ┏│━━━┙ < top_right
+        // multiline_vertical > ┃│
+        //                      ┃│   X1 Y1
+        //                      ┃│   X2 Y2
+        //                      ┃└────╿──┘ < multiline_end_same_line
+        //        bottom_left > ┗━━━━━┥ < bottom_right_with_text
+        //   multiline_horizontal ^   `X` is a good letter
+
+        // multiline_whole_line > ┏ X0 Y0
+        //                        ┃   X1 Y1
+        //                        ┗━━━━┛ < multiline_end_same_line
+
+        // multiline_whole_line > ┏ X0 Y0
+        //                        ┃ X1 Y1
+        //                        ┃  ╿ < multiline_end_up
+        //                        ┗━━┛ < bottom_right
+
+        match (self.theme, is_primary) {
+            (OutputTheme::Ascii, true) => UnderlineParts {
+                style: Style::UnderlinePrimary,
+                underline: '^',
+                label_start: '^',
+                vertical_text_line: '|',
+                multiline_vertical: '|',
+                multiline_horizontal: '_',
+                multiline_whole_line: '/',
+                multiline_start_down: '^',
+                bottom_right: '|',
+                top_left: ' ',
+                top_right_flat: '^',
+                bottom_left: '|',
+                multiline_end_up: '^',
+                multiline_end_same_line: '^',
+                multiline_bottom_right_with_text: '|',
+            },
+            (OutputTheme::Ascii, false) => UnderlineParts {
+                style: Style::UnderlineSecondary,
+                underline: '-',
+                label_start: '-',
+                vertical_text_line: '|',
+                multiline_vertical: '|',
+                multiline_horizontal: '_',
+                multiline_whole_line: '/',
+                multiline_start_down: '-',
+                bottom_right: '|',
+                top_left: ' ',
+                top_right_flat: '-',
+                bottom_left: '|',
+                multiline_end_up: '-',
+                multiline_end_same_line: '-',
+                multiline_bottom_right_with_text: '|',
+            },
+            (OutputTheme::Unicode, true) => UnderlineParts {
+                style: Style::UnderlinePrimary,
+                underline: '━',
+                label_start: '┯',
+                vertical_text_line: '│',
+                multiline_vertical: '┃',
+                multiline_horizontal: '━',
+                multiline_whole_line: '┏',
+                multiline_start_down: '╿',
+                bottom_right: '┙',
+                top_left: '┏',
+                top_right_flat: '┛',
+                bottom_left: '┗',
+                multiline_end_up: '╿',
+                multiline_end_same_line: '┛',
+                multiline_bottom_right_with_text: '┥',
+            },
+            (OutputTheme::Unicode, false) => UnderlineParts {
+                style: Style::UnderlineSecondary,
+                underline: '─',
+                label_start: '┬',
+                vertical_text_line: '│',
+                multiline_vertical: '│',
+                multiline_horizontal: '─',
+                multiline_whole_line: '┌',
+                multiline_start_down: '│',
+                bottom_right: '┘',
+                top_left: '┌',
+                top_right_flat: '┘',
+                bottom_left: '└',
+                multiline_end_up: '│',
+                multiline_end_same_line: '┘',
+                multiline_bottom_right_with_text: '┤',
+            },
+        }
+    }
+
+    fn col_separator(&self) -> char {
+        match self.theme {
+            OutputTheme::Ascii => '|',
+            OutputTheme::Unicode => '│',
+        }
+    }
+
+    fn note_separator(&self) -> char {
+        match self.theme {
+            OutputTheme::Ascii => '=',
+            OutputTheme::Unicode => '╰',
+        }
+    }
+
+    fn multi_suggestion_separator(&self) -> &'static str {
+        match self.theme {
+            OutputTheme::Ascii => "|",
+            OutputTheme::Unicode => "├╴",
+        }
+    }
+
+    fn draw_col_separator(&self, buffer: &mut StyledBuffer, line: usize, col: usize) {
+        let chr = self.col_separator();
+        buffer.puts(line, col, &format!("{chr} "), Style::LineNumber);
+    }
+
+    fn draw_col_separator_no_space(&self, buffer: &mut StyledBuffer, line: usize, col: usize) {
+        let chr = self.col_separator();
+        self.draw_col_separator_no_space_with_style(buffer, chr, line, col, Style::LineNumber);
+    }
+
+    fn draw_col_separator_start(&self, buffer: &mut StyledBuffer, line: usize, col: usize) {
+        match self.theme {
+            OutputTheme::Ascii => {
+                self.draw_col_separator_no_space_with_style(
+                    buffer,
+                    '|',
+                    line,
+                    col,
+                    Style::LineNumber,
+                );
+            }
+            OutputTheme::Unicode => {
+                self.draw_col_separator_no_space_with_style(
+                    buffer,
+                    '╭',
+                    line,
+                    col,
+                    Style::LineNumber,
+                );
+                self.draw_col_separator_no_space_with_style(
+                    buffer,
+                    '╴',
+                    line,
+                    col + 1,
+                    Style::LineNumber,
+                );
+            }
+        }
+    }
+
+    fn draw_col_separator_end(&self, buffer: &mut StyledBuffer, line: usize, col: usize) {
+        match self.theme {
+            OutputTheme::Ascii => {
+                self.draw_col_separator_no_space_with_style(
+                    buffer,
+                    '|',
+                    line,
+                    col,
+                    Style::LineNumber,
+                );
+            }
+            OutputTheme::Unicode => {
+                self.draw_col_separator_no_space_with_style(
+                    buffer,
+                    '╰',
+                    line,
+                    col,
+                    Style::LineNumber,
+                );
+                self.draw_col_separator_no_space_with_style(
+                    buffer,
+                    '╴',
+                    line,
+                    col + 1,
+                    Style::LineNumber,
+                );
+            }
+        }
+    }
+
+    fn draw_col_separator_no_space_with_style(
+        &self,
+        buffer: &mut StyledBuffer,
+        chr: char,
+        line: usize,
+        col: usize,
+        style: Style,
+    ) {
+        buffer.putc(line, col, chr, style);
+    }
+
+    fn draw_range(
+        &self,
+        buffer: &mut StyledBuffer,
+        symbol: char,
+        line: usize,
+        col_from: usize,
+        col_to: usize,
+        style: Style,
+    ) {
+        for col in col_from..col_to {
+            buffer.putc(line, col, symbol, style);
+        }
+    }
+
+    fn draw_note_separator(
+        &self,
+        buffer: &mut StyledBuffer,
+        line: usize,
+        col: usize,
+        is_cont: bool,
+    ) {
+        let chr = match self.theme {
+            OutputTheme::Ascii => "= ",
+            OutputTheme::Unicode if is_cont => "├ ",
+            OutputTheme::Unicode => "╰ ",
+        };
+        buffer.puts(line, col, chr, Style::LineNumber);
+    }
+
+    fn draw_multiline_line(
+        &self,
+        buffer: &mut StyledBuffer,
+        line: usize,
+        offset: usize,
+        depth: usize,
+        style: Style,
+    ) {
+        let chr = match (style, self.theme) {
+            (Style::UnderlinePrimary | Style::LabelPrimary, OutputTheme::Ascii) => '|',
+            (_, OutputTheme::Ascii) => '|',
+            (Style::UnderlinePrimary | Style::LabelPrimary, OutputTheme::Unicode) => '┃',
+            (_, OutputTheme::Unicode) => '│',
+        };
+        buffer.putc(line, offset + depth - 1, chr, style);
+    }
+
+    fn file_start(&self) -> &'static str {
+        match self.theme {
+            OutputTheme::Ascii => "--> ",
+            OutputTheme::Unicode => " ╭▸ ",
+        }
+    }
+
+    fn secondary_file_start(&self) -> &'static str {
+        match self.theme {
+            OutputTheme::Ascii => "::: ",
+            OutputTheme::Unicode => " ⸬ ",
+        }
+    }
+
+    fn diff(&self) -> char {
+        match self.theme {
+            OutputTheme::Ascii => '~',
+            OutputTheme::Unicode => '±',
+        }
+    }
+
+    fn draw_line_separator(&self, buffer: &mut StyledBuffer, line: usize, col: usize) {
+        let (column, dots) = match self.theme {
+            OutputTheme::Ascii => (0, "..."),
+            OutputTheme::Unicode => (col - 2, "‡"),
+        };
+        buffer.puts(line, column, dots, Style::LineNumber);
+    }
+
+    fn margin(&self) -> &'static str {
+        match self.theme {
+            OutputTheme::Ascii => "...",
+            OutputTheme::Unicode => "…",
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+struct UnderlineParts {
+    style: Style,
+    underline: char,
+    label_start: char,
+    vertical_text_line: char,
+    multiline_vertical: char,
+    multiline_horizontal: char,
+    multiline_whole_line: char,
+    multiline_start_down: char,
+    bottom_right: char,
+    top_left: char,
+    top_right_flat: char,
+    bottom_left: char,
+    multiline_end_up: char,
+    multiline_end_same_line: char,
+    multiline_bottom_right_with_text: char,
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -2666,50 +3172,6 @@ fn normalize_whitespace(s: &str) -> String {
     })
 }
 
-fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
-    buffer.puts(line, col, "| ", Style::LineNumber);
-}
-
-fn draw_col_separator_no_space(buffer: &mut StyledBuffer, line: usize, col: usize) {
-    draw_col_separator_no_space_with_style(buffer, line, col, Style::LineNumber);
-}
-
-fn draw_col_separator_no_space_with_style(
-    buffer: &mut StyledBuffer,
-    line: usize,
-    col: usize,
-    style: Style,
-) {
-    buffer.putc(line, col, '|', style);
-}
-
-fn draw_range(
-    buffer: &mut StyledBuffer,
-    symbol: char,
-    line: usize,
-    col_from: usize,
-    col_to: usize,
-    style: Style,
-) {
-    for col in col_from..col_to {
-        buffer.putc(line, col, symbol, style);
-    }
-}
-
-fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
-    buffer.puts(line, col, "= ", Style::LineNumber);
-}
-
-fn draw_multiline_line(
-    buffer: &mut StyledBuffer,
-    line: usize,
-    offset: usize,
-    depth: usize,
-    style: Style,
-) {
-    buffer.putc(line, offset + depth - 1, '|', style);
-}
-
 fn num_overlap(
     a_start: usize,
     a_end: usize,
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 91e2b9996cd..e3b6dcea892 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -27,7 +27,7 @@ use termcolor::{ColorSpec, WriteColor};
 
 use crate::diagnostic::IsLint;
 use crate::emitter::{
-    ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType,
+    ColorConfig, Destination, Emitter, HumanEmitter, HumanReadableErrorType, OutputTheme,
     should_show_source_code,
 };
 use crate::registry::Registry;
@@ -377,6 +377,11 @@ impl Diagnostic {
             .terminal_url(je.terminal_url)
             .ui_testing(je.ui_testing)
             .ignored_directories_in_source_blocks(je.ignored_directories_in_source_blocks.clone())
+            .theme(if let HumanReadableErrorType::Unicode = je.json_rendered {
+                OutputTheme::Unicode
+            } else {
+                OutputTheme::Ascii
+            })
             .emit_diagnostic(diag);
         let buf = Arc::try_unwrap(buf.0).unwrap().into_inner().unwrap();
         let buf = String::from_utf8(buf).unwrap();
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 94365a89adc..98200c367f9 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -623,12 +623,25 @@ impl Drop for DiagCtxtInner {
             self.flush_delayed()
         }
 
+        // Sanity check: did we use some of the expensive `trimmed_def_paths` functions
+        // unexpectedly, that is, without producing diagnostics? If so, for debugging purposes, we
+        // suggest where this happened and how to avoid it.
         if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
             if let Some(backtrace) = &self.must_produce_diag {
+                let suggestion = match backtrace.status() {
+                    BacktraceStatus::Disabled => String::from(
+                        "Backtraces are currently disabled: set `RUST_BACKTRACE=1` and re-run \
+                        to see where it happened.",
+                    ),
+                    BacktraceStatus::Captured => format!(
+                        "This happened in the following `must_produce_diag` call's backtrace:\n\
+                        {backtrace}",
+                    ),
+                    _ => String::from("(impossible to capture backtrace where this happened)"),
+                };
                 panic!(
-                    "must_produce_diag: `trimmed_def_paths` called but no diagnostics emitted; \
-                     `with_no_trimmed_paths` for debugging. \
-                     called at: {backtrace}"
+                    "`trimmed_def_paths` called, diagnostics were expected but none were emitted. \
+                    Use `with_no_trimmed_paths` for debugging. {suggestion}"
                 );
             }
         }
diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs
index 70179237e5d..376fd24d57b 100644
--- a/compiler/rustc_errors/src/tests.rs
+++ b/compiler/rustc_errors/src/tests.rs
@@ -26,16 +26,11 @@ fn make_dummy(ftl: &'static str) -> Dummy {
 
     let langid_en = langid!("en-US");
 
-    #[cfg(parallel_compiler)]
     let mut bundle: FluentBundle =
         IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new_concurrent(vec![
             langid_en,
         ]));
 
-    #[cfg(not(parallel_compiler))]
-    let mut bundle: FluentBundle =
-        IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new(vec![langid_en]));
-
     bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle.");
 
     Dummy { bundle }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 7e4bc508e5c..bed500c3032 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -866,9 +866,7 @@ impl SyntaxExtension {
             })
             .unwrap_or_else(|| (None, helper_attrs));
         let stability = attr::find_stability(sess, attrs, span);
-        // We set `is_const_fn` false to avoid getting any implicit const stability.
-        let const_stability =
-            attr::find_const_stability(sess, attrs, span, /* is_const_fn */ false);
+        let const_stability = attr::find_const_stability(sess, attrs, span);
         let body_stability = attr::find_body_stability(sess, attrs);
         if let Some((_, sp)) = const_stability {
             sess.dcx().emit_err(errors::MacroConstStability {
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index c952d5f6d77..15cb331d07a 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -241,6 +241,8 @@ language_item_table! {
     DerefMut,                sym::deref_mut,           deref_mut_trait,            Target::Trait,          GenericRequirement::Exact(0);
     DerefPure,               sym::deref_pure,          deref_pure_trait,           Target::Trait,          GenericRequirement::Exact(0);
     DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
+    Receiver,                sym::receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
+    ReceiverTarget,          sym::receiver_target,     receiver_target,            Target::AssocTy,        GenericRequirement::None;
     LegacyReceiver,          sym::legacy_receiver,     legacy_receiver_trait,      Target::Trait,          GenericRequirement::None;
 
     Fn,                      kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 3a6ea545741..1802f00bc1f 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1427,16 +1427,6 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     let predicates = tcx.predicates_of(def_id.to_def_id());
     let generics = tcx.generics_of(def_id);
 
-    let is_our_default = |def: &ty::GenericParamDef| match def.kind {
-        GenericParamDefKind::Type { has_default, .. }
-        | GenericParamDefKind::Const { has_default, .. } => {
-            has_default && def.index >= generics.parent_count as u32
-        }
-        GenericParamDefKind::Lifetime => {
-            span_bug!(tcx.def_span(def.def_id), "lifetime params can have no default")
-        }
-    };
-
     // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
     // For example, this forbids the declaration:
     //
@@ -1444,40 +1434,21 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     //
     // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
     for param in &generics.own_params {
-        match param.kind {
-            GenericParamDefKind::Type { .. } => {
-                if is_our_default(param) {
-                    let ty = tcx.type_of(param.def_id).instantiate_identity();
-                    // Ignore dependent defaults -- that is, where the default of one type
-                    // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
-                    // be sure if it will error or not as user might always specify the other.
-                    if !ty.has_param() {
-                        wfcx.register_wf_obligation(
-                            tcx.def_span(param.def_id),
-                            Some(WellFormedLoc::Ty(param.def_id.expect_local())),
-                            ty.into(),
-                        );
-                    }
-                }
-            }
-            GenericParamDefKind::Const { .. } => {
-                if is_our_default(param) {
-                    // FIXME(const_generics_defaults): This
-                    // is incorrect when dealing with unused args, for example
-                    // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
-                    // we should eagerly error.
-                    let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
-                    if !default_ct.has_param() {
-                        wfcx.register_wf_obligation(
-                            tcx.def_span(param.def_id),
-                            None,
-                            default_ct.into(),
-                        );
-                    }
-                }
+        if let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity) {
+            // Ignore dependent defaults -- that is, where the default of one type
+            // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
+            // be sure if it will error or not as user might always specify the other.
+            // FIXME(generic_const_exprs): This is incorrect when dealing with unused const params.
+            // E.g: `struct Foo<const N: usize, const M: usize = { 1 - 2 }>;`. Here, we should
+            // eagerly error but we don't as we have `ConstKind::Unevaluated(.., [N, M])`.
+            if !default.has_param() {
+                wfcx.register_wf_obligation(
+                    tcx.def_span(param.def_id),
+                    matches!(param.kind, GenericParamDefKind::Type { .. })
+                        .then(|| WellFormedLoc::Ty(param.def_id.expect_local())),
+                    default,
+                );
             }
-            // Doesn't have defaults.
-            GenericParamDefKind::Lifetime => {}
         }
     }
 
@@ -1490,39 +1461,16 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     //
     // First we build the defaulted generic parameters.
     let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| {
-        match param.kind {
-            GenericParamDefKind::Lifetime => {
-                // All regions are identity.
-                tcx.mk_param_from_def(param)
-            }
-
-            GenericParamDefKind::Type { .. } => {
-                // If the param has a default, ...
-                if is_our_default(param) {
-                    let default_ty = tcx.type_of(param.def_id).instantiate_identity();
-                    // ... and it's not a dependent default, ...
-                    if !default_ty.has_param() {
-                        // ... then instantiate it with the default.
-                        return default_ty.into();
-                    }
-                }
-
-                tcx.mk_param_from_def(param)
-            }
-            GenericParamDefKind::Const { .. } => {
-                // If the param has a default, ...
-                if is_our_default(param) {
-                    let default_ct = tcx.const_param_default(param.def_id).instantiate_identity();
-                    // ... and it's not a dependent default, ...
-                    if !default_ct.has_param() {
-                        // ... then instantiate it with the default.
-                        return default_ct.into();
-                    }
-                }
-
-                tcx.mk_param_from_def(param)
-            }
+        if param.index >= generics.parent_count as u32
+            // If the param has a default, ...
+            && let Some(default) = param.default_value(tcx).map(ty::EarlyBinder::instantiate_identity)
+            // ... and it's not a dependent default, ...
+            && !default.has_param()
+        {
+            // ... then instantiate it with the default.
+            return default;
         }
+        tcx.mk_param_from_def(param)
     });
 
     // Now we build the instantiated predicates.
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 1774772b50b..bfdf764d299 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -15,7 +15,7 @@ use crate::{Diverges, Expectation, FnCtxt, Needs};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     #[instrument(skip(self), level = "debug", ret)]
-    pub(crate) fn check_match(
+    pub(crate) fn check_expr_match(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         scrut: &'tcx hir::Expr<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 20502de38a2..e6e0f62b54d 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -62,7 +62,7 @@ enum CallStep<'tcx> {
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub(crate) fn check_call(
+    pub(crate) fn check_expr_call(
         &self,
         call_expr: &'tcx hir::Expr<'tcx>,
         callee_expr: &'tcx hir::Expr<'tcx>,
@@ -74,8 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .check_expr_with_expectation_and_args(
                     callee_expr,
                     Expectation::NoExpectation,
-                    arg_exprs,
-                    Some(call_expr),
+                    Some((call_expr, arg_exprs)),
                 ),
             _ => self.check_expr(callee_expr),
         };
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 2026fd9a614..51d78646373 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -137,7 +137,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     }
 
     fcx.is_whole_body.set(true);
-    fcx.check_return_expr(body.value, false);
+    fcx.check_return_or_body_tail(body.value, false);
 
     // Finalize the return check by taking the LUB of the return types
     // we saw and assigning it to the expected return type. This isn't
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index b05731c6d52..354993513da 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -55,6 +55,9 @@ use crate::{
 };
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /// Check an expr with an expectation type, and also demand that the expr's
+    /// evaluated type is a subtype of the expectation at the end. This is a
+    /// *hard* requirement.
     pub(crate) fn check_expr_has_type_or_error(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -97,6 +100,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
+    /// Check an expr with an expectation type, and also demand that the expr's
+    /// evaluated type is a coercible to the expectation at the end. This is a
+    /// *hard* requirement.
     pub(super) fn check_expr_coercible_to_type(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -128,6 +134,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// Check an expr with an expectation type. Don't actually enforce that expectation
+    /// is related to the expr's evaluated type via subtyping or coercion. This is
+    /// usually called because we want to do that subtype/coerce call manually for better
+    /// diagnostics.
     pub(super) fn check_expr_with_hint(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -136,6 +146,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.check_expr_with_expectation(expr, ExpectHasType(expected))
     }
 
+    /// Check an expr with an expectation type, and also [`Needs`] which will
+    /// prompt typeck to convert any implicit immutable derefs to mutable derefs.
     fn check_expr_with_expectation_and_needs(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -153,10 +165,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty
     }
 
+    /// Check an expr with no expectations.
     pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, NoExpectation)
     }
 
+    /// Check an expr with no expectations, but with [`Needs`] which will
+    /// prompt typeck to convert any implicit immutable derefs to mutable derefs.
     pub(super) fn check_expr_with_needs(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
@@ -165,33 +180,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.check_expr_with_expectation_and_needs(expr, NoExpectation, needs)
     }
 
-    /// Invariant:
-    /// If an expression has any sub-expressions that result in a type error,
-    /// inspecting that expression's type with `ty.references_error()` will return
-    /// true. Likewise, if an expression is known to diverge, inspecting its
-    /// type with `ty::type_is_bot` will return true (n.b.: since Rust is
-    /// strict, _|_ can appear in the type of an expression that does not,
-    /// itself, diverge: for example, fn() -> _|_.)
-    /// Note that inspecting a type's structure *directly* may expose the fact
-    /// that there are actually multiple representations for `Error`, so avoid
-    /// that when err needs to be handled differently.
+    /// Check an expr with an expectation type which may be used to eagerly
+    /// guide inference when evaluating that expr.
     #[instrument(skip(self, expr), level = "debug")]
     pub(super) fn check_expr_with_expectation(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        self.check_expr_with_expectation_and_args(expr, expected, &[], None)
+        self.check_expr_with_expectation_and_args(expr, expected, None)
     }
 
-    /// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a
-    /// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`.
+    /// Same as [`Self::check_expr_with_expectation`], but allows us to pass in
+    /// the arguments of a [`ExprKind::Call`] when evaluating its callee that
+    /// is an [`ExprKind::Path`]. We use this to refine the spans for certain
+    /// well-formedness guarantees for the path expr.
     pub(super) fn check_expr_with_expectation_and_args(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
-        args: &'tcx [hir::Expr<'tcx>],
-        call: Option<&'tcx hir::Expr<'tcx>>,
+        call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
     ) -> Ty<'tcx> {
         if self.tcx().sess.verbose_internals() {
             // make this code only run with -Zverbose-internals because it is probably slow
@@ -236,9 +244,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let ty = ensure_sufficient_stack(|| match &expr.kind {
+            // Intercept the callee path expr and give it better spans.
             hir::ExprKind::Path(
                 qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
-            ) => self.check_expr_path(qpath, expr, Some(args), call),
+            ) => self.check_expr_path(qpath, expr, call_expr_and_args),
             _ => self.check_expr_kind(expr, expected),
         });
         let ty = self.resolve_vars_if_possible(ty);
@@ -472,28 +481,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let tcx = self.tcx;
         match expr.kind {
-            ExprKind::Lit(ref lit) => self.check_lit(lit, expected),
-            ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs, expected),
+            ExprKind::Lit(ref lit) => self.check_expr_lit(lit, expected),
+            ExprKind::Binary(op, lhs, rhs) => self.check_expr_binop(expr, op, lhs, rhs, expected),
             ExprKind::Assign(lhs, rhs, span) => {
                 self.check_expr_assign(expr, expected, lhs, rhs, span)
             }
             ExprKind::AssignOp(op, lhs, rhs) => {
-                self.check_binop_assign(expr, op, lhs, rhs, expected)
+                self.check_expr_binop_assign(expr, op, lhs, rhs, expected)
             }
-            ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
+            ExprKind::Unary(unop, oprnd) => self.check_expr_unop(unop, oprnd, expected, expr),
             ExprKind::AddrOf(kind, mutbl, oprnd) => {
                 self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
             }
             ExprKind::Path(QPath::LangItem(lang_item, _)) => {
                 self.check_lang_item_path(lang_item, expr)
             }
-            ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None),
+            ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None),
             ExprKind::InlineAsm(asm) => {
                 // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).
                 self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
                 self.check_expr_asm(asm)
             }
-            ExprKind::OffsetOf(container, fields) => self.check_offset_of(container, fields, expr),
+            ExprKind::OffsetOf(container, fields) => {
+                self.check_expr_offset_of(container, fields, expr)
+            }
             ExprKind::Break(destination, ref expr_opt) => {
                 self.check_expr_break(destination, expr_opt.as_deref(), expr)
             }
@@ -512,13 +523,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_expr_loop(body, source, expected, expr)
             }
             ExprKind::Match(discrim, arms, match_src) => {
-                self.check_match(expr, discrim, arms, expected, match_src)
+                self.check_expr_match(expr, discrim, arms, expected, match_src)
             }
             ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected),
-            ExprKind::Block(body, _) => self.check_block_with_expected(body, expected),
-            ExprKind::Call(callee, args) => self.check_call(expr, callee, args, expected),
+            ExprKind::Block(body, _) => self.check_expr_block(body, expected),
+            ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected),
             ExprKind::MethodCall(segment, receiver, args, _) => {
-                self.check_method_call(expr, segment, receiver, args, expected)
+                self.check_expr_method_call(expr, segment, receiver, args, expected)
             }
             ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
             ExprKind::Type(e, t) => {
@@ -528,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ascribed_ty
             }
             ExprKind::If(cond, then_expr, opt_else_expr) => {
-                self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected)
+                self.check_expr_if(cond, then_expr, opt_else_expr, expr.span, expected)
             }
             ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
             ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
@@ -540,7 +551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ExprKind::Struct(qpath, fields, ref base_expr) => {
                 self.check_expr_struct(expr, expected, qpath, fields, base_expr)
             }
-            ExprKind::Field(base, field) => self.check_field(expr, base, field, expected),
+            ExprKind::Field(base, field) => self.check_expr_field(expr, base, field, expected),
             ExprKind::Index(base, idx, brackets_span) => {
                 self.check_expr_index(base, idx, expr, brackets_span)
             }
@@ -549,7 +560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_expr_unary(
+    fn check_expr_unop(
         &self,
         unop: hir::UnOp,
         oprnd: &'tcx hir::Expr<'tcx>,
@@ -699,8 +710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         qpath: &'tcx hir::QPath<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
-        args: Option<&'tcx [hir::Expr<'tcx>]>,
-        call: Option<&'tcx hir::Expr<'tcx>>,
+        call_expr_and_args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let (res, opt_ty, segs) =
@@ -730,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     segs,
                     opt_ty,
                     res,
-                    call.map_or(expr.span, |e| e.span),
+                    call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
                     expr.span,
                     expr.hir_id,
                 )
@@ -769,7 +779,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // We just want to check sizedness, so instead of introducing
                     // placeholder lifetimes with probing, we just replace higher lifetimes
                     // with fresh vars.
-                    let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span);
+                    let span = call_expr_and_args
+                        .and_then(|(_, args)| args.get(i))
+                        .map_or(expr.span, |arg| arg.span);
                     let input = self.instantiate_binder_with_fresh_vars(
                         span,
                         infer::BoundRegionConversionTime::FnCall,
@@ -795,7 +807,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
             self.require_type_is_sized_deferred(
                 output,
-                call.map_or(expr.span, |e| e.span),
+                call_expr_and_args.map_or(expr.span, |(e, _)| e.span),
                 ObligationCauseCode::SizedCallReturnType,
             );
         }
@@ -972,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if self.ret_coercion_span.get().is_none() {
                 self.ret_coercion_span.set(Some(e.span));
             }
-            self.check_return_expr(e, true);
+            self.check_return_or_body_tail(e, true);
         } else {
             let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
             if self.ret_coercion_span.get().is_none() {
@@ -1035,7 +1047,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// `explicit_return` is `true` if we're checking an explicit `return expr`,
     /// and `false` if we're checking a trailing expression.
-    pub(super) fn check_return_expr(
+    pub(super) fn check_return_or_body_tail(
         &self,
         return_expr: &'tcx hir::Expr<'tcx>,
         explicit_return: bool,
@@ -1259,7 +1271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     // A generic function for checking the 'then' and 'else' clauses in an 'if'
     // or 'if-else' expression.
-    fn check_then_else(
+    fn check_expr_if(
         &self,
         cond_expr: &'tcx hir::Expr<'tcx>,
         then_expr: &'tcx hir::Expr<'tcx>,
@@ -1542,7 +1554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Checks a method call.
-    fn check_method_call(
+    fn check_expr_method_call(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         segment: &'tcx hir::PathSegment<'tcx>,
@@ -2594,7 +2606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     // Check field access expressions
-    fn check_field(
+    fn check_expr_field(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         base: &'tcx hir::Expr<'tcx>,
@@ -3535,8 +3547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let previous_diverges = self.diverges.get();
 
                     // The label blocks should have unit return value or diverge.
-                    let ty =
-                        self.check_block_with_expected(block, ExpectHasType(self.tcx.types.unit));
+                    let ty = self.check_expr_block(block, ExpectHasType(self.tcx.types.unit));
                     if !ty.is_never() {
                         self.demand_suptype(block.span, self.tcx.types.unit, ty);
                         diverge = false;
@@ -3551,7 +3562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if diverge { self.tcx.types.never } else { self.tcx.types.unit }
     }
 
-    fn check_offset_of(
+    fn check_expr_offset_of(
         &self,
         container: &'tcx hir::Ty<'tcx>,
         fields: &[Ident],
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index 97f3807c252..7719facccc7 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -621,7 +621,11 @@ impl<'tcx> AnnotateUnitFallbackVisitor<'_, 'tcx> {
                 .iter()
                 .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
                 .count();
-            for (idx, arg) in args.iter().enumerate() {
+            for (idx, arg) in args
+                .iter()
+                .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
+                .enumerate()
+            {
                 if let Some(ty) = arg.as_type()
                     && let Some(vid) = self.fcx.root_vid(ty)
                     && self.reachable_vids.contains(&vid)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index ce0ab8a913b..f0738491609 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1306,30 +1306,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
                         )
                         .into(),
-                    GenericParamDefKind::Type { has_default, .. } => {
-                        if !infer_args && has_default {
-                            // If we have a default, then it doesn't matter that we're not
-                            // inferring the type arguments: we provide the default where any
-                            // is missing.
-                            tcx.type_of(param.def_id).instantiate(tcx, preceding_args).into()
-                        } else {
-                            // If no type arguments were provided, we have to infer them.
-                            // This case also occurs as a result of some malformed input, e.g.
-                            // a lifetime argument being given instead of a type parameter.
-                            // Using inference instead of `Error` gives better error messages.
-                            self.fcx.var_for_def(self.span, param)
+                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+                        if !infer_args && let Some(default) = param.default_value(tcx) {
+                            // If we have a default, then it doesn't matter that we're not inferring
+                            // the type/const arguments: We provide the default where any is missing.
+                            return default.instantiate(tcx, preceding_args);
                         }
-                    }
-                    GenericParamDefKind::Const { has_default, .. } => {
-                        if has_default {
-                            if !infer_args {
-                                return tcx
-                                    .const_param_default(param.def_id)
-                                    .instantiate(tcx, preceding_args)
-                                    .into();
-                            }
-                        }
-
+                        // If no type/const arguments were provided, we have to infer them.
+                        // This case also occurs as a result of some malformed input, e.g.,
+                        // a lifetime argument being given instead of a type/const parameter.
+                        // Using inference instead of `Error` gives better error messages.
                         self.fcx.var_for_def(self.span, param)
                     }
                 }
@@ -1491,7 +1477,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
         } else if self.tcx.features().generic_const_exprs() {
-            ct.normalize_internal(self.tcx, self.param_env)
+            rustc_trait_selection::traits::evaluate_const(&self.infcx, ct, self.param_env)
         } else {
             ct
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index f93d0e93406..b09d78614c3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -316,12 +316,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .tcx
             .generics_of(def_id)
             .own_args(ty::GenericArgs::identity_for_item(self.tcx, def_id));
-        let Some((index, _)) =
-            own_args.iter().enumerate().find(|(_, arg)| **arg == param_to_point_at)
-        else {
+        let Some(mut index) = own_args.iter().position(|arg| *arg == param_to_point_at) else {
             return false;
         };
-        let Some(arg) = segment.args().args.get(index) else {
+        // SUBTLE: We may or may not turbofish lifetime arguments, which will
+        // otherwise be elided. if our "own args" starts with a lifetime, but
+        // the args list does not, then we should chop off all of the lifetimes,
+        // since they're all elided.
+        let segment_args = segment.args().args;
+        if matches!(own_args[0].unpack(), ty::GenericArgKind::Lifetime(_))
+            && segment_args.first().is_some_and(|arg| arg.is_ty_or_const())
+            && let Some(offset) = own_args.iter().position(|arg| {
+                matches!(arg.unpack(), ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_))
+            })
+            && let Some(new_index) = index.checked_sub(offset)
+        {
+            index = new_index;
+        }
+        let Some(arg) = segment_args.get(index) else {
             return false;
         };
         error.obligation.cause.span = arg
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a6c249da103..50d1322eba6 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1565,7 +1565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     // AST fragment checking
-    pub(in super::super) fn check_lit(
+    pub(in super::super) fn check_expr_lit(
         &self,
         lit: &hir::Lit,
         expected: Expectation<'tcx>,
@@ -1747,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         if let Some(blk) = decl.origin.try_get_else() {
             let previous_diverges = self.diverges.get();
-            let else_ty = self.check_block_with_expected(blk, NoExpectation);
+            let else_ty = self.check_expr_block(blk, NoExpectation);
             let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
             if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
             {
@@ -1805,7 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub(crate) fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
         let unit = self.tcx.types.unit;
-        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
+        let ty = self.check_expr_block(blk, ExpectHasType(unit));
 
         // if the block produces a `!` value, that can always be
         // (effectively) coerced to unit.
@@ -1814,7 +1814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub(in super::super) fn check_block_with_expected(
+    pub(in super::super) fn check_expr_block(
         &self,
         blk: &'tcx hir::Block<'tcx>,
         expected: Expectation<'tcx>,
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index f5987a11fa5..63dccf8b0ce 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
+#![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(never_type)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index cb20a1d7c7b..8772599e316 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3874,22 +3874,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 param.name.ident(),
                             ));
                             let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
+                            let mut applicability = Applicability::MaybeIncorrect;
+                            // Format the path of each suggested candidate, providing placeholders
+                            // for any generic arguments without defaults.
+                            let candidate_strs: Vec<_> = candidates
+                                .iter()
+                                .map(|cand| {
+                                    let cand_path = self.tcx.def_path_str(cand.def_id);
+                                    let cand_params = &self.tcx.generics_of(cand.def_id).own_params;
+                                    let cand_args: String = cand_params
+                                        .iter()
+                                        .skip(1)
+                                        .filter_map(|param| match param.kind {
+                                            ty::GenericParamDefKind::Type {
+                                                has_default: true,
+                                                ..
+                                            }
+                                            | ty::GenericParamDefKind::Const {
+                                                has_default: true,
+                                                ..
+                                            } => None,
+                                            _ => Some(param.name.as_str()),
+                                        })
+                                        .intersperse(", ")
+                                        .collect();
+                                    if cand_args.is_empty() {
+                                        cand_path
+                                    } else {
+                                        applicability = Applicability::HasPlaceholders;
+                                        format!("{cand_path}</* {cand_args} */>")
+                                    }
+                                })
+                                .collect();
+
                             if rcvr_ty.is_ref()
                                 && param.is_impl_trait()
                                 && let Some((bounds_span, _)) = bounds_span
                             {
                                 err.multipart_suggestions(
                                     msg,
-                                    candidates.iter().map(|t| {
+                                    candidate_strs.iter().map(|cand| {
                                         vec![
                                             (param.span.shrink_to_lo(), "(".to_string()),
-                                            (
-                                                bounds_span,
-                                                format!(" + {})", self.tcx.def_path_str(t.def_id)),
-                                            ),
+                                            (bounds_span, format!(" + {cand})")),
                                         ]
                                     }),
-                                    Applicability::MaybeIncorrect,
+                                    applicability,
                                 );
                                 return;
                             }
@@ -3905,16 +3935,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     (param.span.shrink_to_hi(), Introducer::Colon, None)
                                 };
 
-                            let all_suggs = candidates.iter().map(|cand| {
-                                let suggestion = format!(
-                                    "{} {}",
-                                    match introducer {
-                                        Introducer::Plus => " +",
-                                        Introducer::Colon => ":",
-                                        Introducer::Nothing => "",
-                                    },
-                                    self.tcx.def_path_str(cand.def_id)
-                                );
+                            let all_suggs = candidate_strs.iter().map(|cand| {
+                                let suggestion = format!("{} {cand}", match introducer {
+                                    Introducer::Plus => " +",
+                                    Introducer::Colon => ":",
+                                    Introducer::Nothing => "",
+                                },);
 
                                 let mut suggs = vec![];
 
@@ -3928,11 +3954,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 suggs
                             });
 
-                            err.multipart_suggestions(
-                                msg,
-                                all_suggs,
-                                Applicability::MaybeIncorrect,
-                            );
+                            err.multipart_suggestions(msg, all_suggs, applicability);
 
                             return;
                         }
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 9a3492abc9f..72b930ee84d 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -26,7 +26,7 @@ use crate::Expectation;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Checks a `a <op>= b`
-    pub(crate) fn check_binop_assign(
+    pub(crate) fn check_expr_binop_assign(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         op: hir::BinOp,
@@ -85,7 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Checks a potentially overloaded binary operator.
-    pub(crate) fn check_binop(
+    pub(crate) fn check_expr_binop(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         op: hir::BinOp,
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index fc54d69449f..12df4a10e63 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -25,10 +25,10 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::extension;
 pub use rustc_macros::{TypeFoldable, TypeVisitable};
+use rustc_middle::bug;
 use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::traits::select;
 pub use rustc_middle::ty::IntVarValue;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -40,7 +40,6 @@ use rustc_middle::ty::{
     self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
     GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
 };
-use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
 use rustc_type_ir::solve::Reveal;
@@ -1279,84 +1278,6 @@ impl<'tcx> InferCtxt<'tcx> {
         u
     }
 
-    pub fn try_const_eval_resolve(
-        &self,
-        param_env: ty::ParamEnv<'tcx>,
-        unevaluated: ty::UnevaluatedConst<'tcx>,
-        span: Span,
-    ) -> Result<ty::Const<'tcx>, ErrorHandled> {
-        match self.const_eval_resolve(param_env, unevaluated, span) {
-            Ok(Ok(val)) => Ok(ty::Const::new_value(
-                self.tcx,
-                val,
-                self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
-            )),
-            Ok(Err(bad_ty)) => {
-                let tcx = self.tcx;
-                let def_id = unevaluated.def;
-                span_bug!(
-                    tcx.def_span(def_id),
-                    "unable to construct a valtree for the unevaluated constant {:?}: type {bad_ty} is not valtree-compatible",
-                    unevaluated
-                );
-            }
-            Err(err) => Err(err),
-        }
-    }
-
-    /// Resolves and evaluates a constant.
-    ///
-    /// The constant can be located on a trait like `<A as B>::C`, in which case the given
-    /// generic parameters and environment are used to resolve the constant. Alternatively if the
-    /// constant has generic parameters in scope the instantiations are used to evaluate the value
-    /// of the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
-    /// constant `bar::<T>()` requires a instantiation for `T`, if the instantiation for `T` is
-    /// still too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
-    /// returned.
-    ///
-    /// This handles inferences variables within both `param_env` and `args` by
-    /// performing the operation on their respective canonical forms.
-    #[instrument(skip(self), level = "debug")]
-    pub fn const_eval_resolve(
-        &self,
-        mut param_env: ty::ParamEnv<'tcx>,
-        unevaluated: ty::UnevaluatedConst<'tcx>,
-        span: Span,
-    ) -> EvalToValTreeResult<'tcx> {
-        let mut args = self.resolve_vars_if_possible(unevaluated.args);
-        debug!(?args);
-
-        // Postpone the evaluation of constants whose args depend on inference
-        // variables
-        let tcx = self.tcx;
-        if args.has_non_region_infer() {
-            if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
-                let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
-                if let Err(e) = ct.error_reported() {
-                    return Err(ErrorHandled::Reported(e.into(), span));
-                } else if ct.has_non_region_infer() || ct.has_non_region_param() {
-                    return Err(ErrorHandled::TooGeneric(span));
-                } else {
-                    args = replace_param_and_infer_args_with_placeholder(tcx, args);
-                }
-            } else {
-                args = GenericArgs::identity_for_item(tcx, unevaluated.def);
-                param_env = tcx.param_env(unevaluated.def);
-            }
-        }
-
-        let param_env_erased = tcx.erase_regions(param_env);
-        let args_erased = tcx.erase_regions(args);
-        debug!(?param_env_erased);
-        debug!(?args_erased);
-
-        let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased };
-
-        // The return value is the evaluated value which doesn't contain any reference to inference
-        // variables, thus we don't need to instantiate back the original values.
-        tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
-    }
-
     /// The returned function is used in a fast path. If it returns `true` the variable is
     /// unchanged, `false` indicates that the status is unknown.
     #[inline]
@@ -1622,61 +1543,6 @@ impl RegionVariableOrigin {
     }
 }
 
-/// Replaces args that reference param or infer variables with suitable
-/// placeholders. This function is meant to remove these param and infer
-/// args when they're not actually needed to evaluate a constant.
-fn replace_param_and_infer_args_with_placeholder<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    args: GenericArgsRef<'tcx>,
-) -> GenericArgsRef<'tcx> {
-    struct ReplaceParamAndInferWithPlaceholder<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        idx: u32,
-    }
-
-    impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
-        fn cx(&self) -> TyCtxt<'tcx> {
-            self.tcx
-        }
-
-        fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-            if let ty::Infer(_) = t.kind() {
-                let idx = {
-                    let idx = self.idx;
-                    self.idx += 1;
-                    idx
-                };
-                Ty::new_placeholder(self.tcx, ty::PlaceholderType {
-                    universe: ty::UniverseIndex::ROOT,
-                    bound: ty::BoundTy {
-                        var: ty::BoundVar::from_u32(idx),
-                        kind: ty::BoundTyKind::Anon,
-                    },
-                })
-            } else {
-                t.super_fold_with(self)
-            }
-        }
-
-        fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-            if let ty::ConstKind::Infer(_) = c.kind() {
-                ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst {
-                    universe: ty::UniverseIndex::ROOT,
-                    bound: ty::BoundVar::from_u32({
-                        let idx = self.idx;
-                        self.idx += 1;
-                        idx
-                    }),
-                })
-            } else {
-                c.super_fold_with(self)
-            }
-        }
-    }
-
-    args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
-}
-
 impl<'tcx> InferCtxt<'tcx> {
     /// Given a [`hir::Block`], get the span of its last expression or
     /// statement, peeling off any inner blocks.
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index b5abf145d6b..7a2ba07ce87 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -5,8 +5,8 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-rustc-rayon = { version = "0.5.0", optional = true }
-rustc-rayon-core = { version = "0.5.0", optional = true }
+rustc-rayon = { version = "0.5.0" }
+rustc-rayon-core = { version = "0.5.0" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_lowering = { path = "../rustc_ast_lowering" }
 rustc_ast_passes = { path = "../rustc_ast_passes" }
@@ -54,10 +54,4 @@ tracing = "0.1"
 [features]
 # tidy-alphabetical-start
 llvm = ['dep:rustc_codegen_llvm']
-rustc_use_parallel_compiler = [
-    'dep:rustc-rayon',
-    'dep:rustc-rayon-core',
-    'rustc_query_impl/rustc_use_parallel_compiler',
-    'rustc_errors/rustc_use_parallel_compiler'
-]
 # tidy-alphabetical-end
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index fd850d2f39a..7e629c1d18f 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -175,7 +175,7 @@ fn configure_and_expand(
         if cfg!(windows) {
             old_path = env::var_os("PATH").unwrap_or(old_path);
             let mut new_path = Vec::from_iter(
-                sess.host_filesearch(PathKind::All).search_paths().map(|p| p.dir.clone()),
+                sess.host_filesearch().search_paths(PathKind::All).map(|p| p.dir.clone()),
             );
             for path in env::split_paths(&old_path) {
                 if !new_path.contains(&path) {
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index b5bddc4b21a..d3213b1263c 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -6,7 +6,6 @@ use std::{env, iter, thread};
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
-#[cfg(parallel_compiler)]
 use rustc_data_structures::sync;
 use rustc_metadata::{DylibError, load_symbol_from_dylib};
 use rustc_middle::ty::CurrentGcx;
@@ -117,19 +116,6 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
     })
 }
 
-#[cfg(not(parallel_compiler))]
-pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
-    thread_builder_diag: &EarlyDiagCtxt,
-    edition: Edition,
-    _threads: usize,
-    sm_inputs: SourceMapInputs,
-    f: F,
-) -> R {
-    let thread_stack_size = init_stack_size(thread_builder_diag);
-    run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, f)
-}
-
-#[cfg(parallel_compiler)]
 pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
     thread_builder_diag: &EarlyDiagCtxt,
     edition: Edition,
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 9187f6caad4..6e35d89b488 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -346,7 +346,6 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos
         *[other] these lifetimes are
      } in scope but not mentioned in the type's bounds
     .note2 = all lifetimes in scope will be captured by `impl Trait`s in edition 2024
-    .suggestion = use the precise capturing `use<...>` syntax to make the captures explicit
 
 lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
     .suggestion = remove the `use<...>` syntax
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 02d22ee49bd..130f3cb7c2a 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1298,12 +1298,30 @@ impl UnreachablePub {
         let mut applicability = Applicability::MachineApplicable;
         if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
         {
+            // prefer suggesting `pub(super)` instead of `pub(crate)` when possible,
+            // except when `pub(super) == pub(crate)`
+            let new_vis = if let Some(ty::Visibility::Restricted(restricted_did)) =
+                cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| {
+                    effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable)
+                })
+                && let parent_parent = cx.tcx.parent_module_from_def_id(
+                    cx.tcx.parent_module_from_def_id(def_id.into()).into(),
+                )
+                && *restricted_did == parent_parent.to_local_def_id()
+                && !restricted_did.to_def_id().is_crate_root()
+            {
+                "pub(super)"
+            } else {
+                "pub(crate)"
+            };
+
             if vis_span.from_expansion() {
                 applicability = Applicability::MaybeIncorrect;
             }
             let def_span = cx.tcx.def_span(def_id);
             cx.emit_span_lint(UNREACHABLE_PUB, def_span, BuiltinUnreachablePub {
                 what,
+                new_vis,
                 suggestion: (vis_span, applicability),
                 help: exportable,
             });
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index 002ab027982..beab4d4e6a9 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -3,7 +3,7 @@ use std::cell::LazyCell;
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{Applicability, LintDiagnostic};
+use rustc_errors::{LintDiagnostic, Subdiagnostic};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -22,6 +22,9 @@ use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::edition::Edition;
 use rustc_span::{Span, Symbol};
+use rustc_trait_selection::errors::{
+    AddPreciseCapturingForOvercapture, impl_trait_overcapture_suggestion,
+};
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
 
@@ -259,7 +262,11 @@ where
             // If it's owned by this function
             && let opaque =
                 self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty()
-            && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = opaque.origin
+            // We want to recurse into RPITs and async fns, even though the latter
+            // doesn't overcapture on its own, it may mention additional RPITs
+            // in its bounds.
+            && let hir::OpaqueTyOrigin::FnReturn { parent, .. }
+                | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = opaque.origin
             && parent == self.parent_def_id
         {
             let opaque_span = self.tcx.def_span(opaque_def_id);
@@ -334,32 +341,12 @@ where
                 // If we have uncaptured args, and if the opaque doesn't already have
                 // `use<>` syntax on it, and we're < edition 2024, then warn the user.
                 if !uncaptured_args.is_empty() {
-                    let suggestion = if let Ok(snippet) =
-                        self.tcx.sess.source_map().span_to_snippet(opaque_span)
-                        && snippet.starts_with("impl ")
-                    {
-                        let (lifetimes, others): (Vec<_>, Vec<_>) =
-                            captured.into_iter().partition(|def_id| {
-                                self.tcx.def_kind(*def_id) == DefKind::LifetimeParam
-                            });
-                        // Take all lifetime params first, then all others (ty/ct).
-                        let generics: Vec<_> = lifetimes
-                            .into_iter()
-                            .chain(others)
-                            .map(|def_id| self.tcx.item_name(def_id).to_string())
-                            .collect();
-                        // Make sure that we're not trying to name any APITs
-                        if generics.iter().all(|name| !name.starts_with("impl ")) {
-                            Some((
-                                format!(" + use<{}>", generics.join(", ")),
-                                opaque_span.shrink_to_hi(),
-                            ))
-                        } else {
-                            None
-                        }
-                    } else {
-                        None
-                    };
+                    let suggestion = impl_trait_overcapture_suggestion(
+                        self.tcx,
+                        opaque_def_id,
+                        self.parent_def_id,
+                        captured,
+                    );
 
                     let uncaptured_spans: Vec<_> = uncaptured_args
                         .into_iter()
@@ -451,7 +438,7 @@ struct ImplTraitOvercapturesLint<'tcx> {
     uncaptured_spans: Vec<Span>,
     self_ty: Ty<'tcx>,
     num_captured: usize,
-    suggestion: Option<(String, Span)>,
+    suggestion: Option<AddPreciseCapturingForOvercapture>,
 }
 
 impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
@@ -461,13 +448,8 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
             .arg("num_captured", self.num_captured)
             .span_note(self.uncaptured_spans, fluent::lint_note)
             .note(fluent::lint_note2);
-        if let Some((suggestion, span)) = self.suggestion {
-            diag.span_suggestion(
-                span,
-                fluent::lint_suggestion,
-                suggestion,
-                Applicability::MachineApplicable,
-            );
+        if let Some(suggestion) = self.suggestion {
+            suggestion.add_to_diag(diag);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 38e52570e53..352155729e5 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -254,7 +254,8 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
 #[diag(lint_builtin_unreachable_pub)]
 pub(crate) struct BuiltinUnreachablePub<'a> {
     pub what: &'a str,
-    #[suggestion(code = "pub(crate)")]
+    pub new_vis: &'a str,
+    #[suggestion(code = "{new_vis}")]
     pub suggestion: (Span, Applicability),
     #[help]
     pub help: bool,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 1ed702ab4cb..489c911d7ee 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -882,10 +882,12 @@ extern "C" LLVMRustResult LLVMRustOptimize(
         SanitizerOptions->SanitizeKernelAddress) {
       OptimizerLastEPCallbacks.push_back(
 #if LLVM_VERSION_GE(20, 0)
-          [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level,
-                             ThinOrFullLTOPhase phase) {
+          [SanitizerOptions, TM](ModulePassManager &MPM,
+                                 OptimizationLevel Level,
+                                 ThinOrFullLTOPhase phase) {
 #else
-          [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
+          [SanitizerOptions, TM](ModulePassManager &MPM,
+                                 OptimizationLevel Level) {
 #endif
             auto CompileKernel = SanitizerOptions->SanitizeKernelAddress;
             AddressSanitizerOptions opts = AddressSanitizerOptions{
@@ -895,7 +897,12 @@ extern "C" LLVMRustResult LLVMRustOptimize(
                 /*UseAfterScope=*/true,
                 AsanDetectStackUseAfterReturnMode::Runtime,
             };
-            MPM.addPass(AddressSanitizerPass(opts));
+            MPM.addPass(AddressSanitizerPass(
+                opts,
+                /*UseGlobalGC*/ true,
+                // UseOdrIndicator should be false on windows machines
+                // https://reviews.llvm.org/D137227
+                !TM->getTargetTriple().isOSWindows()));
           });
     }
     if (SanitizerOptions->SanitizeHWAddress) {
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index e525d94a0c1..ca16a66763a 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -507,7 +507,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         locator.is_proc_macro = true;
         locator.target = &self.sess.host;
         locator.tuple = TargetTuple::from_tuple(config::host_tuple());
-        locator.filesearch = self.sess.host_filesearch(path_kind);
+        locator.filesearch = self.sess.host_filesearch();
+        locator.path_kind = path_kind;
 
         let Some(host_result) = self.load(locator)? else {
             return Ok(None);
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index ddd97fc66f6..0b53e5eeaa8 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -253,9 +253,10 @@ pub(crate) struct CrateLocator<'a> {
     extra_filename: Option<&'a str>,
     pub target: &'a Target,
     pub tuple: TargetTuple,
-    pub filesearch: FileSearch<'a>,
+    pub filesearch: &'a FileSearch,
     pub is_proc_macro: bool,
 
+    pub path_kind: PathKind,
     // Mutable in-progress state or output.
     crate_rejections: CrateRejections,
 }
@@ -339,7 +340,8 @@ impl<'a> CrateLocator<'a> {
             extra_filename,
             target: &sess.target,
             tuple: sess.opts.target_triple.clone(),
-            filesearch: sess.target_filesearch(path_kind),
+            filesearch: sess.target_filesearch(),
+            path_kind,
             is_proc_macro: false,
             crate_rejections: CrateRejections::default(),
         }
@@ -407,47 +409,49 @@ impl<'a> CrateLocator<'a> {
         // given that `extra_filename` comes from the `-C extra-filename`
         // option and thus can be anything, and the incorrect match will be
         // handled safely in `extract_one`.
-        for search_path in self.filesearch.search_paths() {
+        for search_path in self.filesearch.search_paths(self.path_kind) {
             debug!("searching {}", search_path.dir.display());
-            for spf in search_path.files.iter() {
-                debug!("testing {}", spf.path.display());
+            let spf = &search_path.files;
 
-                let f = &spf.file_name_str;
-                let (hash, kind) = if let Some(f) = f.strip_prefix(rlib_prefix)
-                    && let Some(f) = f.strip_suffix(rlib_suffix)
-                {
-                    (f, CrateFlavor::Rlib)
-                } else if let Some(f) = f.strip_prefix(rmeta_prefix)
-                    && let Some(f) = f.strip_suffix(rmeta_suffix)
-                {
-                    (f, CrateFlavor::Rmeta)
-                } else if let Some(f) = f.strip_prefix(dylib_prefix)
-                    && let Some(f) = f.strip_suffix(dylib_suffix.as_ref())
-                {
-                    (f, CrateFlavor::Dylib)
-                } else {
-                    if f.starts_with(staticlib_prefix) && f.ends_with(staticlib_suffix.as_ref()) {
-                        self.crate_rejections.via_kind.push(CrateMismatch {
-                            path: spf.path.clone(),
-                            got: "static".to_string(),
-                        });
-                    }
-                    continue;
-                };
-
-                info!("lib candidate: {}", spf.path.display());
+            let mut should_check_staticlibs = true;
+            for (prefix, suffix, kind) in [
+                (rlib_prefix.as_str(), rlib_suffix, CrateFlavor::Rlib),
+                (rmeta_prefix.as_str(), rmeta_suffix, CrateFlavor::Rmeta),
+                (dylib_prefix, dylib_suffix, CrateFlavor::Dylib),
+            ] {
+                if prefix == staticlib_prefix && suffix == staticlib_suffix {
+                    should_check_staticlibs = false;
+                }
+                if let Some(matches) = spf.query(prefix, suffix) {
+                    for (hash, spf) in matches {
+                        info!("lib candidate: {}", spf.path.display());
 
-                let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
-                let path = try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
-                if seen_paths.contains(&path) {
-                    continue;
-                };
-                seen_paths.insert(path.clone());
-                match kind {
-                    CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
-                    CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
-                    CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),
-                };
+                        let (rlibs, rmetas, dylibs) =
+                            candidates.entry(hash.to_string()).or_default();
+                        let path =
+                            try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.to_path_buf());
+                        if seen_paths.contains(&path) {
+                            continue;
+                        };
+                        seen_paths.insert(path.clone());
+                        match kind {
+                            CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
+                            CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
+                            CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),
+                        };
+                    }
+                }
+            }
+            if let Some(static_matches) = should_check_staticlibs
+                .then(|| spf.query(staticlib_prefix, staticlib_suffix))
+                .flatten()
+            {
+                for (_, spf) in static_matches {
+                    self.crate_rejections.via_kind.push(CrateMismatch {
+                        path: spf.path.to_path_buf(),
+                        got: "static".to_string(),
+                    });
+                }
             }
         }
 
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index b7695216f3c..493db498b7c 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -28,10 +28,10 @@ pub fn walk_native_lib_search_dirs<R>(
     mut f: impl FnMut(&Path, bool /*is_framework*/) -> ControlFlow<R>,
 ) -> ControlFlow<R> {
     // Library search paths explicitly supplied by user (`-L` on the command line).
-    for search_path in sess.target_filesearch(PathKind::Native).cli_search_paths() {
+    for search_path in sess.target_filesearch().cli_search_paths(PathKind::Native) {
         f(&search_path.dir, false)?;
     }
-    for search_path in sess.target_filesearch(PathKind::Framework).cli_search_paths() {
+    for search_path in sess.target_filesearch().cli_search_paths(PathKind::Framework) {
         // Frameworks are looked up strictly in framework-specific paths.
         if search_path.kind != PathKind::All {
             f(&search_path.dir, true)?;
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 485d1c14df3..3bda3a4aa63 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -11,7 +11,7 @@ either = "1.5.0"
 field-offset = "0.3.5"
 gsgdt = "0.1.2"
 polonius-engine = "0.13.0"
-rustc-rayon-core = { version = "0.5.0", optional = true }
+rustc-rayon-core = { version = "0.5.0" }
 rustc_abi = { path = "../rustc_abi" }
 rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena" }
@@ -43,5 +43,4 @@ tracing = "0.1"
 [features]
 # tidy-alphabetical-start
 rustc_randomized_layouts = []
-rustc_use_parallel_compiler = ["dep:rustc-rayon-core"]
 # tidy-alphabetical-end
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 1ae0bd6740d..f95635370dc 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -1,17 +1,17 @@
 use std::fmt::{self, Debug, Display, Formatter};
 
-use either::Either;
 use rustc_abi::{HasDataLayout, Size};
 use rustc_hir::def_id::DefId;
 use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_session::RemapFileNameExt;
 use rustc_session::config::RemapPathScopeComponents;
 use rustc_span::{DUMMY_SP, Span};
+use rustc_type_ir::visit::TypeVisitableExt;
 
 use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range};
 use crate::mir::{Promoted, pretty_print_const_value};
 use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
-use crate::ty::{self, GenericArgsRef, ScalarInt, Ty, TyCtxt};
+use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt};
 
 ///////////////////////////////////////////////////////////////////////////
 /// Evaluated Constants
@@ -319,15 +319,16 @@ impl<'tcx> Const<'tcx> {
     ) -> Result<ConstValue<'tcx>, ErrorHandled> {
         match self {
             Const::Ty(_, c) => {
-                // We want to consistently have a "clean" value for type system constants (i.e., no
-                // data hidden in the padding), so we always go through a valtree here.
-                match c.eval_valtree(tcx, param_env, span) {
-                    Ok((ty, val)) => Ok(tcx.valtree_to_const_val((ty, val))),
-                    Err(Either::Left(_bad_ty)) => Err(tcx
-                        .dcx()
-                        .delayed_bug("`mir::Const::eval` called on a non-valtree-compatible type")
-                        .into()),
-                    Err(Either::Right(e)) => Err(e),
+                if c.has_non_region_param() {
+                    return Err(ErrorHandled::TooGeneric(span));
+                }
+
+                match c.kind() {
+                    ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))),
+                    ConstKind::Expr(_) => {
+                        bug!("Normalization of `ty::ConstKind::Expr` is unimplemented")
+                    }
+                    _ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()),
                 }
             }
             Const::Unevaluated(uneval, _) => {
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 4a876dc1228..11a4e7f89a7 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -4,7 +4,7 @@ use std::fmt::{self, Debug, Formatter};
 
 use rustc_index::IndexVec;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 
 rustc_index::newtype_index! {
     /// Used by [`CoverageKind::BlockMarker`] to mark blocks during THIR-to-MIR
@@ -158,7 +158,6 @@ impl Debug for CoverageKind {
 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub struct SourceRegion {
-    pub file_name: Symbol,
     pub start_line: u32,
     pub start_col: u32,
     pub end_line: u32,
@@ -167,11 +166,8 @@ pub struct SourceRegion {
 
 impl Debug for SourceRegion {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        write!(
-            fmt,
-            "{}:{}:{} - {}:{}",
-            self.file_name, self.start_line, self.start_col, self.end_line, self.end_col
-        )
+        let &Self { start_line, start_col, end_line, end_col } = self;
+        write!(fmt, "{start_line}:{start_col} - {end_line}:{end_col}")
     }
 }
 
@@ -246,6 +242,7 @@ pub struct Mapping {
 #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct FunctionCoverageInfo {
     pub function_source_hash: u64,
+    pub body_span: Span,
     pub num_counters: usize,
     pub mcdc_bitmap_bits: usize,
     pub expressions: IndexVec<ExpressionId, Expression>,
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index d0f93c19e44..f0e2b7a376c 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -596,8 +596,10 @@ fn write_function_coverage_info(
     function_coverage_info: &coverage::FunctionCoverageInfo,
     w: &mut dyn io::Write,
 ) -> io::Result<()> {
-    let coverage::FunctionCoverageInfo { expressions, mappings, .. } = function_coverage_info;
+    let coverage::FunctionCoverageInfo { body_span, expressions, mappings, .. } =
+        function_coverage_info;
 
+    writeln!(w, "{INDENT}coverage body span: {body_span:?}")?;
     for (id, expression) in expressions.iter_enumerated() {
         writeln!(w, "{INDENT}coverage {id:?} => {expression:?};")?;
     }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 54ead9a7a75..4e3668822ec 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -463,7 +463,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
+    /// Fetch the THIR for a given body.
     query thir_body(key: LocalDefId) -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed> {
         // Perf tests revealed that hashing THIR is inefficient (see #85729).
         no_hash
@@ -2326,13 +2326,19 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Check the signature of this function as well as all the call expressions inside of it
-    /// to ensure that any target features required by the ABI are enabled.
-    /// Should be called on a fully monomorphized instance.
-    query check_feature_dependent_abi(key: ty::Instance<'tcx>) {
-        desc { "check for feature-dependent ABI" }
+    /// Perform monomorphization-time checking on this item.
+    /// This is used for lints/errors that can only be checked once the instance is fully
+    /// monomorphized.
+    query check_mono_item(key: ty::Instance<'tcx>) {
+        desc { "monomorphization-time checking" }
         cache_on_disk_if { true }
     }
+
+    /// Builds the set of functions that should be skipped for the move-size check.
+    query skip_move_check_fns(_: ()) -> &'tcx FxIndexSet<DefId> {
+        arena_cache
+        desc { "functions to skip for move-size check" }
+    }
 }
 
 rustc_query_append! { define_callbacks! }
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 57da5b39ba7..20ba1b27c0e 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -319,7 +319,7 @@ macro_rules! define_callbacks {
 
                 pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>;
 
-                // Ensure that keys grow no larger than 72 bytes by accident.
+                // Ensure that keys grow no larger than 80 bytes by accident.
                 // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(target_pointer_width = "64")]
                 const _: () = {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 45ceb0a555d..70df2379016 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -645,7 +645,7 @@ impl<'tcx> Pat<'tcx> {
             | Binding { subpattern: Some(subpattern), .. }
             | Deref { subpattern }
             | DerefPattern { subpattern, .. }
-            | InlineConstant { subpattern, .. } => subpattern.walk_(it),
+            | ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
             Leaf { subpatterns } | Variant { subpatterns, .. } => {
                 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
             }
@@ -788,12 +788,17 @@ pub enum PatKind<'tcx> {
         value: mir::Const<'tcx>,
     },
 
-    /// Inline constant found while lowering a pattern.
-    InlineConstant {
-        /// [LocalDefId] of the constant, we need this so that we have a
+    /// Pattern obtained by converting a constant (inline or named) to its pattern
+    /// representation using `const_to_pat`.
+    ExpandedConstant {
+        /// [DefId] of the constant, we need this so that we have a
         /// reference that can be used by unsafety checking to visit nested
-        /// unevaluated constants.
-        def: LocalDefId,
+        /// unevaluated constants and for diagnostics. If the `DefId` doesn't
+        /// correspond to a local crate, it points at the `const` item.
+        def_id: DefId,
+        /// If `false`, then `def_id` points at a `const` item, otherwise it
+        /// corresponds to a local inline const.
+        is_inline: bool,
         /// If the inline constant is used in a range pattern, this subpattern
         /// represents the range (if both ends are inline constants, there will
         /// be multiple InlineConstant wrappers).
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 36f0e3d890c..81202a6eaad 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -247,7 +247,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
             }
         }
         Constant { value: _ } => {}
-        InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
+        ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern),
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
             for subpattern in prefix.iter() {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 5ab85a69ce6..5689f3d4265 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,4 +1,3 @@
-use either::Either;
 use rustc_data_structures::intern::Interned;
 use rustc_error_messages::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
@@ -9,7 +8,7 @@ use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
 use tracing::{debug, instrument};
 
 use crate::middle::resolve_bound_vars as rbv;
-use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar};
+use crate::mir::interpret::{LitToConstInput, Scalar};
 use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 
 mod int;
@@ -18,7 +17,7 @@ mod valtree;
 
 pub use int::*;
 pub use kind::*;
-use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
+use rustc_span::{DUMMY_SP, ErrorGuaranteed};
 pub use valtree::*;
 
 pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
@@ -363,60 +362,6 @@ impl<'tcx> Const<'tcx> {
         Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
     }
 
-    /// Returns the evaluated constant as a valtree;
-    /// if that fails due to a valtree-incompatible type, indicate which type that is
-    /// by returning `Err(Left(bad_type))`.
-    #[inline]
-    pub fn eval_valtree(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        span: Span,
-    ) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either<Ty<'tcx>, ErrorHandled>> {
-        assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
-        match self.kind() {
-            ConstKind::Unevaluated(unevaluated) => {
-                // FIXME(eddyb) maybe the `const_eval_*` methods should take
-                // `ty::ParamEnvAnd` instead of having them separate.
-                let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
-                // try to resolve e.g. associated constants to their definition on an impl, and then
-                // evaluate the const.
-                match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) {
-                    Ok(Ok(c)) => {
-                        Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c))
-                    }
-                    Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)),
-                    Err(err) => Err(Either::Right(err)),
-                }
-            }
-            ConstKind::Value(ty, val) => Ok((ty, val)),
-            ConstKind::Error(g) => Err(Either::Right(g.into())),
-            ConstKind::Param(_)
-            | ConstKind::Infer(_)
-            | ConstKind::Bound(_, _)
-            | ConstKind::Placeholder(_)
-            | ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))),
-        }
-    }
-
-    /// Normalizes the constant to a value or an error if possible.
-    #[inline]
-    pub fn normalize_internal(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
-        match self.eval_valtree(tcx, param_env, DUMMY_SP) {
-            Ok((ty, val)) => Self::new_value(tcx, val, ty),
-            Err(Either::Left(_bad_ty)) => {
-                // This can happen when we run on ill-typed code.
-                Self::new_error(
-                    tcx,
-                    tcx.dcx()
-                        .delayed_bug("`ty::Const::eval` called on a non-valtree-compatible type"),
-                )
-            }
-            Err(Either::Right(ErrorHandled::Reported(r, _span))) => Self::new_error(tcx, r.into()),
-            Err(Either::Right(ErrorHandled::TooGeneric(_span))) => self,
-        }
-    }
-
     /// Panics if self.kind != ty::ConstKind::Value
     pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) {
         match self.kind() {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 91b764ae1d4..b3436550e8e 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,46 +1,12 @@
 use std::assert_matches::assert_matches;
 
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension};
+use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 
 use super::Const;
 use crate::mir;
 use crate::ty::abstract_const::CastKind;
-use crate::ty::visit::TypeVisitableExt as _;
 use crate::ty::{self, Ty, TyCtxt};
 
-#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
-impl<'tcx> ty::UnevaluatedConst<'tcx> {
-    /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
-    /// hurts performance.
-    #[inline]
-    fn prepare_for_eval(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> (ty::ParamEnv<'tcx>, Self) {
-        // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
-        // also does later, but we want to do it before checking for
-        // inference variables.
-        // Note that we erase regions *before* calling `with_reveal_all_normalized`,
-        // so that we don't try to invoke this query with
-        // any region variables.
-
-        // HACK(eddyb) when the query key would contain inference variables,
-        // attempt using identity args and `ParamEnv` instead, that will succeed
-        // when the expression doesn't depend on any parameters.
-        // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
-        // we can call `infcx.const_eval_resolve` which handles inference variables.
-        if (param_env, self).has_non_region_infer() {
-            (tcx.param_env(self.def), ty::UnevaluatedConst {
-                def: self.def,
-                args: ty::GenericArgs::identity_for_item(tcx, self.def),
-            })
-        } else {
-            (tcx.erase_regions(param_env).with_reveal_all_normalized(tcx), tcx.erase_regions(self))
-        }
-    }
-}
-
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
 pub enum ExprKind {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index c55733da7b3..84ac281c258 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -22,9 +22,9 @@ use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, RwLock, WorkerLocal};
-#[cfg(parallel_compiler)]
-use rustc_data_structures::sync::{DynSend, DynSync};
+use rustc_data_structures::sync::{
+    self, DynSend, DynSync, FreezeReadGuard, Lock, Lrc, RwLock, WorkerLocal,
+};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan,
@@ -1259,9 +1259,7 @@ pub struct TyCtxt<'tcx> {
 }
 
 // Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution.
-#[cfg(parallel_compiler)]
 unsafe impl DynSend for TyCtxt<'_> {}
-#[cfg(parallel_compiler)]
 unsafe impl DynSync for TyCtxt<'_> {}
 fn _assert_tcx_fields() {
     sync::assert_dyn_sync::<&'_ GlobalCtxt<'_>>();
@@ -1383,9 +1381,7 @@ pub struct CurrentGcx {
     value: Lrc<RwLock<Option<*const ()>>>,
 }
 
-#[cfg(parallel_compiler)]
 unsafe impl DynSend for CurrentGcx {}
-#[cfg(parallel_compiler)]
 unsafe impl DynSync for CurrentGcx {}
 
 impl CurrentGcx {
diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs
index 6a5d3030646..eaab8474dd2 100644
--- a/compiler/rustc_middle/src/ty/context/tls.rs
+++ b/compiler/rustc_middle/src/ty/context/tls.rs
@@ -1,5 +1,3 @@
-#[cfg(not(parallel_compiler))]
-use std::cell::Cell;
 use std::{mem, ptr};
 
 use rustc_data_structures::sync::{self, Lock};
@@ -50,16 +48,8 @@ impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
 }
 
 // Import the thread-local variable from Rayon, which is preserved for Rayon jobs.
-#[cfg(parallel_compiler)]
 use rayon_core::tlv::TLV;
 
-// Otherwise define our own
-#[cfg(not(parallel_compiler))]
-thread_local! {
-    /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
-    static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
-}
-
 #[inline]
 fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
     context as *const _ as *const ()
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 737f1362b34..fd84d75b53f 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -143,12 +143,10 @@ impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> {
     }
 }
 
-#[cfg(parallel_compiler)]
 unsafe impl<'tcx> rustc_data_structures::sync::DynSend for GenericArg<'tcx> where
     &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSend
 {
 }
-#[cfg(parallel_compiler)]
 unsafe impl<'tcx> rustc_data_structures::sync::DynSync for GenericArg<'tcx> where
     &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSync
 {
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 19779740227..ce40ab18261 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -86,10 +86,10 @@ impl GenericParamDef {
         tcx: TyCtxt<'tcx>,
     ) -> Option<EarlyBinder<'tcx, ty::GenericArg<'tcx>>> {
         match self.kind {
-            GenericParamDefKind::Type { has_default, .. } if has_default => {
+            GenericParamDefKind::Type { has_default: true, .. } => {
                 Some(tcx.type_of(self.def_id).map_bound(|t| t.into()))
             }
-            GenericParamDefKind::Const { has_default, .. } if has_default => {
+            GenericParamDefKind::Const { has_default: true, .. } => {
                 Some(tcx.const_param_default(self.def_id).map_bound(|c| c.into()))
             }
             _ => None,
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index ea07cd3a1b9..30a5586f59c 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -5,7 +5,6 @@ use std::ops::Deref;
 use std::{fmt, iter, mem, ptr, slice};
 
 use rustc_data_structures::aligned::{Aligned, align_of};
-#[cfg(parallel_compiler)]
 use rustc_data_structures::sync::DynSync;
 use rustc_serialize::{Encodable, Encoder};
 
@@ -259,7 +258,6 @@ impl<'a, H, T: Copy> IntoIterator for &'a RawList<H, T> {
 unsafe impl<H: Sync, T: Sync> Sync for RawList<H, T> {}
 
 // We need this since `List` uses extern type `OpaqueListContents`.
-#[cfg(parallel_compiler)]
 unsafe impl<H: DynSync, T: DynSync> DynSync for RawList<H, T> {}
 
 // Safety:
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 1a3128ed936..7fda0662a34 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -487,12 +487,10 @@ impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> {
     }
 }
 
-#[cfg(parallel_compiler)]
 unsafe impl<'tcx> rustc_data_structures::sync::DynSend for Term<'tcx> where
     &'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSend
 {
 }
-#[cfg(parallel_compiler)]
 unsafe impl<'tcx> rustc_data_structures::sync::DynSync for Term<'tcx> where
     &'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSync
 {
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 07964e304b9..62d173987fc 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -144,12 +144,20 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
         let mut targets = Vec::new();
         for arm in rest {
             let arm = &self.thir[*arm];
-            let PatKind::Constant { value } = arm.pattern.kind else {
-                return Err(ParseError {
-                    span: arm.pattern.span,
-                    item_description: format!("{:?}", arm.pattern.kind),
-                    expected: "constant pattern".to_string(),
-                });
+            let value = match arm.pattern.kind {
+                PatKind::Constant { value } => value,
+                PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false }
+                    if let PatKind::Constant { value } = subpattern.kind =>
+                {
+                    value
+                }
+                _ => {
+                    return Err(ParseError {
+                        span: arm.pattern.span,
+                        item_description: format!("{:?}", arm.pattern.kind),
+                        expected: "constant pattern".to_string(),
+                    });
+                }
             };
             values.push(value.eval_bits(self.tcx, self.param_env));
             targets.push(self.parse_block(arm.body)?);
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 6df50057ee8..6beabb5ccdb 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -162,7 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 TestCase::Irrefutable { ascription: None, binding }
             }
 
-            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
+            PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
+                subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
+                default_irrefutable()
+            }
+            PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
                 // Apply a type ascription for the inline constant to the value at `match_pair.place`
                 let ascription = place.map(|source| {
                     let span = pattern.span;
@@ -173,7 +177,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                     })
                     .args;
                     let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                        def.to_def_id(),
+                        def_id,
                         ty::UserArgs { args, user_self_ty: None },
                     ));
                     let annotation = ty::CanonicalUserTypeAnnotation {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index a62d4e9d873..9f81e1052d6 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -917,7 +917,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
             }
 
-            PatKind::InlineConstant { ref subpattern, .. } => {
+            PatKind::ExpandedConstant { ref subpattern, .. } => {
                 self.visit_primary_bindings(subpattern, pattern_user_ty, f)
             }
 
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index f3e6301d9d1..52e5f2950a5 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Wild |
                 // these just wrap other patterns, which we recurse on below.
                 PatKind::Or { .. } |
-                PatKind::InlineConstant { .. } |
+                PatKind::ExpandedConstant { .. } |
                 PatKind::AscribeUserType { .. } |
                 PatKind::Error(_) => {}
             }
@@ -386,8 +386,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 visit::walk_pat(self, pat);
                 self.inside_adt = old_inside_adt;
             }
-            PatKind::InlineConstant { def, .. } => {
-                self.visit_inner_body(*def);
+            PatKind::ExpandedConstant { def_id, is_inline, .. } => {
+                if let Some(def) = def_id.as_local()
+                    && *is_inline
+                {
+                    self.visit_inner_body(def);
+                }
                 visit::walk_pat(self, pat);
             }
             _ => {
@@ -1005,10 +1009,6 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
     // Runs all other queries that depend on THIR.
     tcx.ensure_with_value().mir_built(def);
     let thir = &thir.steal();
-    // If `thir` is empty, a type error occurred, skip this body.
-    if thir.exprs.is_empty() {
-        return;
-    }
 
     let hir_id = tcx.local_def_id_to_hir_id(def);
     let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 00f65e0c7d0..4443d9aebc6 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -860,8 +860,10 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
     pub(crate) uncovered: Uncovered,
     #[subdiagnostic]
     pub(crate) inform: Option<Inform>,
+    #[label(mir_build_confused)]
+    pub(crate) interpreted_as_const: Option<Span>,
     #[subdiagnostic]
-    pub(crate) interpreted_as_const: Option<InterpretedAsConst>,
+    pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConst>,
     #[subdiagnostic]
     pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>,
     #[note(mir_build_privately_uninhabited)]
@@ -911,9 +913,9 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
 #[suggestion(
     mir_build_interpreted_as_const,
     code = "{variable}_var",
-    applicability = "maybe-incorrect"
+    applicability = "maybe-incorrect",
+    style = "verbose"
 )]
-#[label(mir_build_confused)]
 pub(crate) struct InterpretedAsConst {
     #[primary_span]
     pub(crate) span: Span,
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 f222a869c03..4b872d9b7f7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -668,8 +668,25 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let mut let_suggestion = None;
         let mut misc_suggestion = None;
         let mut interpreted_as_const = None;
+        let mut interpreted_as_const_sugg = None;
 
-        if let PatKind::Constant { .. }
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. }
+        | PatKind::AscribeUserType {
+            subpattern:
+                box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. },
+            ..
+        } = pat.kind
+            && let DefKind::Const = self.tcx.def_kind(def_id)
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
+            // We filter out paths with multiple path::segments.
+            && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
+        {
+            let span = self.tcx.def_span(def_id);
+            let variable = self.tcx.item_name(def_id).to_string();
+            // When we encounter a constant as the binding name, point at the `const` definition.
+            interpreted_as_const = Some(span);
+            interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable });
+        } else if let PatKind::Constant { .. }
         | PatKind::AscribeUserType {
             subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
             ..
@@ -682,9 +699,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral {
                     start_span: pat.span.shrink_to_lo(),
                 });
-            } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') {
-                interpreted_as_const =
-                    Some(InterpretedAsConst { span: pat.span, variable: snippet });
             }
         }
 
@@ -733,6 +747,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             uncovered: Uncovered::new(pat.span, &cx, witnesses),
             inform,
             interpreted_as_const,
+            interpreted_as_const_sugg,
             witness_1_is_privately_uninhabited,
             _p: (),
             pattern_ty,
@@ -1102,13 +1117,13 @@ fn report_non_exhaustive_match<'p, 'tcx>(
             if ty.is_ptr_sized_integral() {
                 if ty.inner() == cx.tcx.types.usize {
                     err.note(format!(
-                        "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \
-                             exhaustively",
+                        "`{ty}` does not have a fixed maximum value, so half-open ranges are \
+                         necessary to match exhaustively",
                     ));
                 } else if ty.inner() == cx.tcx.types.isize {
                     err.note(format!(
-                        "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \
-                             exhaustively",
+                        "`{ty}` does not have fixed minimum and maximum values, so half-open \
+                         ranges are necessary to match exhaustively",
                     ));
                 }
             } else if ty.inner() == cx.tcx.types.str_ {
@@ -1129,6 +1144,31 @@ fn report_non_exhaustive_match<'p, 'tcx>(
         }
     }
 
+    for &arm in arms {
+        let arm = &thir.arms[arm];
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind
+            && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
+            // We filter out paths with multiple path::segments.
+            && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
+        {
+            let const_name = cx.tcx.item_name(def_id);
+            err.span_label(
+                arm.pattern.span,
+                format!(
+                    "this pattern doesn't introduce a new catch-all binding, but rather pattern \
+                     matches against the value of constant `{const_name}`",
+                ),
+            );
+            err.span_note(cx.tcx.def_span(def_id), format!("constant `{const_name}` defined here"));
+            err.span_suggestion_verbose(
+                arm.pattern.span.shrink_to_hi(),
+                "if you meant to introduce a binding, use a different name",
+                "_var".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     // Whether we suggest the actual missing patterns or `_`.
     let suggest_the_witnesses = witnesses.len() < 4;
     let suggested_arm = if suggest_the_witnesses {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 983853d2de1..82632350af5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,14 +1,13 @@
-use either::Either;
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_apfloat::Float;
 use rustc_hir as hir;
 use rustc_index::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree};
+use rustc_middle::{mir, span_bug};
 use rustc_span::Span;
 use rustc_trait_selection::traits::ObligationCause;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -40,7 +39,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // of opaques defined in this function here.
         let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let mut convert = ConstToPat::new(self, id, span, infcx);
-        convert.to_pat(c, ty)
+
+        match c.kind() {
+            ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
+            ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
+            _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
+        }
     }
 }
 
@@ -81,27 +85,42 @@ impl<'tcx> ConstToPat<'tcx> {
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
 
-    fn to_pat(&mut self, c: ty::Const<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
+    fn unevaluated_to_pat(
+        &mut self,
+        uv: ty::UnevaluatedConst<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
         let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind });
 
-        // Get a valtree. If that fails, this const is definitely not valid for use as a pattern.
-        let valtree = match c.eval_valtree(self.tcx(), self.param_env, self.span) {
-            Ok((_, valtree)) => valtree,
-            Err(Either::Right(e)) => {
-                let err = match e {
-                    ErrorHandled::Reported(..) => {
-                        // Let's tell the use where this failing const occurs.
-                        self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span })
-                    }
-                    ErrorHandled::TooGeneric(_) => self
-                        .tcx()
-                        .dcx()
-                        .emit_err(ConstPatternDependsOnGenericParameter { span: self.span }),
-                };
-                return pat_from_kind(PatKind::Error(err));
+        // It's not *technically* correct to be revealing opaque types here as borrowcheck has
+        // not run yet. However, CTFE itself uses `Reveal::All` unconditionally even during
+        // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a
+        // result we always use a revealed env when resolving the instance to evaluate.
+        //
+        // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
+        // instead of having this logic here
+        let param_env =
+            self.tcx().erase_regions(self.param_env).with_reveal_all_normalized(self.tcx());
+        let uv = self.tcx().erase_regions(uv);
+
+        // try to resolve e.g. associated constants to their definition on an impl, and then
+        // evaluate the const.
+        let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(param_env, uv, self.span) {
+            Ok(Ok(c)) => c,
+            Err(ErrorHandled::Reported(_, _)) => {
+                // Let's tell the use where this failing const occurs.
+                let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
+                return pat_from_kind(PatKind::Error(e));
             }
-            Err(Either::Left(bad_ty)) => {
+            Err(ErrorHandled::TooGeneric(_)) => {
+                let e = self
+                    .tcx()
+                    .dcx()
+                    .emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
+                return pat_from_kind(PatKind::Error(e));
+            }
+            Ok(Err(bad_ty)) => {
                 // The pattern cannot be turned into a valtree.
                 let e = match bad_ty.kind() {
                     ty::Adt(def, ..) => {
@@ -128,8 +147,7 @@ impl<'tcx> ConstToPat<'tcx> {
             if !self.type_has_partial_eq_impl(ty) {
                 let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
                 let e = self.tcx().dcx().emit_err(err);
-                let kind = PatKind::Error(e);
-                return Box::new(Pat { span: self.span, ty, kind });
+                return pat_from_kind(PatKind::Error(e));
             }
         }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index ec852add94d..9b63d788194 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -149,21 +149,30 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             None => Ok((None, None, None)),
             Some(expr) => {
                 let (kind, ascr, inline_const) = match self.lower_lit(expr) {
-                    PatKind::InlineConstant { subpattern, def } => {
-                        (subpattern.kind, None, Some(def))
+                    PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
+                        (subpattern.kind, None, def_id.as_local())
+                    }
+                    PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
+                        (subpattern.kind, None, None)
                     }
                     PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
                         (kind, Some(ascription), None)
                     }
                     kind => (kind, None, None),
                 };
-                let value = if let PatKind::Constant { value } = kind {
-                    value
-                } else {
-                    let msg = format!(
-                        "found bad range pattern endpoint `{expr:?}` outside of error recovery"
-                    );
-                    return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+                let value = match kind {
+                    PatKind::Constant { value } => value,
+                    PatKind::ExpandedConstant { subpattern, .. }
+                        if let PatKind::Constant { value } = subpattern.kind =>
+                    {
+                        value
+                    }
+                    _ => {
+                        let msg = format!(
+                            "found bad range pattern endpoint `{expr:?}` outside of error recovery"
+                        );
+                        return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+                    }
                 };
                 Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
             }
@@ -288,7 +297,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             };
         }
         for def in [lo_inline, hi_inline].into_iter().flatten() {
-            kind = PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) };
+            kind = PatKind::ExpandedConstant {
+                def_id: def.to_def_id(),
+                is_inline: true,
+                subpattern: Box::new(Pat { span, ty, kind }),
+            };
         }
         Ok(kind)
     }
@@ -562,7 +575,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let args = self.typeck_results.node_args(id);
         let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
-        let pattern = self.const_to_pat(c, ty, id, span);
+        let subpattern = self.const_to_pat(c, ty, id, span);
+        let pattern = Box::new(Pat {
+            span,
+            ty,
+            kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
+        });
 
         if !is_associated_const {
             return pattern;
@@ -637,7 +655,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
         let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
-        PatKind::InlineConstant { subpattern, def: def_id }
+        PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
     }
 
     /// Converts literals, paths and negation of literals to patterns.
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index dae13df4054..6be0ed5fb31 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -707,9 +707,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            PatKind::InlineConstant { def, subpattern } => {
-                print_indented!(self, "InlineConstant {", depth_lvl + 1);
-                print_indented!(self, format!("def: {:?}", def), depth_lvl + 2);
+            PatKind::ExpandedConstant { def_id, is_inline, subpattern } => {
+                print_indented!(self, "ExpandedConstant {", depth_lvl + 1);
+                print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2);
+                print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2);
                 print_indented!(self, "subpattern:", depth_lvl + 2);
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
index c8992b8b834..9bbfae17fd9 100644
--- a/compiler/rustc_mir_transform/messages.ftl
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -34,3 +34,5 @@ mir_transform_undefined_transmute = pointers cannot be transmuted to integers du
     .note = at compile-time, pointers do not have an integer value
     .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
     .help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
+
+mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 2e4c503f3ce..e8b3d80be02 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -22,8 +22,8 @@ use rustc_middle::mir::{
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
-use tracing::{debug, debug_span, instrument, trace};
+use rustc_span::{BytePos, Pos, SourceFile, Span};
+use tracing::{debug, debug_span, trace};
 
 use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
 use crate::coverage::graph::CoverageGraph;
@@ -122,6 +122,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
 
     mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
         function_source_hash: hir_info.function_source_hash,
+        body_span: hir_info.body_span,
         num_counters: coverage_counters.num_counters(),
         mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits,
         expressions: coverage_counters.into_expressions(),
@@ -142,19 +143,11 @@ fn create_mappings<'tcx>(
     coverage_counters: &CoverageCounters,
 ) -> Vec<Mapping> {
     let source_map = tcx.sess.source_map();
-    let body_span = hir_info.body_span;
-
-    let source_file = source_map.lookup_source_file(body_span.lo());
-
-    use rustc_session::RemapFileNameExt;
-    use rustc_session::config::RemapPathScopeComponents;
-    let file_name = Symbol::intern(
-        &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
-    );
+    let file = source_map.lookup_source_file(hir_info.body_span.lo());
 
     let term_for_bcb =
         |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters");
-    let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span);
+    let region_for_span = |span: Span| make_source_region(source_map, hir_info, &file, span);
 
     // Fully destructure the mappings struct to make sure we don't miss any kinds.
     let ExtractedMappings {
@@ -398,7 +391,42 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
     data.statements.insert(0, statement);
 }
 
-/// Convert the Span into its file name, start line and column, and end line and column.
+fn ensure_non_empty_span(
+    source_map: &SourceMap,
+    hir_info: &ExtractedHirInfo,
+    span: Span,
+) -> Option<Span> {
+    if !span.is_empty() {
+        return Some(span);
+    }
+
+    let lo = span.lo();
+    let hi = span.hi();
+
+    // The span is empty, so try to expand it to cover an adjacent '{' or '}',
+    // but only within the bounds of the body span.
+    let try_next = hi < hir_info.body_span.hi();
+    let try_prev = hir_info.body_span.lo() < lo;
+    if !(try_next || try_prev) {
+        return None;
+    }
+
+    source_map
+        .span_to_source(span, |src, start, end| try {
+            // We're only checking for specific ASCII characters, so we don't
+            // have to worry about multi-byte code points.
+            if try_next && src.as_bytes()[end] == b'{' {
+                Some(span.with_hi(hi + BytePos(1)))
+            } else if try_prev && src.as_bytes()[start - 1] == b'}' {
+                Some(span.with_lo(lo - BytePos(1)))
+            } else {
+                None
+            }
+        })
+        .ok()?
+}
+
+/// Converts the span into its start line and column, and end line and column.
 ///
 /// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
 /// the compiler, these column numbers are denoted in **bytes**, because that's what
@@ -408,56 +436,29 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
 /// but it's hard to rule out entirely (especially in the presence of complex macros
 /// or other expansions), and if it does happen then skipping a span or function is
 /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
-#[instrument(level = "debug", skip(source_map))]
 fn make_source_region(
     source_map: &SourceMap,
-    file_name: Symbol,
+    hir_info: &ExtractedHirInfo,
+    file: &SourceFile,
     span: Span,
-    body_span: Span,
 ) -> Option<SourceRegion> {
+    let span = ensure_non_empty_span(source_map, hir_info, span)?;
+
     let lo = span.lo();
     let hi = span.hi();
 
-    let file = source_map.lookup_source_file(lo);
-    if !file.contains(hi) {
-        debug!(?span, ?file, ?lo, ?hi, "span crosses multiple files; skipping");
-        return None;
-    }
-
     // Column numbers need to be in bytes, so we can't use the more convenient
     // `SourceMap` methods for looking up file coordinates.
-    let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> {
+    let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> {
         let rpos = file.relative_position(pos);
         let line_index = file.lookup_line(rpos)?;
         let line_start = file.lines()[line_index];
         // Line numbers and column numbers are 1-based, so add 1 to each.
-        Some((rpos, line_index + 1, (rpos - line_start).to_usize() + 1))
+        Some((line_index + 1, (rpos - line_start).to_usize() + 1))
     };
 
-    let (lo_rpos, mut start_line, mut start_col) = rpos_and_line_and_byte_column(lo)?;
-    let (hi_rpos, mut end_line, mut end_col) = rpos_and_line_and_byte_column(hi)?;
-
-    // If the span is empty, try to expand it horizontally by one character's
-    // worth of bytes, so that it is more visible in `llvm-cov` reports.
-    // We do this after resolving line/column numbers, so that empty spans at the
-    // end of a line get an extra column instead of wrapping to the next line.
-    if span.is_empty()
-        && body_span.contains(span)
-        && let Some(src) = &file.src
-    {
-        // Prefer to expand the end position, if it won't go outside the body span.
-        if hi < body_span.hi() {
-            let hi_rpos = hi_rpos.to_usize();
-            let nudge_bytes = src.ceil_char_boundary(hi_rpos + 1) - hi_rpos;
-            end_col += nudge_bytes;
-        } else if lo > body_span.lo() {
-            let lo_rpos = lo_rpos.to_usize();
-            let nudge_bytes = lo_rpos - src.floor_char_boundary(lo_rpos - 1);
-            // Subtract the nudge, but don't go below column 1.
-            start_col = start_col.saturating_sub(nudge_bytes).max(1);
-        }
-        // If neither nudge could be applied, stick with the empty span coordinates.
-    }
+    let (mut start_line, start_col) = line_and_byte_column(lo)?;
+    let (mut end_line, end_col) = line_and_byte_column(hi)?;
 
     // Apply an offset so that code in doctests has correct line numbers.
     // FIXME(#79417): Currently we have no way to offset doctest _columns_.
@@ -465,7 +466,6 @@ fn make_source_region(
     end_line = source_map.doctest_offset_line(&file.name, end_line);
 
     check_source_region(SourceRegion {
-        file_name,
         start_line: start_line as u32,
         start_col: start_col as u32,
         end_line: end_line as u32,
@@ -478,7 +478,7 @@ fn make_source_region(
 /// discard regions that are improperly ordered, or might be interpreted in a
 /// way that makes them improperly ordered.
 fn check_source_region(source_region: SourceRegion) -> Option<SourceRegion> {
-    let SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = source_region;
+    let SourceRegion { start_line, start_col, end_line, end_col } = source_region;
 
     // Line/column coordinates are supposed to be 1-based. If we ever emit
     // coordinates of 0, `llvm-cov` might misinterpret them.
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index 42cbece32d8..589be81558c 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -50,6 +50,16 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
         _ => {}
     }
 
+    let sig = tcx.fn_sig(def_id).instantiate_identity();
+    for ty in sig.inputs().skip_binder().iter().chain(std::iter::once(&sig.output().skip_binder()))
+    {
+        // FIXME(f16_f128): in order to avoid crashes building `core`, always inline to skip
+        // codegen if the function is not used.
+        if ty == &tcx.types.f16 || ty == &tcx.types.f128 {
+            return true;
+        }
+    }
+
     // Don't do any inference when incremental compilation is enabled; the additional inlining that
     // inference permits also creates more work for small edits.
     if tcx.sess.opts.incremental.is_some() {
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 8b309147c64..2d9eeddea2e 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -38,6 +38,12 @@ pub(crate) struct UnalignedPackedRef {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(mir_transform_unknown_pass_name)]
+pub(crate) struct UnknownPassName<'a> {
+    pub(crate) name: &'a str,
+}
+
 pub(crate) struct AssertLint<P> {
     pub span: Span,
     pub assert_kind: AssertKind<P>,
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index d184328748f..d2d5facbbdc 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -9,7 +9,6 @@
 #![feature(let_chains)]
 #![feature(map_try_insert)]
 #![feature(never_type)]
-#![feature(round_char_boundary)]
 #![feature(try_blocks)]
 #![feature(yeet_expr)]
 #![warn(unreachable_pub)]
@@ -41,77 +40,158 @@ use tracing::{debug, trace};
 #[macro_use]
 mod pass_manager;
 
+use std::sync::LazyLock;
+
 use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};
 
-mod abort_unwinding_calls;
-mod add_call_guards;
-mod add_moves_for_packed_drops;
-mod add_retag;
-mod add_subtyping_projections;
-mod check_alignment;
-mod check_const_item_mutation;
-mod check_packed_ref;
-mod check_undefined_transmutes;
-// This pass is public to allow external drivers to perform MIR cleanup
-pub mod cleanup_post_borrowck;
-mod copy_prop;
-mod coroutine;
 mod cost_checker;
-mod coverage;
 mod cross_crate_inline;
-mod ctfe_limit;
-mod dataflow_const_prop;
-mod dead_store_elimination;
 mod deduce_param_attrs;
-mod deduplicate_blocks;
-mod deref_separator;
-mod dest_prop;
-pub mod dump_mir;
-mod early_otherwise_branch;
-mod elaborate_box_derefs;
-mod elaborate_drops;
 mod errors;
 mod ffi_unwind_calls;
-mod function_item_references;
-mod gvn;
-// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
-// by custom rustc drivers, running all the steps by themselves. See #114628.
-pub mod inline;
-mod instsimplify;
-mod jump_threading;
-mod known_panics_lint;
-mod large_enums;
 mod lint;
-mod lower_intrinsics;
-mod lower_slice_len;
-mod match_branches;
-mod mentioned_items;
-mod multiple_return_terminators;
-mod nrvo;
-mod post_drop_elaboration;
-mod prettify;
-mod promote_consts;
-mod ref_prop;
-mod remove_noop_landing_pads;
-mod remove_place_mention;
-mod remove_storage_markers;
-mod remove_uninit_drops;
-mod remove_unneeded_drops;
-mod remove_zsts;
-mod required_consts;
-mod reveal_all;
-mod sanity_check;
 mod shim;
 mod ssa;
-// This pass is public to allow external drivers to perform MIR cleanup
-pub mod simplify;
-mod simplify_branches;
-mod simplify_comparison_integral;
-mod single_use_consts;
-mod sroa;
-mod unreachable_enum_branching;
-mod unreachable_prop;
-mod validate;
+
+/// We import passes via this macro so that we can have a static list of pass names
+/// (used to verify CLI arguments). It takes a list of modules, followed by the passes
+/// declared within them.
+/// ```ignore,macro-test
+/// declare_passes! {
+///     // Declare a single pass from the module `abort_unwinding_calls`
+///     mod abort_unwinding_calls : AbortUnwindingCalls;
+///     // When passes are grouped together as an enum, declare the two constituent passes
+///     mod add_call_guards : AddCallGuards {
+///         AllCallEdges,
+///         CriticalCallEdges
+///     };
+///     // Declares multiple pass groups, each containing their own constituent passes
+///     mod simplify : SimplifyCfg {
+///         Initial,
+///         /* omitted */
+///     }, SimplifyLocals {
+///         BeforeConstProp,
+///         /* omitted */
+///     };
+/// }
+/// ```
+macro_rules! declare_passes {
+    (
+        $(
+            $vis:vis mod $mod_name:ident : $($pass_name:ident $( { $($ident:ident),* } )?),+ $(,)?;
+        )*
+    ) => {
+        $(
+            $vis mod $mod_name;
+            $(
+                // Make sure the type name is correct
+                #[allow(unused_imports)]
+                use $mod_name::$pass_name as _;
+            )+
+        )*
+
+        static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| [
+            // Fake marker pass
+            "PreCodegen",
+            $(
+                $(
+                    stringify!($pass_name),
+                    $(
+                        $(
+                            $mod_name::$pass_name::$ident.name(),
+                        )*
+                    )?
+                )+
+            )*
+        ].into_iter().collect());
+    };
+}
+
+declare_passes! {
+    mod abort_unwinding_calls : AbortUnwindingCalls;
+    mod add_call_guards : AddCallGuards { AllCallEdges, CriticalCallEdges };
+    mod add_moves_for_packed_drops : AddMovesForPackedDrops;
+    mod add_retag : AddRetag;
+    mod add_subtyping_projections : Subtyper;
+    mod check_alignment : CheckAlignment;
+    mod check_const_item_mutation : CheckConstItemMutation;
+    mod check_packed_ref : CheckPackedRef;
+    mod check_undefined_transmutes : CheckUndefinedTransmutes;
+    // This pass is public to allow external drivers to perform MIR cleanup
+    pub mod cleanup_post_borrowck : CleanupPostBorrowck;
+
+    mod copy_prop : CopyProp;
+    mod coroutine : StateTransform;
+    mod coverage : InstrumentCoverage;
+    mod ctfe_limit : CtfeLimit;
+    mod dataflow_const_prop : DataflowConstProp;
+    mod dead_store_elimination : DeadStoreElimination {
+        Initial,
+        Final
+    };
+    mod deduplicate_blocks : DeduplicateBlocks;
+    mod deref_separator : Derefer;
+    mod dest_prop : DestinationPropagation;
+    pub mod dump_mir : Marker;
+    mod early_otherwise_branch : EarlyOtherwiseBranch;
+    mod elaborate_box_derefs : ElaborateBoxDerefs;
+    mod elaborate_drops : ElaborateDrops;
+    mod function_item_references : FunctionItemReferences;
+    mod gvn : GVN;
+    // Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
+    // by custom rustc drivers, running all the steps by themselves. See #114628.
+    pub mod inline : Inline;
+    mod instsimplify : InstSimplify { BeforeInline, AfterSimplifyCfg };
+    mod jump_threading : JumpThreading;
+    mod known_panics_lint : KnownPanicsLint;
+    mod large_enums : EnumSizeOpt;
+    mod lower_intrinsics : LowerIntrinsics;
+    mod lower_slice_len : LowerSliceLenCalls;
+    mod match_branches : MatchBranchSimplification;
+    mod mentioned_items : MentionedItems;
+    mod multiple_return_terminators : MultipleReturnTerminators;
+    mod nrvo : RenameReturnPlace;
+    mod post_drop_elaboration : CheckLiveDrops;
+    mod prettify : ReorderBasicBlocks, ReorderLocals;
+    mod promote_consts : PromoteTemps;
+    mod ref_prop : ReferencePropagation;
+    mod remove_noop_landing_pads : RemoveNoopLandingPads;
+    mod remove_place_mention : RemovePlaceMention;
+    mod remove_storage_markers : RemoveStorageMarkers;
+    mod remove_uninit_drops : RemoveUninitDrops;
+    mod remove_unneeded_drops : RemoveUnneededDrops;
+    mod remove_zsts : RemoveZsts;
+    mod required_consts : RequiredConstsVisitor;
+    mod reveal_all : RevealAll;
+    mod sanity_check : SanityCheck;
+    // This pass is public to allow external drivers to perform MIR cleanup
+    pub mod simplify :
+        SimplifyCfg {
+            Initial,
+            PromoteConsts,
+            RemoveFalseEdges,
+            PostAnalysis,
+            PreOptimizations,
+            Final,
+            MakeShim,
+            AfterUnreachableEnumBranching
+        },
+        SimplifyLocals {
+            BeforeConstProp,
+            AfterGVN,
+            Final
+        };
+    mod simplify_branches : SimplifyConstCondition {
+        AfterConstProp,
+        Final
+    };
+    mod simplify_comparison_integral : SimplifyComparisonIntegral;
+    mod single_use_consts : SingleUseConsts;
+    mod sroa : ScalarReplacementOfAggregates;
+    mod unreachable_enum_branching : UnreachableEnumBranching;
+    mod unreachable_prop : UnreachablePropagation;
+    mod validate : Validator;
+}
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 29f8b4f6e4d..779e7f22101 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -1,24 +1,25 @@
 use std::cell::RefCell;
 use std::collections::hash_map::Entry;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use tracing::trace;
 
 use crate::lint::lint_body;
-use crate::validate;
+use crate::{errors, validate};
 
 thread_local! {
-    static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
+    /// Maps MIR pass names to a snake case form to match profiling naming style
+    static PASS_TO_PROFILER_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
         RefCell::new(FxHashMap::default())
     };
 }
 
 /// Converts a MIR pass name into a snake case form to match the profiling naming style.
 fn to_profiler_name(type_name: &'static str) -> &'static str {
-    PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
+    PASS_TO_PROFILER_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
         Entry::Occupied(e) => *e.get(),
         Entry::Vacant(e) => {
             let snake_case: String = type_name
@@ -198,6 +199,31 @@ fn run_passes_inner<'tcx>(
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     trace!(?overridden_passes);
 
+    let named_passes: FxIndexSet<_> =
+        overridden_passes.iter().map(|(name, _)| name.as_str()).collect();
+
+    for &name in named_passes.difference(&*crate::PASS_NAMES) {
+        tcx.dcx().emit_warn(errors::UnknownPassName { name });
+    }
+
+    // Verify that no passes are missing from the `declare_passes` invocation
+    #[cfg(debug_assertions)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[allow(rustc::untranslatable_diagnostic)]
+    {
+        let used_passes: FxIndexSet<_> = passes.iter().map(|p| p.name()).collect();
+
+        let undeclared = used_passes.difference(&*crate::PASS_NAMES).collect::<Vec<_>>();
+        if let Some((name, rest)) = undeclared.split_first() {
+            let mut err =
+                tcx.dcx().struct_bug(format!("pass `{name}` is not declared in `PASS_NAMES`"));
+            for name in rest {
+                err.note(format!("pass `{name}` is also not declared in `PASS_NAMES`"));
+            }
+            err.emit();
+        }
+    }
+
     let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id()));
 
     if !body.should_skip() {
diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl
index 6da387bbebc..8528a2e68c0 100644
--- a/compiler/rustc_monomorphize/messages.ftl
+++ b/compiler/rustc_monomorphize/messages.ftl
@@ -1,12 +1,19 @@
 monomorphize_abi_error_disabled_vector_type_call =
-  ABI error: this function call uses a vector type that requires the `{$required_feature}` target feature, which is not enabled in the caller
+  this function call uses a SIMD vector type that (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled in the caller
   .label = function called here
   .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`)
 monomorphize_abi_error_disabled_vector_type_def =
-  ABI error: this function definition uses a vector type that requires the `{$required_feature}` target feature, which is not enabled
+  this function definition uses a SIMD vector type that (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled
   .label = function defined here
   .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`)
 
+monomorphize_abi_error_unsupported_vector_type_call =
+  this function call uses a SIMD vector type that is not currently supported with the chosen ABI
+  .label = function called here
+monomorphize_abi_error_unsupported_vector_type_def =
+  this function definition uses a SIMD vector type that is not currently supported with the chosen ABI
+  .label = function defined here
+
 monomorphize_couldnt_dump_mono_stats =
     unexpected error occurred while dumping monomorphization stats: {$error}
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 85151e5f093..429e31b2c88 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -205,13 +205,8 @@
 //! this is not implemented however: a mono item will be produced
 //! regardless of whether it is actually needed or not.
 
-mod abi_check;
-mod move_check;
-
 use std::path::PathBuf;
 
-use move_check::MoveCheckState;
-use rustc_abi::Size;
 use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir as hir;
@@ -228,15 +223,15 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    self, AssocKind, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt,
-    TypeFoldable, TypeVisitableExt, VtblEntry,
+    self, GenericArgs, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable,
+    TypeVisitableExt, VtblEntry,
 };
 use rustc_middle::util::Providers;
 use rustc_middle::{bug, span_bug};
 use rustc_session::Limit;
 use rustc_session::config::EntryFnType;
 use rustc_span::source_map::{Spanned, dummy_spanned, respan};
-use rustc_span::symbol::{Ident, sym};
+use rustc_span::symbol::sym;
 use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument, trace};
 
@@ -612,8 +607,6 @@ struct MirUsedCollector<'a, 'tcx> {
     /// Note that this contains *not-monomorphized* items!
     used_mentioned_items: &'a mut UnordSet<MentionedItem<'tcx>>,
     instance: Instance<'tcx>,
-    visiting_call_terminator: bool,
-    move_check: move_check::MoveCheckState,
 }
 
 impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
@@ -760,13 +753,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         };
 
         match terminator.kind {
-            mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. }
-            | mir::TerminatorKind::TailCall { ref func, ref args, ref fn_span } => {
+            mir::TerminatorKind::Call { ref func, .. }
+            | mir::TerminatorKind::TailCall { ref func, .. } => {
                 let callee_ty = func.ty(self.body, tcx);
                 // *Before* monomorphizing, record that we already handled this mention.
                 self.used_mentioned_items.insert(MentionedItem::Fn(callee_ty));
                 let callee_ty = self.monomorphize(callee_ty);
-                self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
                 visit_fn_use(self.tcx, callee_ty, true, source, &mut self.used_items)
             }
             mir::TerminatorKind::Drop { ref place, .. } => {
@@ -826,14 +818,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
             push_mono_lang_item(self, reason.lang_item());
         }
 
-        self.visiting_call_terminator = matches!(terminator.kind, mir::TerminatorKind::Call { .. });
         self.super_terminator(terminator, location);
-        self.visiting_call_terminator = false;
-    }
-
-    fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
-        self.super_operand(operand, location);
-        self.check_operand_move_size(operand, location);
     }
 }
 
@@ -1183,20 +1168,6 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt
     }
 }
 
-fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> {
-    for impl_def_id in tcx.inherent_impls(def_id) {
-        if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
-            tcx,
-            fn_ident,
-            AssocKind::Fn,
-            def_id,
-        ) {
-            return Some(new.def_id);
-        }
-    }
-    None
-}
-
 /// Scans the MIR in order to find function calls, closures, and drop-glue.
 ///
 /// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
@@ -1208,7 +1179,8 @@ fn collect_items_of_instance<'tcx>(
     mentioned_items: &mut MonoItems<'tcx>,
     mode: CollectionMode,
 ) {
-    tcx.ensure().check_feature_dependent_abi(instance);
+    // This item is getting monomorphized, do mono-time checks.
+    tcx.ensure().check_mono_item(instance);
 
     let body = tcx.instance_mir(instance.def);
     // Naively, in "used" collection mode, all functions get added to *both* `used_items` and
@@ -1228,8 +1200,6 @@ fn collect_items_of_instance<'tcx>(
         used_items,
         used_mentioned_items: &mut used_mentioned_items,
         instance,
-        visiting_call_terminator: false,
-        move_check: MoveCheckState::new(),
     };
 
     if mode == CollectionMode::UsedItems {
@@ -1626,5 +1596,4 @@ pub(crate) fn collect_crate_mono_items<'tcx>(
 
 pub(crate) fn provide(providers: &mut Providers) {
     providers.hooks.should_codegen_locally = should_codegen_locally;
-    abi_check::provide(providers);
 }
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index 5048a8d5d99..02865cad302 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -110,3 +110,17 @@ pub(crate) struct AbiErrorDisabledVectorTypeCall<'a> {
     pub span: Span,
     pub required_feature: &'a str,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(monomorphize_abi_error_unsupported_vector_type_def)]
+pub(crate) struct AbiErrorUnsupportedVectorTypeDef {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(monomorphize_abi_error_unsupported_vector_type_call)]
+pub(crate) struct AbiErrorUnsupportedVectorTypeCall {
+    #[label]
+    pub span: Span,
+}
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index e92e6978d0f..0cfc4371db5 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -16,6 +16,7 @@ use rustc_span::ErrorGuaranteed;
 
 mod collector;
 mod errors;
+mod mono_checks;
 mod partitioning;
 mod polymorphize;
 mod util;
@@ -47,4 +48,5 @@ fn custom_coerce_unsize_info<'tcx>(
 pub fn provide(providers: &mut Providers) {
     partitioning::provide(providers);
     polymorphize::provide(providers);
+    mono_checks::provide(providers);
 }
diff --git a/compiler/rustc_monomorphize/src/collector/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
index f1c57f1e997..d53595929e7 100644
--- a/compiler/rustc_monomorphize/src/collector/abi_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -1,9 +1,7 @@
 //! This module ensures that if a function's ABI requires a particular target feature,
 //! that target feature is enabled both on the callee and all callers.
 use rustc_hir::CRATE_HIR_ID;
-use rustc_middle::mir::visit::Visitor as MirVisitor;
-use rustc_middle::mir::{self, Location, traversal};
-use rustc_middle::query::Providers;
+use rustc_middle::mir::{self, traversal};
 use rustc_middle::ty::inherent::*;
 use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt};
 use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES;
@@ -12,7 +10,10 @@ use rustc_span::{DUMMY_SP, Span, Symbol};
 use rustc_target::abi::call::{FnAbi, PassMode};
 use rustc_target::abi::{BackendRepr, RegKind};
 
-use crate::errors::{AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef};
+use crate::errors::{
+    AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef,
+    AbiErrorUnsupportedVectorTypeCall, AbiErrorUnsupportedVectorTypeDef,
+};
 
 fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
     match mode {
@@ -25,11 +26,15 @@ fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
     }
 }
 
+/// Checks whether a certain function ABI is compatible with the target features currently enabled
+/// for a certain function.
+/// If not, `emit_err` is called, with `Some(feature)` if a certain feature should be enabled and
+/// with `None` if no feature is known that would make the ABI compatible.
 fn do_check_abi<'tcx>(
     tcx: TyCtxt<'tcx>,
     abi: &FnAbi<'tcx, Ty<'tcx>>,
     target_feature_def: DefId,
-    mut emit_err: impl FnMut(&'static str),
+    mut emit_err: impl FnMut(Option<&'static str>),
 ) {
     let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else {
         return;
@@ -42,7 +47,7 @@ fn do_check_abi<'tcx>(
             let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
                 Some((_, feature)) => feature,
                 None => {
-                    emit_err("<no available feature for this size>");
+                    emit_err(None);
                     continue;
                 }
             };
@@ -50,7 +55,7 @@ fn do_check_abi<'tcx>(
             if !tcx.sess.unstable_target_features.contains(&feature_sym)
                 && !codegen_attrs.target_features.iter().any(|x| x.name == feature_sym)
             {
-                emit_err(feature);
+                emit_err(Some(&feature));
             }
         }
     }
@@ -67,12 +72,21 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
     };
     do_check_abi(tcx, abi, instance.def_id(), |required_feature| {
         let span = tcx.def_span(instance.def_id());
-        tcx.emit_node_span_lint(
-            ABI_UNSUPPORTED_VECTOR_TYPES,
-            CRATE_HIR_ID,
-            span,
-            AbiErrorDisabledVectorTypeDef { span, required_feature },
-        );
+        if let Some(required_feature) = required_feature {
+            tcx.emit_node_span_lint(
+                ABI_UNSUPPORTED_VECTOR_TYPES,
+                CRATE_HIR_ID,
+                span,
+                AbiErrorDisabledVectorTypeDef { span, required_feature },
+            );
+        } else {
+            tcx.emit_node_span_lint(
+                ABI_UNSUPPORTED_VECTOR_TYPES,
+                CRATE_HIR_ID,
+                span,
+                AbiErrorUnsupportedVectorTypeDef { span },
+            );
+        }
     })
 }
 
@@ -111,52 +125,49 @@ fn check_call_site_abi<'tcx>(
         return;
     };
     do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| {
-        tcx.emit_node_span_lint(
-            ABI_UNSUPPORTED_VECTOR_TYPES,
-            CRATE_HIR_ID,
-            span,
-            AbiErrorDisabledVectorTypeCall { span, required_feature },
-        );
+        if let Some(required_feature) = required_feature {
+            tcx.emit_node_span_lint(
+                ABI_UNSUPPORTED_VECTOR_TYPES,
+                CRATE_HIR_ID,
+                span,
+                AbiErrorDisabledVectorTypeCall { span, required_feature },
+            );
+        } else {
+            tcx.emit_node_span_lint(
+                ABI_UNSUPPORTED_VECTOR_TYPES,
+                CRATE_HIR_ID,
+                span,
+                AbiErrorUnsupportedVectorTypeCall { span },
+            );
+        }
     });
 }
 
-struct MirCallesAbiCheck<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a mir::Body<'tcx>,
-    instance: Instance<'tcx>,
-}
-
-impl<'a, 'tcx> MirVisitor<'tcx> for MirCallesAbiCheck<'a, 'tcx> {
-    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, _: Location) {
+fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
+    // Check all function call terminators.
+    for (bb, _data) in traversal::mono_reachable(body, tcx, instance) {
+        let terminator = body.basic_blocks[bb].terminator();
         match terminator.kind {
             mir::TerminatorKind::Call { ref func, ref fn_span, .. }
             | mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
-                let callee_ty = func.ty(self.body, self.tcx);
-                let callee_ty = self.instance.instantiate_mir_and_normalize_erasing_regions(
-                    self.tcx,
+                let callee_ty = func.ty(body, tcx);
+                let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
+                    tcx,
                     ty::ParamEnv::reveal_all(),
                     ty::EarlyBinder::bind(callee_ty),
                 );
-                check_call_site_abi(self.tcx, callee_ty, *fn_span, self.body.source.instance);
+                check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance);
             }
             _ => {}
         }
     }
 }
 
-fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
-    let body = tcx.instance_mir(instance.def);
-    let mut visitor = MirCallesAbiCheck { tcx, body, instance };
-    for (bb, data) in traversal::mono_reachable(body, tcx, instance) {
-        visitor.visit_basic_block_data(bb, data)
-    }
-}
-
-fn check_feature_dependent_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
+pub(crate) fn check_feature_dependent_abi<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    body: &'tcx mir::Body<'tcx>,
+) {
     check_instance_abi(tcx, instance);
-    check_callees_abi(tcx, instance);
-}
-
-pub(super) fn provide(providers: &mut Providers) {
-    *providers = Providers { check_feature_dependent_abi, ..*providers }
+    check_callees_abi(tcx, instance, body);
 }
diff --git a/compiler/rustc_monomorphize/src/mono_checks/mod.rs b/compiler/rustc_monomorphize/src/mono_checks/mod.rs
new file mode 100644
index 00000000000..1ecda824fb8
--- /dev/null
+++ b/compiler/rustc_monomorphize/src/mono_checks/mod.rs
@@ -0,0 +1,23 @@
+//! This implements a single query, `check_mono_fn`, that gets fired for each
+//! monomorphization of all functions. This lets us implement monomorphization-time
+//! checks in a way that is friendly to incremental compilation.
+
+use rustc_middle::query::Providers;
+use rustc_middle::ty::{Instance, TyCtxt};
+
+mod abi_check;
+mod move_check;
+
+fn check_mono_item<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
+    let body = tcx.instance_mir(instance.def);
+    abi_check::check_feature_dependent_abi(tcx, instance, body);
+    move_check::check_moves(tcx, instance, body);
+}
+
+pub(super) fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        check_mono_item,
+        skip_move_check_fns: move_check::skip_move_check_fns,
+        ..*providers
+    }
+}
diff --git a/compiler/rustc_monomorphize/src/collector/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
index b86ef1e7373..7f04bdf46f1 100644
--- a/compiler/rustc_monomorphize/src/collector/move_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
@@ -1,38 +1,74 @@
+use rustc_abi::Size;
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir::def_id::DefId;
+use rustc_middle::mir::visit::Visitor as MirVisitor;
+use rustc_middle::mir::{self, Location, traversal};
+use rustc_middle::ty::{self, AssocKind, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_session::Limit;
 use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
-use tracing::debug;
+use rustc_span::Span;
+use rustc_span::source_map::Spanned;
+use rustc_span::symbol::{Ident, sym};
+use tracing::{debug, trace};
 
-use super::*;
 use crate::errors::LargeAssignmentsLint;
 
-pub(super) struct MoveCheckState {
+struct MoveCheckVisitor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    body: &'tcx mir::Body<'tcx>,
     /// Spans for move size lints already emitted. Helps avoid duplicate lints.
     move_size_spans: Vec<Span>,
-    /// Set of functions for which it is OK to move large data into.
-    skip_move_check_fns: Option<Vec<DefId>>,
 }
 
-impl MoveCheckState {
-    pub(super) fn new() -> Self {
-        MoveCheckState { move_size_spans: vec![], skip_move_check_fns: None }
+pub(crate) fn check_moves<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    body: &'tcx mir::Body<'tcx>,
+) {
+    let mut visitor = MoveCheckVisitor { tcx, instance, body, move_size_spans: vec![] };
+    for (bb, data) in traversal::mono_reachable(body, tcx, instance) {
+        visitor.visit_basic_block_data(bb, data)
     }
 }
 
-impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
-    pub(super) fn check_operand_move_size(
-        &mut self,
-        operand: &mir::Operand<'tcx>,
-        location: Location,
-    ) {
-        let limit = self.tcx.move_size_limit();
-        if limit.0 == 0 {
-            return;
+impl<'tcx> MirVisitor<'tcx> for MoveCheckVisitor<'tcx> {
+    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
+        match terminator.kind {
+            mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. }
+            | mir::TerminatorKind::TailCall { ref func, ref args, ref fn_span } => {
+                let callee_ty = func.ty(self.body, self.tcx);
+                let callee_ty = self.monomorphize(callee_ty);
+                self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
+            }
+            _ => {}
         }
 
-        // This function is called by visit_operand() which visits _all_
-        // operands, including TerminatorKind::Call operands. But if
-        // check_fn_args_move_size() has been called, the operands have already
-        // been visited. Do not visit them again.
-        if self.visiting_call_terminator {
+        // We deliberately do *not* visit the nested operands here, to avoid
+        // hitting `visit_operand` for function arguments.
+    }
+
+    fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
+        self.check_operand_move_size(operand, location);
+    }
+}
+
+impl<'tcx> MoveCheckVisitor<'tcx> {
+    fn monomorphize<T>(&self, value: T) -> T
+    where
+        T: TypeFoldable<TyCtxt<'tcx>>,
+    {
+        trace!("monomorphize: self.instance={:?}", self.instance);
+        self.instance.instantiate_mir_and_normalize_erasing_regions(
+            self.tcx,
+            ty::ParamEnv::reveal_all(),
+            ty::EarlyBinder::bind(value),
+        )
+    }
+
+    fn check_operand_move_size(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
+        let limit = self.tcx.move_size_limit();
+        if limit.0 == 0 {
             return;
         }
 
@@ -64,12 +100,7 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         let ty::FnDef(def_id, _) = *callee_ty.kind() else {
             return;
         };
-        if self
-            .move_check
-            .skip_move_check_fns
-            .get_or_insert_with(|| build_skip_move_check_fns(self.tcx))
-            .contains(&def_id)
-        {
+        if self.tcx.skip_move_check_fns(()).contains(&def_id) {
             return;
         }
 
@@ -116,14 +147,12 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         span: Span,
     ) {
         let source_info = self.body.source_info(location);
-        debug!(?source_info);
-        for reported_span in &self.move_check.move_size_spans {
+        for reported_span in &self.move_size_spans {
             if reported_span.overlaps(span) {
                 return;
             }
         }
         let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
-        debug!(?lint_root);
         let Some(lint_root) = lint_root else {
             // This happens when the issue is in a function from a foreign crate that
             // we monomorphized in the current crate. We can't get a `HirId` for things
@@ -137,11 +166,25 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
             size: too_large_size.bytes(),
             limit: limit as u64,
         });
-        self.move_check.move_size_spans.push(span);
+        self.move_size_spans.push(span);
+    }
+}
+
+fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> {
+    for impl_def_id in tcx.inherent_impls(def_id) {
+        if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
+            tcx,
+            fn_ident,
+            AssocKind::Fn,
+            def_id,
+        ) {
+            return Some(new.def_id);
+        }
     }
+    None
 }
 
-fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
+pub(crate) fn skip_move_check_fns(tcx: TyCtxt<'_>, _: ()) -> FxIndexSet<DefId> {
     let fns = [
         (tcx.lang_items().owned_box(), "new"),
         (tcx.get_diagnostic_item(sym::Rc), "new"),
@@ -151,5 +194,5 @@ fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
         .filter_map(|(def_id, fn_name)| {
             def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name)))
         })
-        .collect::<Vec<_>>()
+        .collect()
 }
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index f7fbfed5b8e..4ba54a2e0bf 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -29,10 +29,10 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size
     // FIXME: Uplift the leak check into this crate.
     fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>;
 
-    fn try_const_eval_resolve(
+    fn evaluate_const(
         &self,
         param_env: <Self::Interner as Interner>::ParamEnv,
-        unevaluated: ty::UnevaluatedConst<Self::Interner>,
+        uv: ty::UnevaluatedConst<Self::Interner>,
     ) -> Option<<Self::Interner as Interner>::Const>;
 
     // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`!
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 8685896715e..979a3794748 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -1001,12 +1001,12 @@ where
     // Try to evaluate a const, or return `None` if the const is too generic.
     // This doesn't mean the const isn't evaluatable, though, and should be treated
     // as an ambiguity rather than no-solution.
-    pub(super) fn try_const_eval_resolve(
+    pub(super) fn evaluate_const(
         &self,
         param_env: I::ParamEnv,
-        unevaluated: ty::UnevaluatedConst<I>,
+        uv: ty::UnevaluatedConst<I>,
     ) -> Option<I::Const> {
-        self.delegate.try_const_eval_resolve(param_env, unevaluated)
+        self.delegate.evaluate_const(param_env, uv)
     }
 
     pub(super) fn is_transmutable(
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 6793779b205..5c54656cc59 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -143,7 +143,7 @@ where
     ) -> QueryResult<I> {
         match ct.kind() {
             ty::ConstKind::Unevaluated(uv) => {
-                // We never return `NoSolution` here as `try_const_eval_resolve` emits an
+                // We never return `NoSolution` here as `evaluate_const` emits an
                 // error itself when failing to evaluate, so emitting an additional fulfillment
                 // error in that case is unnecessary noise. This may change in the future once
                 // evaluation failures are allowed to impact selection, e.g. generic const
@@ -151,7 +151,7 @@ where
 
                 // FIXME(generic_const_exprs): Implement handling for generic
                 // const expressions here.
-                if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv) {
+                if let Some(_normalized) = self.evaluate_const(param_env, uv) {
                     self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 } else {
                     self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs
index 5d5597429da..8ad0bf5cdf9 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs
@@ -14,7 +14,7 @@ where
         &mut self,
         goal: Goal<I, ty::NormalizesTo<I>>,
     ) -> QueryResult<I> {
-        if let Some(normalized_const) = self.try_const_eval_resolve(
+        if let Some(normalized_const) = self.evaluate_const(
             goal.param_env,
             ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
         ) {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 7f114013320..3546e5b0f04 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -683,7 +683,9 @@ impl<'a> Parser<'a> {
             })
         {
             self.bump();
-            self.dcx().emit_err(RemoveLet { span: lo });
+            // Trim extra space after the `let`
+            let span = lo.with_hi(self.token.span.lo());
+            self.dcx().emit_err(RemoveLet { span });
             lo = self.token.span;
         }
 
diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs
index 92684505ab0..decaecd2682 100644
--- a/compiler/rustc_parse/src/parser/tests.rs
+++ b/compiler/rustc_parse/src/parser/tests.rs
@@ -12,7 +12,7 @@ use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, Toke
 use rustc_ast::{self as ast, PatKind, visit};
 use rustc_ast_pretty::pprust::item_to_string;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::emitter::HumanEmitter;
+use rustc_errors::emitter::{HumanEmitter, OutputTheme};
 use rustc_errors::{DiagCtxt, MultiSpan, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
@@ -36,16 +36,17 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> {
     ))
 }
 
-fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
+fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
     let output = Arc::new(Mutex::new(Vec::new()));
     let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
     let fallback_bundle = rustc_errors::fallback_fluent_bundle(
         vec![crate::DEFAULT_LOCALE_RESOURCE, crate::DEFAULT_LOCALE_RESOURCE],
         false,
     );
-    let emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle)
+    let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle)
         .sm(Some(source_map.clone()))
         .diagnostic_width(Some(140));
+    emitter = emitter.theme(theme);
     let dcx = DiagCtxt::new(Box::new(emitter));
     (dcx, source_map, output)
 }
@@ -69,7 +70,7 @@ fn with_expected_parse_error<T, F>(source_str: &str, expected_output: &str, f: F
 where
     F: for<'a> FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
 {
-    let (handler, source_map, output) = create_test_handler();
+    let (handler, source_map, output) = create_test_handler(OutputTheme::Ascii);
     let psess = ParseSess::with_dcx(handler, source_map);
     let mut p = string_to_parser(&psess, source_str.to_string());
     let result = f(&mut p);
@@ -189,34 +190,55 @@ impl<T: Write> Write for Shared<T> {
 }
 
 #[allow(rustc::untranslatable_diagnostic)] // no translation needed for tests
-fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
+fn test_harness(
+    file_text: &str,
+    span_labels: Vec<SpanLabel>,
+    notes: Vec<(Option<(Position, Position)>, &'static str)>,
+    expected_output_ascii: &str,
+    expected_output_unicode: &str,
+) {
     create_default_session_globals_then(|| {
-        let (dcx, source_map, output) = create_test_handler();
-        source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
-
-        let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
-        let mut msp = MultiSpan::from_span(primary_span);
-        for span_label in span_labels {
-            let span = make_span(&file_text, &span_label.start, &span_label.end);
-            msp.push_span_label(span, span_label.label);
-            println!("span: {:?} label: {:?}", span, span_label.label);
-            println!("text: {:?}", source_map.span_to_snippet(span));
-        }
+        for (theme, expected_output) in [
+            (OutputTheme::Ascii, expected_output_ascii),
+            (OutputTheme::Unicode, expected_output_unicode),
+        ] {
+            let (dcx, source_map, output) = create_test_handler(theme);
+            source_map
+                .new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned());
+
+            let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
+            let mut msp = MultiSpan::from_span(primary_span);
+            for span_label in &span_labels {
+                let span = make_span(&file_text, &span_label.start, &span_label.end);
+                msp.push_span_label(span, span_label.label);
+                println!("span: {:?} label: {:?}", span, span_label.label);
+                println!("text: {:?}", source_map.span_to_snippet(span));
+            }
 
-        dcx.handle().span_err(msp, "foo");
+            let mut err = dcx.handle().struct_span_err(msp, "foo");
+            for (position, note) in &notes {
+                if let Some((start, end)) = position {
+                    let span = make_span(&file_text, &start, &end);
+                    err.span_note(span, *note);
+                } else {
+                    err.note(*note);
+                }
+            }
+            err.emit();
 
-        assert!(
-            expected_output.chars().next() == Some('\n'),
-            "expected output should begin with newline"
-        );
-        let expected_output = &expected_output[1..];
+            assert!(
+                expected_output.chars().next() == Some('\n'),
+                "expected output should begin with newline"
+            );
+            let expected_output = &expected_output[1..];
 
-        let bytes = output.lock().unwrap();
-        let actual_output = str::from_utf8(&bytes).unwrap();
-        println!("expected output:\n------\n{}------", expected_output);
-        println!("actual output:\n------\n{}------", actual_output);
+            let bytes = output.lock().unwrap();
+            let actual_output = str::from_utf8(&bytes).unwrap();
+            println!("expected output:\n------\n{}------", expected_output);
+            println!("actual output:\n------\n{}------", actual_output);
 
-        assert!(expected_output == actual_output)
+            assert!(expected_output == actual_output)
+        }
     })
 }
 
@@ -253,6 +275,7 @@ fn foo() {
             end: Position { string: "}", count: 1 },
             label: "test",
         }],
+        vec![],
         r#"
 error: foo
  --> test.rs:2:10
@@ -263,6 +286,16 @@ error: foo
   | |_^ test
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:2:10
+  │
+2 │   fn foo() {
+  │ ┏━━━━━━━━━━┛
+3 │ ┃ }
+  ╰╴┗━┛ test
+
+"#,
     );
 }
 
@@ -280,6 +313,7 @@ fn foo() {
             end: Position { string: "}", count: 1 },
             label: "test",
         }],
+        vec![],
         r#"
 error: foo
  --> test.rs:2:10
@@ -291,6 +325,17 @@ error: foo
   | |___^ test
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:2:10
+  │
+2 │   fn foo() {
+  │ ┏━━━━━━━━━━┛
+  ‡ ┃
+5 │ ┃   }
+  ╰╴┗━━━┛ test
+
+"#,
     );
 }
 #[test]
@@ -315,6 +360,7 @@ fn foo() {
                 label: "`Y` is a good letter too",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -329,6 +375,20 @@ error: foo
   |       `X` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │      X0 Y0
+  │ ┏━━━━┛  │
+  │ ┃┌──────┘
+4 │ ┃│   X1 Y1
+5 │ ┃│   X2 Y2
+  │ ┃└────╿──┘ `Y` is a good letter too
+  │ ┗━━━━━┥
+  ╰╴      `X` is a good letter
+
+"#,
     );
 }
 
@@ -353,6 +413,7 @@ fn foo() {
                 label: "`Y` is a good letter too",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -366,6 +427,72 @@ error: foo
   |       `Y` is a good letter too
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │      X0 Y0
+  │ ┏━━━━┛  │
+  │ ┃┌──────┘
+4 │ ┃│   Y1 X1
+  │ ┗│━━━━│━━┛ `X` is a good letter
+  │  └────┤
+  ╰╴      `Y` is a good letter too
+
+"#,
+    );
+}
+
+#[test]
+fn multiline_and_normal_overlap() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![
+            SpanLabel {
+                start: Position { string: "Y0", count: 1 },
+                end: Position { string: "X2", count: 1 },
+                label: "`X` is a good letter",
+            },
+            SpanLabel {
+                start: Position { string: "X0", count: 1 },
+                end: Position { string: "Y0", count: 1 },
+                label: "`Y` is a good letter too",
+            },
+        ],
+        vec![],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |     X0 Y0 Z0
+  |  ___---^-
+  | |   |
+  | |   `Y` is a good letter too
+4 | |   X1 Y1 Z1
+5 | |   X2 Y2 Z2
+  | |____^ `X` is a good letter
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │     X0 Y0 Z0
+  │ ┏━━━┬──┛─
+  │ ┃   │
+  │ ┃   `Y` is a good letter too
+4 │ ┃   X1 Y1 Z1
+5 │ ┃   X2 Y2 Z2
+  ╰╴┗━━━━┛ `X` is a good letter
+
+"#,
     );
 }
 
@@ -392,6 +519,7 @@ fn foo() {
                 label: "`Y` is a good letter too",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:6
@@ -406,6 +534,789 @@ error: foo
   |  |____- `Y` is a good letter too
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │      X0 Y0 Z0
+  │ ┏━━━━━━━┛
+4 │ ┃    X1 Y1 Z1
+  │ ┃┌─────────┘
+5 │ ┃│   X2 Y2 Z2
+  │ ┗│━━━━┛ `X` is a good letter
+6 │  │   X3 Y3 Z3
+  ╰╴ └────┘ `Y` is a good letter too
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_1() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![(None, "bar")],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+  = note: bar
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  │
+  ╰ note: bar
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_2() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![(None, "bar"), (None, "qux")],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+  = note: bar
+  = note: qux
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  │
+  ├ note: bar
+  ╰ note: qux
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_3() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![(None, "bar"), (None, "baz"), (None, "qux")],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+  = note: bar
+  = note: baz
+  = note: qux
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  │
+  ├ note: bar
+  ├ note: baz
+  ╰ note: qux
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_1() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![(
+            Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+            "bar",
+        )],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+note: bar
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  ╰╴
+note: bar
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_2() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "bar",
+            ),
+            (
+                Some((Position { string: "X2", count: 1 }, Position { string: "Y2", count: 1 })),
+                "qux",
+            ),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+note: bar
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+note: qux
+ --> test.rs:5:3
+  |
+5 |   X2 Y2 Z2
+  |   ^^^^^
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  ╰╴
+note: bar
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+note: qux
+  ╭▸ test.rs:5:3
+  │
+5 │   X2 Y2 Z2
+  ╰╴  ━━━━━
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_3() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "bar",
+            ),
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "baz",
+            ),
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "qux",
+            ),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+note: bar
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+note: baz
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+note: qux
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  ╰╴
+note: bar
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+note: baz
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+note: qux
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_4() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "bar",
+            ),
+            (None, "qux"),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+note: bar
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+  = note: qux
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  ╰╴
+note: bar
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  │   ━━━━━━━━
+  ╰ note: qux
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_5() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (None, "bar"),
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "qux",
+            ),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+  = note: bar
+note: qux
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  │
+  ╰ note: bar
+note: qux
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_6() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (None, "bar"),
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "baz",
+            ),
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "qux",
+            ),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+  = note: bar
+note: baz
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+note: qux
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  │
+  ╰ note: bar
+note: baz
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+note: qux
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_7() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z3", count: 1 })),
+                "bar",
+            ),
+            (None, "baz"),
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "qux",
+            ),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+note: bar
+ --> test.rs:4:3
+  |
+4 | /   X1 Y1 Z1
+5 | |   X2 Y2 Z2
+6 | |   X3 Y3 Z3
+  | |__________^
+  = note: baz
+note: qux
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  ╰╴
+note: bar
+  ╭▸ test.rs:4:3
+  │
+4 │ ┏   X1 Y1 Z1
+5 │ ┃   X2 Y2 Z2
+6 │ ┃   X3 Y3 Z3
+  │ ┗━━━━━━━━━━┛
+  ╰ note: baz
+note: qux
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_8() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "bar",
+            ),
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "baz",
+            ),
+            (None, "qux"),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+note: bar
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+note: baz
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+  = note: qux
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  ╰╴
+note: bar
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+note: baz
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  │   ━━━━━━━━
+  ╰ note: qux
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_9() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (None, "bar"),
+            (None, "baz"),
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "qux",
+            ),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+  = note: bar
+  = note: baz
+note: qux
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  │
+  ├ note: bar
+  ╰ note: baz
+note: qux
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  ╰╴  ━━━━━━━━
+
+"#,
+    );
+}
+
+#[test]
+fn different_note_spanned_10() {
+    test_harness(
+        r#"
+fn foo() {
+  X0 Y0 Z0
+  X1 Y1 Z1
+  X2 Y2 Z2
+  X3 Y3 Z3
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "Y0", count: 1 },
+            end: Position { string: "Z0", count: 1 },
+            label: "`X` is a good letter",
+        }],
+        vec![
+            (
+                Some((Position { string: "X1", count: 1 }, Position { string: "Z1", count: 1 })),
+                "bar",
+            ),
+            (None, "baz"),
+            (None, "qux"),
+        ],
+        r#"
+error: foo
+ --> test.rs:3:6
+  |
+3 |   X0 Y0 Z0
+  |      ^^^^^ `X` is a good letter
+  |
+note: bar
+ --> test.rs:4:3
+  |
+4 |   X1 Y1 Z1
+  |   ^^^^^^^^
+  = note: baz
+  = note: qux
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │   X0 Y0 Z0
+  │      ━━━━━ `X` is a good letter
+  ╰╴
+note: bar
+  ╭▸ test.rs:4:3
+  │
+4 │   X1 Y1 Z1
+  │   ━━━━━━━━
+  ├ note: baz
+  ╰ note: qux
+
+"#,
     );
 }
 
@@ -436,6 +1347,7 @@ fn foo() {
                 label: "`Z` label",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -452,6 +1364,22 @@ error: foo
   |        `X` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │       X0 Y0 Z0
+  │ ┏━━━━━┛  │  │
+  │ ┃┌───────┘  │
+  │ ┃│┌─────────┘
+4 │ ┃││   X1 Y1 Z1
+5 │ ┃││   X2 Y2 Z2
+  │ ┃│└────╿──│──┘ `Z` label
+  │ ┃└─────│──┤
+  │ ┗━━━━━━┥  `Y` is a good letter too
+  ╰╴       `X` is a good letter
+
+"#,
     );
 }
 
@@ -482,6 +1410,7 @@ fn foo() {
                 label: "`Z` label",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -496,6 +1425,20 @@ error: foo
   |      `Z` label
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │ ┏   X0 Y0 Z0
+4 │ ┃   X1 Y1 Z1
+5 │ ┃   X2 Y2 Z2
+  │ ┃    ╿
+  │ ┃    │
+  │ ┃    `X` is a good letter
+  │ ┗━━━━`Y` is a good letter too
+  ╰╴     `Z` label
+
+"#,
     );
 }
 
@@ -527,6 +1470,7 @@ fn foo() {
                 label: "`Z`",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:6
@@ -545,6 +1489,24 @@ error: foo
   |  |_______- `Z`
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │      X0 Y0 Z0
+  │ ┏━━━━━━━┛
+4 │ ┃    X1 Y1 Z1
+  │ ┃┌────╿─┘
+  │ ┗│━━━━┥
+  │  │    `X` is a good letter
+5 │  │   X2 Y2 Z2
+  │  └───│──────┘ `Y` is a good letter too
+  │  ┌───┘
+  │  │
+6 │  │   X3 Y3 Z3
+  ╰╴ └───────┘ `Z`
+
+"#,
     );
 }
 
@@ -571,6 +1533,7 @@ fn foo() {
                 label: "`Y` is a good letter too",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -584,6 +1547,19 @@ error: foo
   | |__________- `Y` is a good letter too
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │ ┏   X0 Y0 Z0
+4 │ ┃   X1 Y1 Z1
+  │ ┗━━━━┛ `X` is a good letter
+5 │     X2 Y2 Z2
+  │ ┌──────┘
+6 │ │   X3 Y3 Z3
+  ╰╴└──────────┘ `Y` is a good letter too
+
+"#,
     );
 }
 
@@ -610,6 +1586,7 @@ fn foo() {
                 label: "`Y` is a good letter too",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:6
@@ -625,6 +1602,21 @@ error: foo
   |  |__________- `Y` is a good letter too
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:6
+  │
+3 │      X0 Y0 Z0
+  │ ┏━━━━━━━┛
+4 │ ┃    X1 Y1 Z1
+  │ ┃┌────╿────┘
+  │ ┗│━━━━┥
+  │  │    `X` is a good letter
+5 │  │   X2 Y2 Z2
+6 │  │   X3 Y3 Z3
+  ╰╴ └──────────┘ `Y` is a good letter too
+
+"#,
     );
 }
 
@@ -653,6 +1645,7 @@ fn foo() {
                 label: "",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:7
@@ -661,6 +1654,57 @@ error: foo
   |   ----^^^^-^^-- `a` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:7
+  │
+3 │   a { b { c } d }
+  ╰╴  ────━━━━─━━── `a` is a good letter
+
+"#,
+    );
+}
+
+#[test]
+fn multiline_notes() {
+    test_harness(
+        r#"
+fn foo() {
+  a { b { c } d }
+}
+"#,
+        vec![SpanLabel {
+            start: Position { string: "a", count: 1 },
+            end: Position { string: "d", count: 1 },
+            label: "`a` is a good letter",
+        }],
+        vec![(None, "foo\nbar"), (None, "foo\nbar")],
+        r#"
+error: foo
+ --> test.rs:3:3
+  |
+3 |   a { b { c } d }
+  |   ^^^^^^^^^^^^^ `a` is a good letter
+  |
+  = note: foo
+          bar
+  = note: foo
+          bar
+
+"#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │   a { b { c } d }
+  │   ━━━━━━━━━━━━━ `a` is a good letter
+  │
+  ├ note: foo
+  │       bar
+  ╰ note: foo
+          bar
+
+"#,
     );
 }
 
@@ -684,6 +1728,7 @@ fn foo() {
                 label: "",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -692,6 +1737,14 @@ error: foo
   |   ^^^^-------^^ `a` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │   a { b { c } d }
+  ╰╴  ━━━━───────━━ `a` is a good letter
+
+"#,
     );
 }
 
@@ -720,6 +1773,7 @@ fn foo() {
                 label: "",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:7
@@ -730,6 +1784,16 @@ error: foo
   |       `b` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:7
+  │
+3 │   a { b { c } d }
+  │   ────┯━━━─━━──
+  │       │
+  ╰╴      `b` is a good letter
+
+"#,
     );
 }
 
@@ -753,6 +1817,7 @@ fn foo() {
                 label: "`b` is a good letter",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -763,6 +1828,16 @@ error: foo
   |       `b` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │   a { b { c } d }
+  │   ━━━━┬──────━━
+  │       │
+  ╰╴      `b` is a good letter
+
+"#,
     );
 }
 
@@ -786,6 +1861,7 @@ fn foo() {
                 label: "",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -796,6 +1872,16 @@ error: foo
   |   `a` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │   a  bc  d
+  │   ┯━━━────
+  │   │
+  ╰╴  `a` is a good letter
+
+"#,
     );
 }
 
@@ -819,6 +1905,7 @@ fn foo() {
                 label: "",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -827,6 +1914,14 @@ error: foo
   |   ^^^^-------^^
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │   a { b { c } d }
+  ╰╴  ━━━━───────━━
+
+"#,
     );
 }
 
@@ -855,6 +1950,7 @@ fn foo() {
                 label: "",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:7
@@ -863,6 +1959,14 @@ error: foo
   |   ----^^^^-^^--
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:7
+  │
+3 │   a { b { c } d }
+  ╰╴  ────━━━━─━━──
+
+"#,
     );
 }
 
@@ -886,6 +1990,7 @@ fn foo() {
                 label: "`b` is a good letter",
             },
         ],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -897,6 +2002,17 @@ error: foo
   |   `a` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │   a { b { c } d }
+  │   ┯━━━┬──────━━
+  │   │   │
+  │   │   `b` is a good letter
+  ╰╴  `a` is a good letter
+
+"#,
     );
 }
 
@@ -913,6 +2029,7 @@ fn foo() {
             end: Position { string: "d", count: 1 },
             label: "`a` is a good letter",
         }],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -921,6 +2038,14 @@ error: foo
   |   ^^^^^^^^^^^^^ `a` is a good letter
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │   a { b { c } d }
+  ╰╴  ━━━━━━━━━━━━━ `a` is a good letter
+
+"#,
     );
 }
 
@@ -937,6 +2062,7 @@ fn foo() {
             end: Position { string: "d", count: 1 },
             label: "",
         }],
+        vec![],
         r#"
 error: foo
  --> test.rs:3:3
@@ -945,6 +2071,14 @@ error: foo
   |   ^^^^^^^^^^^^^
 
 "#,
+        r#"
+error: foo
+  ╭▸ test.rs:3:3
+  │
+3 │   a { b { c } d }
+  ╰╴  ━━━━━━━━━━━━━
+
+"#,
     );
 }
 
@@ -981,6 +2115,7 @@ fn foo() {
                 label: "`Y` is a good letter too",
             },
         ],
+        vec![],
         r#"
 error: foo
   --> test.rs:3:6
@@ -1000,6 +2135,25 @@ error: foo
    |  |__________- `Y` is a good letter too
 
 "#,
+        r#"
+error: foo
+   ╭▸ test.rs:3:6
+   │
+3  │      X0 Y0 Z0
+   │ ┏━━━━━━━┛
+4  │ ┃    X1 Y1 Z1
+   │ ┃┌────╿────┘
+   │ ┗│━━━━┥
+   │  │    `X` is a good letter
+5  │  │ 1
+6  │  │ 2
+7  │  │ 3
+   ‡  │
+15 │  │   X2 Y2 Z2
+16 │  │   X3 Y3 Z3
+   ╰╴ └──────────┘ `Y` is a good letter too
+
+"#,
     );
 }
 
@@ -1036,6 +2190,7 @@ fn foo() {
                 label: "`Z` is a good letter too",
             },
         ],
+        vec![],
         r#"
 error: foo
   --> test.rs:3:6
@@ -1058,6 +2213,28 @@ error: foo
    | |________^ `Y` is a good letter
 
 "#,
+        r#"
+error: foo
+   ╭▸ test.rs:3:6
+   │
+3  │      X0 Y0 Z0
+   │ ┏━━━━━━━┛
+4  │ ┃  1
+5  │ ┃  2
+6  │ ┃  3
+7  │ ┃    X1 Y1 Z1
+   │ ┃┌─────────┘
+8  │ ┃│ 4
+9  │ ┃│ 5
+10 │ ┃│ 6
+11 │ ┃│   X2 Y2 Z2
+   │ ┃└──────────┘ `Z` is a good letter too
+   ‡ ┃
+15 │ ┃  10
+16 │ ┃    X3 Y3 Z3
+   ╰╴┗━━━━━━━━┛ `Y` is a good letter
+
+"#,
     );
 }
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 6f0bcf5c3f0..08098ae7f6c 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -234,6 +234,9 @@ passes_doc_masked_only_extern_crate =
 passes_doc_rust_logo =
     the `#[doc(rust_logo)]` attribute is used for Rust branding
 
+passes_doc_search_unbox_invalid =
+    `#[doc(search_unbox)]` should be used on generic structs and enums
+
 passes_doc_test_literal = `#![doc(test(...)]` does not take a literal
 
 passes_doc_test_takes_list =
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 64a527ef106..836511325f4 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -16,8 +16,8 @@ use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, B
 use rustc_hir::def_id::LocalModDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{
-    self as hir, self, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, Item, ItemKind,
-    MethodKind, Safety, Target, TraitItem,
+    self as hir, self, AssocItemKind, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId,
+    Item, ItemKind, MethodKind, Safety, Target, TraitItem,
 };
 use rustc_macros::LintDiagnostic;
 use rustc_middle::hir::nested_filter;
@@ -937,6 +937,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
+    fn check_doc_search_unbox(&self, meta: &MetaItemInner, hir_id: HirId) {
+        let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else {
+            self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
+            return;
+        };
+        match item.kind {
+            ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics)
+                if generics.params.len() != 0 => {}
+            ItemKind::Trait(_, _, generics, _, items)
+                if generics.params.len() != 0
+                    || items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {}
+            _ => {
+                self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
+            }
+        }
+    }
+
     /// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes.
     ///
     /// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
@@ -1149,6 +1166,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             }
                         }
 
+                        sym::search_unbox => {
+                            if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
+                                self.check_doc_search_unbox(meta, hir_id);
+                            }
+                        }
+
                         sym::test => {
                             if self.check_attr_crate_level(attr, meta, hir_id) {
                                 self.check_test_attr(meta, hir_id);
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 70c92f0144c..2d1734c0314 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -245,6 +245,13 @@ pub(crate) struct DocKeywordOnlyImpl {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_doc_search_unbox_invalid)]
+pub(crate) struct DocSearchUnboxInvalid {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_doc_inline_conflict)]
 #[help]
 pub(crate) struct DocKeywordConflict {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index cd47c8ece60..4a793f1875e 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -16,7 +16,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Constness, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
 use rustc_middle::middle::privacy::EffectiveVisibilities;
@@ -149,6 +149,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             if let Some(stab) = self.parent_stab {
                 if inherit_deprecation.yes() && stab.is_unstable() {
                     self.index.stab_map.insert(def_id, stab);
+                    if fn_sig.is_some_and(|s| s.header.is_const()) {
+                        let const_stab =
+                            attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab);
+                        self.index.const_stab_map.insert(def_id, const_stab);
+                    }
                 }
             }
 
@@ -161,68 +166,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             return;
         }
 
+        // # Regular and body stability
+
         let stab = attr::find_stability(self.tcx.sess, attrs, item_sp);
-        let const_stab = attr::find_const_stability(
-            self.tcx.sess,
-            attrs,
-            item_sp,
-            fn_sig.is_some_and(|s| s.header.is_const()),
-        );
         let body_stab = attr::find_body_stability(self.tcx.sess, attrs);
 
-        // If the current node is a function with const stability attributes (directly given or
-        // implied), check if the function/method is const or the parent impl block is const.
-        if let Some(fn_sig) = fn_sig
-            && !fn_sig.header.is_const()
-            && const_stab.is_some()
-        {
-            self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
-        }
-
-        // If this is marked const *stable*, it must also be regular-stable.
-        if let Some((const_stab, const_span)) = const_stab
-            && let Some(fn_sig) = fn_sig
-            && const_stab.is_const_stable()
-            && !stab.is_some_and(|(s, _)| s.is_stable())
-        {
-            self.tcx
-                .dcx()
-                .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
-        }
-
-        // Stable *language* features shouldn't be used as unstable library features.
-        // (Not doing this for stable library features is checked by tidy.)
-        if let Some((
-            ConstStability { level: Unstable { .. }, feature: Some(feature), .. },
-            const_span,
-        )) = const_stab
-        {
-            if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
-                self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
-                    span: const_span,
-                    item_sp,
-                });
-            }
-        }
-
-        let const_stab = const_stab.map(|(const_stab, _span)| {
-            self.index.const_stab_map.insert(def_id, const_stab);
-            const_stab
-        });
-
-        // `impl const Trait for Type` items forward their const stability to their
-        // immediate children.
-        // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
-        // Currently, once that is set, we do not inherit anything from the parent any more.
-        if const_stab.is_none() {
-            debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
-            if let Some(parent) = self.parent_const_stab {
-                if parent.is_const_unstable() {
-                    self.index.const_stab_map.insert(def_id, parent);
-                }
-            }
-        }
-
         if let Some((depr, span)) = &depr
             && depr.is_since_rustc_version()
             && stab.is_none()
@@ -289,15 +237,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 self.index.implications.insert(implied_by, feature);
             }
 
-            if let Some(ConstStability {
-                level: Unstable { implied_by: Some(implied_by), .. },
-                feature,
-                ..
-            }) = const_stab
-            {
-                self.index.implications.insert(implied_by, feature.unwrap());
-            }
-
             self.index.stab_map.insert(def_id, stab);
             stab
         });
@@ -311,6 +250,91 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             }
         }
 
+        let final_stab = self.index.stab_map.get(&def_id);
+
+        // # Const stability
+
+        let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp);
+
+        // If the current node is a function with const stability attributes (directly given or
+        // implied), check if the function/method is const.
+        if let Some(fn_sig) = fn_sig
+            && !fn_sig.header.is_const()
+            && const_stab.is_some()
+        {
+            self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
+        }
+
+        // If this is marked const *stable*, it must also be regular-stable.
+        if let Some((const_stab, const_span)) = const_stab
+            && let Some(fn_sig) = fn_sig
+            && const_stab.is_const_stable()
+            && !stab.is_some_and(|s| s.is_stable())
+        {
+            self.tcx
+                .dcx()
+                .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
+        }
+
+        // Stable *language* features shouldn't be used as unstable library features.
+        // (Not doing this for stable library features is checked by tidy.)
+        if let Some((ConstStability { level: Unstable { .. }, feature, .. }, const_span)) =
+            const_stab
+        {
+            if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
+                self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
+                    span: const_span,
+                    item_sp,
+                });
+            }
+        }
+
+        // After checking the immediate attributes, get rid of the span and compute implied
+        // const stability: inherit feature gate from regular stability.
+        let mut const_stab = const_stab.map(|(stab, _span)| stab);
+
+        // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability.
+        if fn_sig.is_some_and(|s| s.header.is_const())  && const_stab.is_none() &&
+            // We only ever inherit unstable features.
+            let Some(inherit_regular_stab) =
+                final_stab.filter(|s| s.is_unstable())
+        {
+            const_stab = Some(ConstStability {
+                // We subject these implicitly-const functions to recursive const stability.
+                const_stable_indirect: true,
+                promotable: false,
+                level: inherit_regular_stab.level,
+                feature: inherit_regular_stab.feature,
+            });
+        }
+
+        // Now that everything is computed, insert it into the table.
+        const_stab.inspect(|const_stab| {
+            self.index.const_stab_map.insert(def_id, *const_stab);
+        });
+
+        if let Some(ConstStability {
+            level: Unstable { implied_by: Some(implied_by), .. },
+            feature,
+            ..
+        }) = const_stab
+        {
+            self.index.implications.insert(implied_by, feature);
+        }
+
+        // `impl const Trait for Type` items forward their const stability to their
+        // immediate children.
+        // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
+        // Currently, once that is set, we do not inherit anything from the parent any more.
+        if const_stab.is_none() {
+            debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
+            if let Some(parent) = self.parent_const_stab {
+                if parent.is_const_unstable() {
+                    self.index.const_stab_map.insert(def_id, parent);
+                }
+            }
+        }
+
         self.recurse_with_stability_attrs(
             depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
             stab,
@@ -565,13 +589,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
         }
     }
 
-    fn check_missing_or_wrong_const_stability(&self, def_id: LocalDefId, span: Span) {
-        // The visitor runs for "unstable-if-unmarked" crates, but we don't yet support
-        // that on the const side.
-        if !self.tcx.features().staged_api() {
-            return;
-        }
-
+    fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
         // if the const impl is derived using the `derive_const` attribute,
         // then it would be "stable" at least for the impl.
         // We gate usages of it using `feature(const_trait_impl)` anyways
@@ -582,12 +600,12 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
 
         let is_const = self.tcx.is_const_fn(def_id.to_def_id())
             || self.tcx.is_const_trait_impl(def_id.to_def_id());
-        let is_stable =
-            self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable());
-        let missing_const_stability_attribute =
-            self.tcx.lookup_const_stability(def_id).is_none_or(|s| s.feature.is_none());
 
-        if is_const && is_stable && missing_const_stability_attribute {
+        // Reachable const fn must have a stability attribute.
+        if is_const
+            && self.effective_visibilities.is_reachable(def_id)
+            && self.tcx.lookup_const_stability(def_id).is_none()
+        {
             let descr = self.tcx.def_descr(def_id.to_def_id());
             self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr });
         }
@@ -615,7 +633,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
         }
 
         // Ensure stable `const fn` have a const stability attribute.
-        self.check_missing_or_wrong_const_stability(i.owner_id.def_id, i.span);
+        self.check_missing_const_stability(i.owner_id.def_id, i.span);
 
         intravisit::walk_item(self, i)
     }
@@ -629,7 +647,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
         let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
             self.check_missing_stability(ii.owner_id.def_id, ii.span);
-            self.check_missing_or_wrong_const_stability(ii.owner_id.def_id, ii.span);
+            self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -760,23 +778,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
             // For implementations of traits, check the stability of each item
             // individually as it's possible to have a stable trait with unstable
             // items.
-            hir::ItemKind::Impl(hir::Impl {
-                constness,
-                of_trait: Some(ref t),
-                self_ty,
-                items,
-                ..
-            }) => {
+            hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
                 let features = self.tcx.features();
                 if features.staged_api() {
                     let attrs = self.tcx.hir().attrs(item.hir_id());
                     let stab = attr::find_stability(self.tcx.sess, attrs, item.span);
-                    let const_stab = attr::find_const_stability(
-                        self.tcx.sess,
-                        attrs,
-                        item.span,
-                        matches!(constness, Constness::Const),
-                    );
+                    let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span);
 
                     // If this impl block has an #[unstable] attribute, give an
                     // error if all involved types and traits are stable, because
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 9ea5023064c..7cc6ba24450 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -453,7 +453,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
         let fields: Vec<_>;
         match &pat.kind {
             PatKind::AscribeUserType { subpattern, .. }
-            | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern),
+            | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 1a5c29afdc9..c845d60ac07 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -782,21 +782,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
 impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
     fn generics(&mut self) -> &mut Self {
         for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
-            match param.kind {
-                GenericParamDefKind::Lifetime => {}
-                GenericParamDefKind::Type { has_default, .. } => {
-                    if has_default {
-                        self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
-                    }
-                }
-                GenericParamDefKind::Const { has_default, .. } => {
-                    self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
-                    if has_default {
-                        self.visit(
-                            self.ev.tcx.const_param_default(param.def_id).instantiate_identity(),
-                        );
-                    }
-                }
+            if let GenericParamDefKind::Const { .. } = param.kind {
+                self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
+            }
+            if let Some(default) = param.default_value(self.ev.tcx) {
+                self.visit(default.instantiate_identity());
             }
         }
         self
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 2bb1be22b98..6e8fd32610b 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -19,8 +19,3 @@ rustc_span = { path = "../rustc_span" }
 thin-vec = "0.2.12"
 tracing = "0.1"
 # tidy-alphabetical-end
-
-[features]
-# tidy-alphabetical-start
-rustc_use_parallel_compiler = ["rustc_query_system/rustc_use_parallel_compiler"]
-# tidy-alphabetical-end
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 2f42fa47728..96b210accdb 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 parking_lot = "0.12"
-rustc-rayon-core = { version = "0.5.0", optional = true }
+rustc-rayon-core = { version = "0.5.0" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
@@ -23,8 +23,3 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 thin-vec = "0.2.12"
 tracing = "0.1"
 # tidy-alphabetical-end
-
-[features]
-# tidy-alphabetical-start
-rustc_use_parallel_compiler = ["dep:rustc-rayon-core"]
-# tidy-alphabetical-end
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index e7ed8288499..9b26a5bbcc6 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -837,12 +837,6 @@ impl<D: Deps> DepGraphData<D> {
     ) -> Option<DepNodeIndex> {
         let frame = MarkFrame { index: prev_dep_node_index, parent: frame };
 
-        #[cfg(not(parallel_compiler))]
-        {
-            debug_assert!(!self.dep_node_exists(dep_node));
-            debug_assert!(self.colors.get(prev_dep_node_index).is_none());
-        }
-
         // We never try to mark eval_always nodes as green
         debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
 
@@ -871,13 +865,6 @@ impl<D: Deps> DepGraphData<D> {
         // Maybe store a list on disk and encode this fact in the DepNodeState
         let side_effects = qcx.load_side_effects(prev_dep_node_index);
 
-        #[cfg(not(parallel_compiler))]
-        debug_assert!(
-            self.colors.get(prev_dep_node_index).is_none(),
-            "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \
-                      insertion for {dep_node:?}"
-        );
-
         if side_effects.maybe_any() {
             qcx.dep_context().dep_graph().with_query_deserialization(|| {
                 self.emit_side_effects(qcx, dep_node_index, side_effects)
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 5af41b9e687..2a7d759ab35 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -1,21 +1,16 @@
 use std::hash::Hash;
 use std::io::Write;
+use std::iter;
 use std::num::NonZero;
+use std::sync::Arc;
 
-use rustc_data_structures::fx::FxHashMap;
+use parking_lot::{Condvar, Mutex};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::jobserver;
 use rustc_errors::{Diag, DiagCtxtHandle};
 use rustc_hir::def::DefKind;
 use rustc_session::Session;
-use rustc_span::Span;
-#[cfg(parallel_compiler)]
-use {
-    parking_lot::{Condvar, Mutex},
-    rustc_data_structures::fx::FxHashSet,
-    rustc_data_structures::jobserver,
-    rustc_span::DUMMY_SP,
-    std::iter,
-    std::sync::Arc,
-};
+use rustc_span::{DUMMY_SP, Span};
 
 use crate::dep_graph::DepContext;
 use crate::error::CycleStack;
@@ -41,17 +36,14 @@ impl QueryJobId {
         map.get(&self).unwrap().query.clone()
     }
 
-    #[cfg(parallel_compiler)]
     fn span(self, map: &QueryMap) -> Span {
         map.get(&self).unwrap().job.span
     }
 
-    #[cfg(parallel_compiler)]
     fn parent(self, map: &QueryMap) -> Option<QueryJobId> {
         map.get(&self).unwrap().job.parent
     }
 
-    #[cfg(parallel_compiler)]
     fn latch(self, map: &QueryMap) -> Option<&QueryLatch> {
         map.get(&self).unwrap().job.latch.as_ref()
     }
@@ -75,7 +67,6 @@ pub struct QueryJob {
     pub parent: Option<QueryJobId>,
 
     /// The latch that is used to wait on this job.
-    #[cfg(parallel_compiler)]
     latch: Option<QueryLatch>,
 }
 
@@ -83,16 +74,9 @@ impl QueryJob {
     /// Creates a new query job.
     #[inline]
     pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
-        QueryJob {
-            id,
-            span,
-            parent,
-            #[cfg(parallel_compiler)]
-            latch: None,
-        }
+        QueryJob { id, span, parent, latch: None }
     }
 
-    #[cfg(parallel_compiler)]
     pub(super) fn latch(&mut self) -> QueryLatch {
         if self.latch.is_none() {
             self.latch = Some(QueryLatch::new());
@@ -106,11 +90,8 @@ impl QueryJob {
     /// as there are no concurrent jobs which could be waiting on us
     #[inline]
     pub fn signal_complete(self) {
-        #[cfg(parallel_compiler)]
-        {
-            if let Some(latch) = self.latch {
-                latch.set();
-            }
+        if let Some(latch) = self.latch {
+            latch.set();
         }
     }
 }
@@ -176,7 +157,6 @@ impl QueryJobId {
     }
 }
 
-#[cfg(parallel_compiler)]
 #[derive(Debug)]
 struct QueryWaiter {
     query: Option<QueryJobId>,
@@ -185,7 +165,6 @@ struct QueryWaiter {
     cycle: Mutex<Option<CycleError>>,
 }
 
-#[cfg(parallel_compiler)]
 impl QueryWaiter {
     fn notify(&self, registry: &rayon_core::Registry) {
         rayon_core::mark_unblocked(registry);
@@ -193,20 +172,17 @@ impl QueryWaiter {
     }
 }
 
-#[cfg(parallel_compiler)]
 #[derive(Debug)]
 struct QueryLatchInfo {
     complete: bool,
     waiters: Vec<Arc<QueryWaiter>>,
 }
 
-#[cfg(parallel_compiler)]
 #[derive(Clone, Debug)]
 pub(super) struct QueryLatch {
     info: Arc<Mutex<QueryLatchInfo>>,
 }
 
-#[cfg(parallel_compiler)]
 impl QueryLatch {
     fn new() -> Self {
         QueryLatch {
@@ -273,7 +249,6 @@ impl QueryLatch {
 }
 
 /// A resumable waiter of a query. The usize is the index into waiters in the query's latch
-#[cfg(parallel_compiler)]
 type Waiter = (QueryJobId, usize);
 
 /// Visits all the non-resumable and resumable waiters of a query.
@@ -285,7 +260,6 @@ type Waiter = (QueryJobId, usize);
 /// For visits of resumable waiters it returns Some(Some(Waiter)) which has the
 /// required information to resume the waiter.
 /// If all `visit` calls returns None, this function also returns None.
-#[cfg(parallel_compiler)]
 fn visit_waiters<F>(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option<Option<Waiter>>
 where
     F: FnMut(Span, QueryJobId) -> Option<Option<Waiter>>,
@@ -316,7 +290,6 @@ where
 /// `span` is the reason for the `query` to execute. This is initially DUMMY_SP.
 /// If a cycle is detected, this initial value is replaced with the span causing
 /// the cycle.
-#[cfg(parallel_compiler)]
 fn cycle_check(
     query_map: &QueryMap,
     query: QueryJobId,
@@ -357,7 +330,6 @@ fn cycle_check(
 /// Finds out if there's a path to the compiler root (aka. code which isn't in a query)
 /// from `query` without going through any of the queries in `visited`.
 /// This is achieved with a depth first search.
-#[cfg(parallel_compiler)]
 fn connected_to_root(
     query_map: &QueryMap,
     query: QueryJobId,
@@ -380,7 +352,6 @@ fn connected_to_root(
 }
 
 // Deterministically pick an query from a list
-#[cfg(parallel_compiler)]
 fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T
 where
     F: Fn(&T) -> (Span, QueryJobId),
@@ -406,7 +377,6 @@ where
 /// the function return true.
 /// If a cycle was not found, the starting query is removed from `jobs` and
 /// the function returns false.
-#[cfg(parallel_compiler)]
 fn remove_cycle(
     query_map: &QueryMap,
     jobs: &mut Vec<QueryJobId>,
@@ -511,7 +481,6 @@ fn remove_cycle(
 /// uses a query latch and then resuming that waiter.
 /// There may be multiple cycles involved in a deadlock, so this searches
 /// all active queries for cycles before finally resuming all the waiters at once.
-#[cfg(parallel_compiler)]
 pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) {
     let mut wakelist = Vec::new();
     let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 3e35fdb77b3..b81386f06ec 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -2,10 +2,9 @@ mod plumbing;
 pub use self::plumbing::*;
 
 mod job;
-#[cfg(parallel_compiler)]
-pub use self::job::break_query_cycles;
 pub use self::job::{
-    QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, print_query_stack, report_cycle,
+    QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryMap, break_query_cycles, print_query_stack,
+    report_cycle,
 };
 
 mod caches;
@@ -38,7 +37,6 @@ pub struct QueryStackFrame {
     pub dep_kind: DepKind,
     /// This hash is used to deterministically pick
     /// a query to remove cycles in the parallel compiler.
-    #[cfg(parallel_compiler)]
     hash: Hash64,
 }
 
@@ -51,18 +49,9 @@ impl QueryStackFrame {
         def_kind: Option<DefKind>,
         dep_kind: DepKind,
         ty_def_id: Option<DefId>,
-        _hash: impl FnOnce() -> Hash64,
+        hash: impl FnOnce() -> Hash64,
     ) -> Self {
-        Self {
-            description,
-            span,
-            def_id,
-            def_kind,
-            ty_def_id,
-            dep_kind,
-            #[cfg(parallel_compiler)]
-            hash: _hash(),
-        }
+        Self { description, span, def_id, def_kind, ty_def_id, dep_kind, hash: hash() }
     }
 
     // FIXME(eddyb) Get more valid `Span`s on queries.
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 17486be04dc..aac8ab87c64 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -13,7 +13,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sharded::Sharded;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lock;
-#[cfg(parallel_compiler)]
 use rustc_data_structures::{outline, sync};
 use rustc_errors::{Diag, FatalError, StashKey};
 use rustc_span::{DUMMY_SP, Span};
@@ -25,9 +24,7 @@ use crate::HandleCycleError;
 use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams};
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
-#[cfg(parallel_compiler)]
-use crate::query::job::QueryLatch;
-use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, report_cycle};
+use crate::query::job::{QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryLatch, report_cycle};
 use crate::query::{
     QueryContext, QueryMap, QuerySideEffects, QueryStackFrame, SerializedDepNodeIndex,
 };
@@ -263,7 +260,6 @@ where
 }
 
 #[inline(always)]
-#[cfg(parallel_compiler)]
 fn wait_for_query<Q, Qcx>(
     query: Q,
     qcx: Qcx,
@@ -334,7 +330,7 @@ where
     // re-executing the query since `try_start` only checks that the query is not currently
     // executing, but another thread may have already completed the query and stores it result
     // in the query cache.
-    if cfg!(parallel_compiler) && qcx.dep_context().sess().threads() > 1 {
+    if qcx.dep_context().sess().threads() > 1 {
         if let Some((value, index)) = query.query_cache(qcx).lookup(&key) {
             qcx.dep_context().profiler().query_cache_hit(index.into());
             return (value, Some(index));
@@ -359,7 +355,6 @@ where
         Entry::Occupied(mut entry) => {
             match entry.get_mut() {
                 QueryResult::Started(job) => {
-                    #[cfg(parallel_compiler)]
                     if sync::is_dyn_thread_safe() {
                         // Get the latch out
                         let latch = job.latch();
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index a825458dc89..bf27b767a49 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -130,18 +130,16 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
         &self,
         anon_const: &'a AnonConst,
     ) -> Option<(PendingAnonConstInfo, NodeId)> {
-        let (block_was_stripped, expr) = anon_const.value.maybe_unwrap_block();
-        match expr {
-            Expr { kind: ExprKind::MacCall(..), id, .. } => Some((
+        anon_const.value.optionally_braced_mac_call(false).map(|(block_was_stripped, id)| {
+            (
                 PendingAnonConstInfo {
                     id: anon_const.id,
                     span: anon_const.value.span,
                     block_was_stripped,
                 },
-                *id,
-            )),
-            _ => None,
-        }
+                id,
+            )
+        })
     }
 
     /// Determines whether the expression `const_arg_sub_expr` is a simple macro call, sometimes
@@ -161,18 +159,11 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
             panic!("Checking expr is trivial macro call without having entered anon const: `{const_arg_sub_expr:?}`"),
         );
 
-        let (block_was_stripped, expr) = if pending_anon.block_was_stripped {
-            (true, const_arg_sub_expr)
-        } else {
-            const_arg_sub_expr.maybe_unwrap_block()
-        };
-
-        match expr {
-            Expr { kind: ExprKind::MacCall(..), id, .. } => {
-                Some((PendingAnonConstInfo { block_was_stripped, ..pending_anon }, *id))
-            }
-            _ => None,
-        }
+        const_arg_sub_expr.optionally_braced_mac_call(pending_anon.block_was_stripped).map(
+            |(block_was_stripped, id)| {
+                (PendingAnonConstInfo { block_was_stripped, ..pending_anon }, id)
+            },
+        )
     }
 }
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index fa2403db925..44721bd889a 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1398,9 +1398,25 @@ pub enum OptionKind {
 }
 
 pub struct RustcOptGroup {
-    apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
+    /// The "primary" name for this option. Normally equal to `long_name`,
+    /// except for options that don't have a long name, in which case
+    /// `short_name` is used.
+    ///
+    /// This is needed when interacting with `getopts` in some situations,
+    /// because if an option has both forms, that library treats the long name
+    /// as primary and the short name as an alias.
     pub name: &'static str,
     stability: OptionStability,
+    kind: OptionKind,
+
+    short_name: &'static str,
+    long_name: &'static str,
+    desc: &'static str,
+    value_hint: &'static str,
+
+    /// If true, this option should not be printed by `rustc --help`, but
+    /// should still be printed by `rustc --help -v`.
+    pub is_verbose_help_only: bool,
 }
 
 impl RustcOptGroup {
@@ -1409,7 +1425,13 @@ impl RustcOptGroup {
     }
 
     pub fn apply(&self, options: &mut getopts::Options) {
-        (self.apply)(options);
+        let &Self { short_name, long_name, desc, value_hint, .. } = self;
+        match self.kind {
+            OptionKind::Opt => options.optopt(short_name, long_name, desc, value_hint),
+            OptionKind::Multi => options.optmulti(short_name, long_name, desc, value_hint),
+            OptionKind::Flag => options.optflag(short_name, long_name, desc),
+            OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
+        };
     }
 }
 
@@ -1419,31 +1441,22 @@ pub fn make_opt(
     short_name: &'static str,
     long_name: &'static str,
     desc: &'static str,
-    hint: &'static str,
+    value_hint: &'static str,
 ) -> RustcOptGroup {
+    // "Flag" options don't have a value, and therefore don't have a value hint.
+    match kind {
+        OptionKind::Opt | OptionKind::Multi => {}
+        OptionKind::Flag | OptionKind::FlagMulti => assert_eq!(value_hint, ""),
+    }
     RustcOptGroup {
         name: cmp::max_by_key(short_name, long_name, |s| s.len()),
         stability,
-        apply: match kind {
-            OptionKind::Opt => Box::new(move |opts: &mut getopts::Options| {
-                opts.optopt(short_name, long_name, desc, hint)
-            }),
-            OptionKind::Multi => Box::new(move |opts: &mut getopts::Options| {
-                opts.optmulti(short_name, long_name, desc, hint)
-            }),
-            OptionKind::Flag => {
-                assert_eq!(hint, "");
-                Box::new(move |opts: &mut getopts::Options| {
-                    opts.optflag(short_name, long_name, desc)
-                })
-            }
-            OptionKind::FlagMulti => {
-                assert_eq!(hint, "");
-                Box::new(move |opts: &mut getopts::Options| {
-                    opts.optflagmulti(short_name, long_name, desc)
-                })
-            }
-        },
+        kind,
+        short_name,
+        long_name,
+        desc,
+        value_hint,
+        is_verbose_help_only: false,
     }
 }
 
@@ -1454,16 +1467,15 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE
     )
 });
 
-/// Returns the "short" subset of the rustc command line options,
-/// including metadata for each option, such as whether the option is
-/// part of the stable long-term interface for rustc.
-pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
+/// Returns all rustc command line options, including metadata for
+/// each option, such as whether the option is stable.
+pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
     use OptionKind::{Flag, FlagMulti, Multi, Opt};
-    use OptionStability::Stable;
+    use OptionStability::{Stable, Unstable};
 
     use self::make_opt as opt;
 
-    vec![
+    let mut options = vec![
         opt(Stable, Flag, "h", "help", "Display this message", ""),
         opt(
             Stable,
@@ -1550,21 +1562,11 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
         opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
         opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
         opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
-    ]
-}
-
-/// Returns all rustc command line options, including metadata for
-/// each option, such as whether the option is part of the stable
-/// long-term interface for rustc.
-pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
-    use OptionKind::{Multi, Opt};
-    use OptionStability::{Stable, Unstable};
-
-    use self::make_opt as opt;
+    ];
 
-    let mut opts = rustc_short_optgroups();
-    // FIXME: none of these descriptions are actually used
-    opts.extend(vec![
+    // Options in this list are hidden from `rustc --help` by default, but are
+    // shown by `rustc --help -v`.
+    let verbose_only = [
         opt(
             Stable,
             Multi,
@@ -1590,9 +1592,9 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
             "",
             "color",
             "Configure coloring of output:
-                                 auto   = colorize, if output goes to a tty (default);
-                                 always = always colorize output;
-                                 never  = never colorize output",
+                auto   = colorize, if output goes to a tty (default);
+                always = always colorize output;
+                never  = never colorize output",
             "auto|always|never",
         ),
         opt(
@@ -1612,8 +1614,13 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
             "FROM=TO",
         ),
         opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"),
-    ]);
-    opts
+    ];
+    options.extend(verbose_only.into_iter().map(|mut opt| {
+        opt.is_verbose_help_only = true;
+        opt
+    }));
+
+    options
 }
 
 pub fn get_cmd_lint_options(
@@ -1721,6 +1728,9 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json
         for sub_option in option.split(',') {
             match sub_option {
                 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
+                "diagnostic-unicode" => {
+                    json_rendered = HumanReadableErrorType::Unicode;
+                }
                 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
                 "artifacts" => json_artifact_notifications = true,
                 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
@@ -1767,14 +1777,17 @@ pub fn parse_error_format(
                 ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color }
             }
             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short, color),
+            Some("human-unicode") => {
+                ErrorOutputType::HumanReadable(HumanReadableErrorType::Unicode, color)
+            }
             Some(arg) => {
                 early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
                     HumanReadableErrorType::Default,
                     color,
                 ));
                 early_dcx.early_fatal(format!(
-                    "argument for `--error-format` must be `human`, `json` or \
-                     `short` (instead was `{arg}`)"
+                    "argument for `--error-format` must be `human`, `human-annotate-rs`, \
+                    `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)"
                 ))
             }
         }
@@ -1827,18 +1840,21 @@ pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches
 fn check_error_format_stability(
     early_dcx: &EarlyDiagCtxt,
     unstable_opts: &UnstableOptions,
-    error_format: ErrorOutputType,
+    format: ErrorOutputType,
 ) {
-    if !unstable_opts.unstable_options {
-        if let ErrorOutputType::Json { pretty: true, .. } = error_format {
-            early_dcx.early_fatal("`--error-format=pretty-json` is unstable");
-        }
-        if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, _) =
-            error_format
-        {
-            early_dcx.early_fatal("`--error-format=human-annotate-rs` is unstable");
-        }
-    }
+    if unstable_opts.unstable_options {
+        return;
+    }
+    let format = match format {
+        ErrorOutputType::Json { pretty: true, .. } => "pretty-json",
+        ErrorOutputType::HumanReadable(format, _) => match format {
+            HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs",
+            HumanReadableErrorType::Unicode => "human-unicode",
+            _ => return,
+        },
+        _ => return,
+    };
+    early_dcx.early_fatal(format!("`--error-format={format}` is unstable"))
 }
 
 fn parse_output_types(
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 213a94ab880..4be013fd6fd 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -4,37 +4,44 @@ use std::path::{Path, PathBuf};
 use std::{env, fs};
 
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
+use rustc_target::spec::Target;
 use smallvec::{SmallVec, smallvec};
 
 use crate::search_paths::{PathKind, SearchPath};
 
 #[derive(Clone)]
-pub struct FileSearch<'a> {
-    cli_search_paths: &'a [SearchPath],
-    tlib_path: &'a SearchPath,
-    kind: PathKind,
+pub struct FileSearch {
+    cli_search_paths: Vec<SearchPath>,
+    tlib_path: SearchPath,
 }
 
-impl<'a> FileSearch<'a> {
-    pub fn cli_search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
-        let kind = self.kind;
+impl FileSearch {
+    pub fn cli_search_paths<'b>(&'b self, kind: PathKind) -> impl Iterator<Item = &'b SearchPath> {
         self.cli_search_paths.iter().filter(move |sp| sp.kind.matches(kind))
     }
 
-    pub fn search_paths(&self) -> impl Iterator<Item = &'a SearchPath> {
-        let kind = self.kind;
+    pub fn search_paths<'b>(&'b self, kind: PathKind) -> impl Iterator<Item = &'b SearchPath> {
         self.cli_search_paths
             .iter()
             .filter(move |sp| sp.kind.matches(kind))
-            .chain(std::iter::once(self.tlib_path))
+            .chain(std::iter::once(&self.tlib_path))
     }
 
-    pub fn new(
-        cli_search_paths: &'a [SearchPath],
-        tlib_path: &'a SearchPath,
-        kind: PathKind,
-    ) -> FileSearch<'a> {
-        FileSearch { cli_search_paths, tlib_path, kind }
+    pub fn new(cli_search_paths: &[SearchPath], tlib_path: &SearchPath, target: &Target) -> Self {
+        let this = FileSearch {
+            cli_search_paths: cli_search_paths.to_owned(),
+            tlib_path: tlib_path.clone(),
+        };
+        this.refine(&["lib", &target.staticlib_prefix, &target.dll_prefix])
+    }
+    // Produce a new file search from this search that has a smaller set of candidates.
+    fn refine(mut self, allowed_prefixes: &[&str]) -> FileSearch {
+        self.cli_search_paths
+            .iter_mut()
+            .for_each(|search_paths| search_paths.files.retain(allowed_prefixes));
+        self.tlib_path.files.retain(allowed_prefixes);
+
+        self
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 087ba0522eb..f485e8cace5 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -130,7 +130,7 @@ top_level_options!(
     pub struct Options {
         /// The crate config requested for the session, which may be combined
         /// with additional crate configurations during the compile process.
-        #[rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field")]
+        #[rustc_lint_opt_deny_field_access("use `TyCtxt::crate_types` instead of this field")]
         crate_types: Vec<CrateType> [TRACKED],
         optimize: OptLevel [TRACKED],
         /// Include the `debug_assertions` flag in dependency tracking, since it
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index c148b09c718..78473fccd2d 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -1,4 +1,5 @@
 use std::path::{Path, PathBuf};
+use std::sync::Arc;
 
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_target::spec::TargetTuple;
@@ -10,9 +11,44 @@ use crate::filesearch::make_target_lib_path;
 pub struct SearchPath {
     pub kind: PathKind,
     pub dir: PathBuf,
-    pub files: Vec<SearchPathFile>,
+    pub files: FilesIndex,
 }
 
+/// [FilesIndex] contains paths that can be efficiently looked up with (prefix, suffix) pairs.
+#[derive(Clone, Debug)]
+pub struct FilesIndex(Vec<(Arc<str>, SearchPathFile)>);
+
+impl FilesIndex {
+    /// Look up [SearchPathFile] by (prefix, suffix) pair.
+    pub fn query<'this, 'prefix, 'suffix>(
+        &'this self,
+        prefix: &'prefix str,
+        suffix: &'suffix str,
+    ) -> Option<impl Iterator<Item = (String, &'this SearchPathFile)> + use<'this, 'prefix, 'suffix>>
+    {
+        let start = self.0.partition_point(|(k, _)| **k < *prefix);
+        if start == self.0.len() {
+            return None;
+        }
+        let end = self.0[start..].partition_point(|(k, _)| k.starts_with(prefix));
+        let prefixed_items = &self.0[start..][..end];
+
+        let ret = prefixed_items.into_iter().filter_map(move |(k, v)| {
+            k.ends_with(suffix).then(|| {
+                (
+                    String::from(
+                        &v.file_name_str[prefix.len()..v.file_name_str.len() - suffix.len()],
+                    ),
+                    v,
+                )
+            })
+        });
+        Some(ret)
+    }
+    pub fn retain(&mut self, prefixes: &[&str]) {
+        self.0.retain(|(k, _)| prefixes.iter().any(|prefix| k.starts_with(prefix)));
+    }
+}
 /// The obvious implementation of `SearchPath::files` is a `Vec<PathBuf>`. But
 /// it is searched repeatedly by `find_library_crate`, and the searches involve
 /// checking the prefix and suffix of the filename of each `PathBuf`. This is
@@ -26,8 +62,8 @@ pub struct SearchPath {
 /// UTF-8, and so a non-UTF-8 filename couldn't be one we're looking for.)
 #[derive(Clone, Debug)]
 pub struct SearchPathFile {
-    pub path: PathBuf,
-    pub file_name_str: String,
+    pub path: Arc<Path>,
+    pub file_name_str: Arc<str>,
 }
 
 #[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable, HashStable_Generic)]
@@ -98,20 +134,25 @@ impl SearchPath {
 
     pub fn new(kind: PathKind, dir: PathBuf) -> Self {
         // Get the files within the directory.
-        let files = match std::fs::read_dir(&dir) {
+        let mut files = match std::fs::read_dir(&dir) {
             Ok(files) => files
                 .filter_map(|e| {
                     e.ok().and_then(|e| {
-                        e.file_name().to_str().map(|s| SearchPathFile {
-                            path: e.path(),
-                            file_name_str: s.to_string(),
+                        e.file_name().to_str().map(|s| {
+                            let file_name_str: Arc<str> = s.into();
+                            (Arc::clone(&file_name_str), SearchPathFile {
+                                path: e.path().into(),
+                                file_name_str,
+                            })
                         })
                     })
                 })
                 .collect::<Vec<_>>(),
-            Err(..) => vec![],
-        };
 
+            Err(..) => Default::default(),
+        };
+        files.sort_by(|(lhs, _), (rhs, _)| lhs.cmp(rhs));
+        let files = FilesIndex(files);
         SearchPath { kind, dir, files }
     }
 }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 9d9434a7776..29fabdd1deb 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -16,7 +16,9 @@ use rustc_data_structures::sync::{
 };
 use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
 use rustc_errors::codes::*;
-use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType, stderr_destination};
+use rustc_errors::emitter::{
+    DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination,
+};
 use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
@@ -42,8 +44,9 @@ use crate::config::{
     InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents,
     SwitchWithOptPath,
 };
+use crate::filesearch::FileSearch;
 use crate::parse::{ParseSess, add_feature_diagnostics};
-use crate::search_paths::{PathKind, SearchPath};
+use crate::search_paths::SearchPath;
 use crate::{errors, filesearch, lint};
 
 struct OptimizationFuel {
@@ -216,6 +219,9 @@ pub struct Session {
     /// This is mainly useful for other tools that reads that debuginfo to figure out
     /// how to call the compiler with the same arguments.
     pub expanded_args: Vec<String>,
+
+    target_filesearch: FileSearch,
+    host_filesearch: FileSearch,
 }
 
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
@@ -441,11 +447,11 @@ impl Session {
         format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.as_u64())
     }
 
-    pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
-        filesearch::FileSearch::new(&self.opts.search_paths, &self.target_tlib_path, kind)
+    pub fn target_filesearch(&self) -> &filesearch::FileSearch {
+        &self.target_filesearch
     }
-    pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
-        filesearch::FileSearch::new(&self.opts.search_paths, &self.host_tlib_path, kind)
+    pub fn host_filesearch(&self) -> &filesearch::FileSearch {
+        &self.host_filesearch
     }
 
     /// Returns a list of directories where target-specific tool binaries are located. Some fallback
@@ -966,6 +972,11 @@ fn default_emitter(
                     .macro_backtrace(macro_backtrace)
                     .track_diagnostics(track_diagnostics)
                     .terminal_url(terminal_url)
+                    .theme(if let HumanReadableErrorType::Unicode = kind {
+                        OutputTheme::Unicode
+                    } else {
+                        OutputTheme::Ascii
+                    })
                     .ignored_directories_in_source_blocks(
                         sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(),
                     );
@@ -1104,7 +1115,9 @@ pub fn build_session(
     });
 
     let asm_arch = if target.allow_asm { InlineAsmArch::from_str(&target.arch).ok() } else { None };
-
+    let target_filesearch =
+        filesearch::FileSearch::new(&sopts.search_paths, &target_tlib_path, &target);
+    let host_filesearch = filesearch::FileSearch::new(&sopts.search_paths, &host_tlib_path, &host);
     let sess = Session {
         target,
         host,
@@ -1131,6 +1144,8 @@ pub fn build_session(
         cfg_version,
         using_internal_features,
         expanded_args,
+        target_filesearch,
+        host_filesearch,
     };
 
     validate_commandline_args_with_session_available(&sess);
@@ -1470,6 +1485,11 @@ fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
             let short = kind.short();
             Box::new(
                 HumanEmitter::new(stderr_destination(color_config), fallback_bundle)
+                    .theme(if let HumanReadableErrorType::Unicode = kind {
+                        OutputTheme::Unicode
+                    } else {
+                        OutputTheme::Ascii
+                    })
                     .short_message(short),
             )
         }
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index c57d516fcae..a9ca5dbe509 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1300,7 +1300,6 @@ pub fn register_expn_id(
     let expn_id = ExpnId { krate, local_id };
     HygieneData::with(|hygiene_data| {
         let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
-        debug_assert!(_old_data.is_none() || cfg!(parallel_compiler));
         let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
         debug_assert!(_old_hash.is_none() || _old_hash == Some(hash));
         let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
@@ -1423,18 +1422,7 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
             ctxt_data = old.clone();
         }
 
-        let dummy = std::mem::replace(
-            &mut hygiene_data.syntax_context_data[ctxt.as_u32() as usize],
-            ctxt_data,
-        );
-        if cfg!(not(parallel_compiler)) {
-            // Make sure nothing weird happened while `decode_data` was running.
-            // We used `kw::Empty` for the dummy value and we expect nothing to be
-            // modifying the dummy entry.
-            // This does not hold for the parallel compiler as another thread may
-            // have inserted the fully decoded data.
-            assert_eq!(dummy.dollar_crate_name, kw::Empty);
-        }
+        hygiene_data.syntax_context_data[ctxt.as_u32() as usize] = ctxt_data;
     });
 
     // Mark the context as completed
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 5b1be5bca05..8966cfc9171 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -521,14 +521,6 @@ impl SpanData {
     }
 }
 
-// The interner is pointed to by a thread local value which is only set on the main thread
-// with parallelization is disabled. So we don't allow `Span` to transfer between threads
-// to avoid panics and other errors, even though it would be memory safe to do so.
-#[cfg(not(parallel_compiler))]
-impl !Send for Span {}
-#[cfg(not(parallel_compiler))]
-impl !Sync for Span {}
-
 impl PartialOrd for Span {
     fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
         PartialOrd::partial_cmp(&self.data(), &rhs.data())
@@ -567,12 +559,6 @@ impl Span {
         !self.is_dummy() && sm.is_span_accessible(self)
     }
 
-    /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
-    #[inline]
-    pub fn from_expansion(self) -> bool {
-        !self.ctxt().is_root()
-    }
-
     /// Returns `true` if `span` originates in a derive-macro's expansion.
     pub fn in_derive_expansion(self) -> bool {
         matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
@@ -2223,6 +2209,10 @@ pub fn char_width(ch: char) -> usize {
     }
 }
 
+pub fn str_width(s: &str) -> usize {
+    s.chars().map(char_width).sum()
+}
+
 /// Normalizes the source code and records the normalizations.
 fn normalize_src(src: &mut String) -> Vec<NormalizedPos> {
     let mut normalized_pos = vec![];
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index f36bb38623e..e74a5c2d8fe 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -534,7 +534,7 @@ impl SourceMap {
     /// Extracts the source surrounding the given `Span` using the `extract_source` function. The
     /// extract function takes three arguments: a string slice containing the source, an index in
     /// the slice for the beginning of the span and an index in the slice for the end of the span.
-    fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSnippetError>
+    pub fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSnippetError>
     where
         F: Fn(&str, usize, usize) -> Result<T, SpanSnippetError>,
     {
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index db8170fa6ae..9d6c7d2a42a 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -303,6 +303,13 @@ impl Span {
         }
     }
 
+    /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
+    #[inline]
+    pub fn from_expansion(self) -> bool {
+        // If the span is fully inferred then ctxt > MAX_CTXT
+        self.inline_ctxt().map_or(true, |ctxt| !ctxt.is_root())
+    }
+
     /// Returns `true` if this is a dummy span with any hygienic context.
     #[inline]
     pub fn is_dummy(self) -> bool {
@@ -370,9 +377,10 @@ impl Span {
     pub fn eq_ctxt(self, other: Span) -> bool {
         match (self.inline_ctxt(), other.inline_ctxt()) {
             (Ok(ctxt1), Ok(ctxt2)) => ctxt1 == ctxt2,
-            (Ok(ctxt), Err(index)) | (Err(index), Ok(ctxt)) => {
-                with_span_interner(|interner| ctxt == interner.spans[index].ctxt)
-            }
+            // If `inline_ctxt` returns `Ok` the context is <= MAX_CTXT.
+            // If it returns `Err` the span is fully interned and the context is > MAX_CTXT.
+            // As these do not overlap an `Ok` and `Err` result cannot have an equal context.
+            (Ok(_), Err(_)) | (Err(_), Ok(_)) => false,
             (Err(index1), Err(index2)) => with_span_interner(|interner| {
                 interner.spans[index1].ctxt == interner.spans[index2].ctxt
             }),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c04c793ba46..42c6221dc57 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1568,6 +1568,8 @@ symbols! {
         readonly,
         realloc,
         reason,
+        receiver,
+        receiver_target,
         recursion_limit,
         reexport_test_harness_main,
         ref_pat_eat_one_layer_2024,
@@ -1761,6 +1763,7 @@ symbols! {
         saturating_add,
         saturating_div,
         saturating_sub,
+        search_unbox,
         select_unpredictable,
         self_in_typedefs,
         self_struct_ctor,
diff --git a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
index c0bcc79b5b9..1515d8fe00a 100644
--- a/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/m68k_unknown_linux_gnu.rs
@@ -1,5 +1,5 @@
 use crate::abi::Endian;
-use crate::spec::{Target, TargetOptions, base};
+use crate::spec::{LinkSelfContainedDefault, Target, TargetOptions, base};
 
 pub(crate) fn target() -> Target {
     let mut base = base::linux_gnu::opts();
@@ -17,6 +17,13 @@ pub(crate) fn target() -> Target {
         pointer_width: 32,
         data_layout: "E-m:e-p:32:16:32-i8:8:8-i16:16:16-i32:16:32-n8:16:32-a:0:16-S16".into(),
         arch: "m68k".into(),
-        options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
+        options: TargetOptions {
+            endian: Endian::Big,
+            mcount: "_mcount".into(),
+
+            // LLD currently does not have support for M68k
+            link_self_contained: LinkSelfContainedDefault::False,
+            ..base
+        },
     }
 }
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index c4f9c742650..88536926b11 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -92,6 +92,11 @@ impl Stability {
 //
 // Stabilizing a target feature requires t-lang approval.
 
+// If feature A "implies" feature B, then:
+// - when A gets enabled (via `-Ctarget-feature` or `#[target_feature]`), we also enable B
+// - when B gets disabled (via `-Ctarget-feature`), we also disable A
+//
+// Both of these are also applied transitively.
 type ImpliedFeatures = &'static [&'static str];
 
 const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
@@ -463,13 +468,14 @@ const WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("bulk-memory", Stable, &[]),
     ("exception-handling", Unstable(sym::wasm_target_feature), &[]),
     ("extended-const", Stable, &[]),
-    ("multivalue", Unstable(sym::wasm_target_feature), &[]),
+    ("multivalue", Stable, &[]),
     ("mutable-globals", Stable, &[]),
     ("nontrapping-fptoint", Stable, &[]),
-    ("reference-types", Unstable(sym::wasm_target_feature), &[]),
+    ("reference-types", Stable, &[]),
     ("relaxed-simd", Stable, &["simd128"]),
     ("sign-ext", Stable, &[]),
     ("simd128", Stable, &[]),
+    ("tail-call", Stable, &[]),
     ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]),
     // tidy-alphabetical-end
 ];
@@ -580,9 +586,20 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
 // certain size to have their "proper" ABI on each architecture.
 // Note that they must be kept sorted by vector size.
 const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
-    &[(128, "sse"), (256, "avx"), (512, "avx512f")];
+    &[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
 const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
 
+// We might want to add "helium" too.
+const ARM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")];
+
+const POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "altivec")];
+const WASM_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "simd128")];
+const S390X_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vector")];
+const RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
+    &[/*(64, "zvl64b"), */ (128, "v")];
+// Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
+const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(128, "vis")*/];
+
 impl super::spec::Target {
     pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
         match &*self.arch {
@@ -607,8 +624,15 @@ impl super::spec::Target {
     pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> {
         match &*self.arch {
             "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            "aarch64" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI),
-            // FIXME: add support for non-tier1 architectures
+            "aarch64" | "arm64ec" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "arm" => Some(ARM_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "powerpc" | "powerpc64" => Some(POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "loongarch64" => Some(&[]), // on-stack ABI, so we complain about all by-val vectors
+            "riscv32" | "riscv64" => Some(RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "wasm32" | "wasm64" => Some(WASM_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "s390x" => Some(S390X_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            "sparc" | "sparc64" => Some(SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI),
+            // FIXME: add support for non-tier2 architectures
             _ => None,
         }
     }
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 3ddd23924b5..1ab89ecde7a 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -282,6 +282,8 @@ trait_selection_precise_capturing_new = add a `use<...>` bound to explicitly cap
 
 trait_selection_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate
 
+trait_selection_precise_capturing_overcaptures = use the precise capturing `use<...>` syntax to make the captures explicit
+
 trait_selection_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
 trait_selection_prlf_defined_without_sub = the lifetime defined here...
 trait_selection_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
@@ -455,7 +457,9 @@ trait_selection_unable_to_construct_constant_value = unable to construct a const
 trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}`
     .help = expect either a generic argument name or {"`{Self}`"} as format argument
 
-trait_selection_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable
+trait_selection_warn_removing_apit_params_for_overcapture = you could use a `use<...>` bound to explicitly specify captures, but argument-position `impl Trait`s are not nameable
+
+trait_selection_warn_removing_apit_params_for_undercapture = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable
 
 trait_selection_where_copy_predicates = copy the `where` clause predicates from the trait
 
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 455e3ec751e..afac6fc6004 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,13 +1,14 @@
 use std::path::PathBuf;
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
     EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{Visitor, walk_ty};
 use rustc_hir::{FnRetTy, GenericParamKind};
 use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -1792,6 +1793,138 @@ impl Subdiagnostic for AddPreciseCapturingAndParams {
             self.suggs,
             Applicability::MaybeIncorrect,
         );
-        diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params);
+        diag.span_note(
+            self.apit_spans,
+            fluent::trait_selection_warn_removing_apit_params_for_undercapture,
+        );
+    }
+}
+
+/// Given a set of captured `DefId` for an RPIT (opaque_def_id) and a given
+/// function (fn_def_id), try to suggest adding `+ use<...>` to capture just
+/// the specified parameters. If one of those parameters is an APIT, then try
+/// to suggest turning it into a regular type parameter.
+pub fn impl_trait_overcapture_suggestion<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    opaque_def_id: LocalDefId,
+    fn_def_id: LocalDefId,
+    captured_args: FxIndexSet<DefId>,
+) -> Option<AddPreciseCapturingForOvercapture> {
+    let generics = tcx.generics_of(fn_def_id);
+
+    let mut captured_lifetimes = FxIndexSet::default();
+    let mut captured_non_lifetimes = FxIndexSet::default();
+    let mut synthetics = vec![];
+
+    for arg in captured_args {
+        if tcx.def_kind(arg) == DefKind::LifetimeParam {
+            captured_lifetimes.insert(tcx.item_name(arg));
+        } else {
+            let idx = generics.param_def_id_to_index(tcx, arg).expect("expected arg in scope");
+            let param = generics.param_at(idx as usize, tcx);
+            if param.kind.is_synthetic() {
+                synthetics.push((tcx.def_span(arg), param.name));
+            } else {
+                captured_non_lifetimes.insert(tcx.item_name(arg));
+            }
+        }
+    }
+
+    let mut next_fresh_param = || {
+        ["T", "U", "V", "W", "X", "Y", "A", "B", "C"]
+            .into_iter()
+            .map(Symbol::intern)
+            .chain((0..).map(|i| Symbol::intern(&format!("T{i}"))))
+            .find(|s| captured_non_lifetimes.insert(*s))
+            .unwrap()
+    };
+
+    let mut suggs = vec![];
+    let mut apit_spans = vec![];
+
+    if !synthetics.is_empty() {
+        let mut new_params = String::new();
+        for (i, (span, name)) in synthetics.into_iter().enumerate() {
+            apit_spans.push(span);
+
+            let fresh_param = next_fresh_param();
+
+            // Suggest renaming.
+            suggs.push((span, fresh_param.to_string()));
+
+            // Super jank. Turn `impl Trait` into `T: Trait`.
+            //
+            // This currently involves stripping the `impl` from the name of
+            // the parameter, since APITs are always named after how they are
+            // rendered in the AST. This sucks! But to recreate the bound list
+            // from the APIT itself would be miserable, so we're stuck with
+            // this for now!
+            if i > 0 {
+                new_params += ", ";
+            }
+            let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start();
+            new_params += fresh_param.as_str();
+            new_params += ": ";
+            new_params += name_as_bounds;
+        }
+
+        let Some(generics) = tcx.hir().get_generics(fn_def_id) else {
+            // This shouldn't happen, but don't ICE.
+            return None;
+        };
+
+        // Add generics or concatenate to the end of the list.
+        suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() {
+            (params_span, format!(", {new_params}"))
+        } else {
+            (generics.span, format!("<{new_params}>"))
+        });
+    }
+
+    let concatenated_bounds = captured_lifetimes
+        .into_iter()
+        .chain(captured_non_lifetimes)
+        .map(|sym| sym.to_string())
+        .collect::<Vec<_>>()
+        .join(", ");
+
+    suggs.push((
+        tcx.def_span(opaque_def_id).shrink_to_hi(),
+        format!(" + use<{concatenated_bounds}>"),
+    ));
+
+    Some(AddPreciseCapturingForOvercapture { suggs, apit_spans })
+}
+
+pub struct AddPreciseCapturingForOvercapture {
+    pub suggs: Vec<(Span, String)>,
+    pub apit_spans: Vec<Span>,
+}
+
+impl Subdiagnostic for AddPreciseCapturingForOvercapture {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        _f: &F,
+    ) {
+        let applicability = if self.apit_spans.is_empty() {
+            Applicability::MachineApplicable
+        } else {
+            // If there are APIT that are converted to regular parameters,
+            // then this may make the API turbofishable in ways that were
+            // not intended.
+            Applicability::MaybeIncorrect
+        };
+        diag.multipart_suggestion_verbose(
+            fluent::trait_selection_precise_capturing_overcaptures,
+            self.suggs,
+            applicability,
+        );
+        if !self.apit_spans.is_empty() {
+            diag.span_note(
+                self.apit_spans,
+                fluent::trait_selection_warn_removing_apit_params_for_overcapture,
+            );
+        }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index c53689b211d..2cc787c8bc5 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -15,7 +15,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 use rustc_type_ir::TypingMode;
 use rustc_type_ir::solve::{Certainty, NoSolution};
 
-use crate::traits::specialization_graph;
+use crate::traits::{EvaluateConstErr, specialization_graph};
 
 #[repr(transparent)]
 pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
@@ -77,20 +77,19 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
     }
 
-    fn try_const_eval_resolve(
+    fn evaluate_const(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        unevaluated: ty::UnevaluatedConst<'tcx>,
+        uv: ty::UnevaluatedConst<'tcx>,
     ) -> Option<ty::Const<'tcx>> {
-        use rustc_middle::mir::interpret::ErrorHandled;
-        match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
-            Ok(Ok(val)) => Some(ty::Const::new_value(
-                self.tcx,
-                val,
-                self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
-            )),
-            Ok(Err(_)) | Err(ErrorHandled::TooGeneric(_)) => None,
-            Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())),
+        let ct = ty::Const::new_unevaluated(self.tcx, uv);
+
+        match crate::traits::try_evaluate_const(&self.0, ct, param_env) {
+            Ok(ct) => Some(ct),
+            Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)),
+            Err(
+                EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
+            ) => None,
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 52ba5621d31..103f7c76a86 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -7,7 +7,6 @@ use std::iter;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_data_structures::unord::UnordSet;
 use rustc_infer::infer::DefineOpaqueTypes;
-use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{Region, RegionVid};
 use tracing::debug;
 use ty::TypingMode;
@@ -761,23 +760,20 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     let evaluate = |c: ty::Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
-                            match selcx.infcx.const_eval_resolve(
+                            let ct = super::try_evaluate_const(
+                                selcx.infcx,
+                                c,
                                 obligation.param_env,
-                                unevaluated,
-                                obligation.cause.span,
-                            ) {
-                                Ok(Ok(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))),
-                                Ok(Err(_)) => {
-                                    let tcx = self.tcx;
-                                    let reported =
-                                        tcx.dcx().emit_err(UnableToConstructConstantValue {
-                                            span: tcx.def_span(unevaluated.def),
-                                            unevaluated,
-                                        });
-                                    Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def)))
-                                }
-                                Err(err) => Err(err),
+                            );
+
+                            if let Err(EvaluateConstErr::InvalidConstParamTy(_)) = ct {
+                                self.tcx.dcx().emit_err(UnableToConstructConstantValue {
+                                    span: self.tcx.def_span(unevaluated.def),
+                                    unevaluated,
+                                });
                             }
+
+                            ct
                         } else {
                             Ok(c)
                         }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 1be3c964454..15eb5d74cbf 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -12,13 +12,13 @@
 use rustc_hir::def::DefKind;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::bug;
-use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
+use super::EvaluateConstErr;
 use crate::traits::ObligationCtxt;
 
 /// Check if a given constant can be evaluated.
@@ -68,16 +68,18 @@ pub fn is_const_evaluatable<'tcx>(
                 // here.
                 tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported");
             }
-            ty::ConstKind::Unevaluated(uv) => {
-                let concrete = infcx.const_eval_resolve(param_env, uv, span);
-                match concrete {
-                    Err(ErrorHandled::TooGeneric(_)) => {
+            ty::ConstKind::Unevaluated(_) => {
+                match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
+                    Err(EvaluateConstErr::HasGenericsOrInfers) => {
                         Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug(
                             span,
                             "Missing value for constant, but no error reported?",
                         )))
                     }
-                    Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
+                    Err(
+                        EvaluateConstErr::EvaluationFailure(e)
+                        | EvaluateConstErr::InvalidConstParamTy(e),
+                    ) => Err(NotConstEvaluatable::Error(e.into())),
                     Ok(_) => Ok(()),
                 }
             }
@@ -92,16 +94,7 @@ pub fn is_const_evaluatable<'tcx>(
             _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
         };
 
-        // FIXME: We should only try to evaluate a given constant here if it is fully concrete
-        // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
-        //
-        // We previously did not check this, so we only emit a future compat warning if
-        // const evaluation succeeds and the given constant is still polymorphic for now
-        // and hopefully soon change this to an error.
-        //
-        // See #74595 for more details about this.
-        let concrete = infcx.const_eval_resolve(param_env, uv, span);
-        match concrete {
+        match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) {
             // If we're evaluating a generic foreign constant, under a nightly compiler while
             // the current crate does not enable `feature(generic_const_exprs)`, abort
             // compilation with a useful error.
@@ -130,7 +123,7 @@ pub fn is_const_evaluatable<'tcx>(
                     .emit()
             }
 
-            Err(ErrorHandled::TooGeneric(_)) => {
+            Err(EvaluateConstErr::HasGenericsOrInfers) => {
                 let err = if uv.has_non_region_infer() {
                     NotConstEvaluatable::MentionsInfer
                 } else if uv.has_non_region_param() {
@@ -145,7 +138,9 @@ pub fn is_const_evaluatable<'tcx>(
 
                 Err(err)
             }
-            Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
+            Err(
+                EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e),
+            ) => Err(NotConstEvaluatable::Error(e.into())),
             Ok(_) => Ok(()),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 21141f6e18f..2ec5f0d2249 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -10,7 +10,6 @@ use rustc_infer::traits::{
     TraitEngine,
 };
 use rustc_middle::bug;
-use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
@@ -26,6 +25,7 @@ use super::{
 };
 use crate::error_reporting::InferCtxtErrorExt;
 use crate::infer::{InferCtxt, TyOrConstInferVar};
+use crate::traits::EvaluateConstErr;
 use crate::traits::normalize::normalize_with_depth_to;
 use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -664,23 +664,25 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
 
                     let mut evaluate = |c: Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
-                            match self.selcx.infcx.try_const_eval_resolve(
+                            match super::try_evaluate_const(
+                                self.selcx.infcx,
+                                c,
                                 obligation.param_env,
-                                unevaluated,
-                                obligation.cause.span,
                             ) {
                                 Ok(val) => Ok(val),
-                                Err(e) => {
-                                    match e {
-                                        ErrorHandled::TooGeneric(..) => {
-                                            stalled_on.extend(unevaluated.args.iter().filter_map(
-                                                TyOrConstInferVar::maybe_from_generic_arg,
-                                            ));
-                                        }
-                                        _ => {}
-                                    }
-                                    Err(e)
+                                e @ Err(EvaluateConstErr::HasGenericsOrInfers) => {
+                                    stalled_on.extend(
+                                        unevaluated
+                                            .args
+                                            .iter()
+                                            .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+                                    );
+                                    e
                                 }
+                                e @ Err(
+                                    EvaluateConstErr::EvaluationFailure(_)
+                                    | EvaluateConstErr::InvalidConstParamTy(_),
+                                ) => e,
                             }
                         } else {
                             Ok(c)
@@ -707,14 +709,20 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                                 }
                             }
                         }
-                        (Err(ErrorHandled::Reported(reported, _)), _)
-                        | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error(
-                            FulfillmentErrorCode::Select(SelectionError::NotConstEvaluatable(
-                                NotConstEvaluatable::Error(reported.into()),
-                            )),
-                        ),
-                        (Err(ErrorHandled::TooGeneric(_)), _)
-                        | (_, Err(ErrorHandled::TooGeneric(_))) => {
+                        (Err(EvaluateConstErr::InvalidConstParamTy(e)), _)
+                        | (_, Err(EvaluateConstErr::InvalidConstParamTy(e))) => {
+                            ProcessResult::Error(FulfillmentErrorCode::Select(
+                                SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
+                            ))
+                        }
+                        (Err(EvaluateConstErr::EvaluationFailure(e)), _)
+                        | (_, Err(EvaluateConstErr::EvaluationFailure(e))) => {
+                            ProcessResult::Error(FulfillmentErrorCode::Select(
+                                SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(e)),
+                            ))
+                        }
+                        (Err(EvaluateConstErr::HasGenericsOrInfers), _)
+                        | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
                             if c1.has_non_region_infer() || c2.has_non_region_infer() {
                                 ProcessResult::Unchanged
                             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 436c0fabd29..fe90066b4e7 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -27,6 +27,7 @@ use std::fmt::Debug;
 use std::ops::ControlFlow;
 
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::DefKind;
 pub use rustc_infer::traits::*;
 use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
@@ -34,11 +35,11 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode,
-    Upcast,
+    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
+    TypeSuperVisitable, TypingMode, Upcast,
 };
-use rustc_span::Span;
 use rustc_span::def_id::DefId;
+use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
 pub use self::coherence::{
@@ -366,11 +367,23 @@ pub fn normalize_param_env_or_error<'tcx>(
                     if c.has_escaping_bound_vars() {
                         return ty::Const::new_misc_error(self.0);
                     }
+
                     // While it is pretty sus to be evaluating things with an empty param env, it
                     // should actually be okay since without `feature(generic_const_exprs)` the only
                     // const arguments that have a non-empty param env are array repeat counts. These
                     // do not appear in the type system though.
-                    c.normalize_internal(self.0, ty::ParamEnv::empty())
+                    if let ty::ConstKind::Unevaluated(uv) = c.kind()
+                        && self.0.def_kind(uv.def) == DefKind::AnonConst
+                    {
+                        let infcx = self.0.infer_ctxt().build(TypingMode::non_body_analysis());
+                        let c = evaluate_const(&infcx, c, ty::ParamEnv::empty());
+                        // We should never wind up with any `infcx` local state when normalizing anon consts
+                        // under min const generics.
+                        assert!(!c.has_infer() && !c.has_placeholders());
+                        return c;
+                    }
+
+                    c
                 }
             }
 
@@ -474,6 +487,210 @@ pub fn normalize_param_env_or_error<'tcx>(
     ty::ParamEnv::new(tcx.mk_clauses(&predicates), unnormalized_env.reveal())
 }
 
+#[derive(Debug)]
+pub enum EvaluateConstErr {
+    /// The constant being evaluated was either a generic parameter or inference variable, *or*,
+    /// some unevaluated constant with either generic parameters or inference variables in its
+    /// generic arguments.
+    HasGenericsOrInfers,
+    /// The type this constant evalauted to is not valid for use in const generics. This should
+    /// always result in an error when checking the constant is correctly typed for the parameter
+    /// it is an argument to, so a bug is delayed when encountering this.
+    InvalidConstParamTy(ErrorGuaranteed),
+    /// CTFE failed to evaluate the constant in some unrecoverable way (e.g. encountered a `panic!`).
+    /// This is also used when the constant was already tainted by error.
+    EvaluationFailure(ErrorGuaranteed),
+}
+
+// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
+// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own
+// normalization scheme
+/// Evaluates a type system constant returning a `ConstKind::Error` in cases where CTFE failed and
+/// returning the passed in constant if it was not fully concrete (i.e. depended on generic parameters
+/// or inference variables)
+///
+/// You should not call this function unless you are implementing normalization itself. Prefer to use
+/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`.
+pub fn evaluate_const<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ct: ty::Const<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> ty::Const<'tcx> {
+    match try_evaluate_const(infcx, ct, param_env) {
+        Ok(ct) => ct,
+        Err(EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e)) => {
+            ty::Const::new_error(infcx.tcx, e)
+        }
+        Err(EvaluateConstErr::HasGenericsOrInfers) => ct,
+    }
+}
+
+// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
+// FIXME(generic_const_exprs): Consider accepting a `ty::UnevaluatedConst` when we are not rolling our own
+// normalization scheme
+/// Evaluates a type system constant making sure to not allow constants that depend on generic parameters
+/// or inference variables to succeed in evaluating.
+///
+/// You should not call this function unless you are implementing normalization itself. Prefer to use
+/// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`.
+#[instrument(level = "debug", skip(infcx), ret)]
+pub fn try_evaluate_const<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    ct: ty::Const<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> Result<ty::Const<'tcx>, EvaluateConstErr> {
+    let tcx = infcx.tcx;
+    let ct = infcx.resolve_vars_if_possible(ct);
+    debug!(?ct);
+
+    match ct.kind() {
+        ty::ConstKind::Value(..) => Ok(ct),
+        ty::ConstKind::Error(e) => Err(EvaluateConstErr::EvaluationFailure(e)),
+        ty::ConstKind::Param(_)
+        | ty::ConstKind::Infer(_)
+        | ty::ConstKind::Bound(_, _)
+        | ty::ConstKind::Placeholder(_)
+        | ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers),
+        ty::ConstKind::Unevaluated(uv) => {
+            // Postpone evaluation of constants that depend on generic parameters or inference variables.
+            let (args, param_env) = if tcx.features().generic_const_exprs()
+                && uv.has_non_region_infer()
+            {
+                // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
+                // inference variables and generic parameters to show up in `ty::Const` even though the anon const
+                // does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
+                match tcx.thir_abstract_const(uv.def) {
+                    Ok(Some(ct)) => {
+                        let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
+                        if let Err(e) = ct.error_reported() {
+                            return Err(EvaluateConstErr::EvaluationFailure(e));
+                        } else if ct.has_non_region_infer() || ct.has_non_region_param() {
+                            // If the anon const *does* actually use generic parameters or inference variables from
+                            // the generic arguments provided for it, then we should *not* attempt to evaluate it.
+                            return Err(EvaluateConstErr::HasGenericsOrInfers);
+                        } else {
+                            (replace_param_and_infer_args_with_placeholder(tcx, uv.args), param_env)
+                        }
+                    }
+                    Err(_) | Ok(None) => {
+                        let args = GenericArgs::identity_for_item(tcx, uv.def);
+                        let param_env = tcx.param_env(uv.def);
+                        (args, param_env)
+                    }
+                }
+            } else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() {
+                // FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
+                //
+                // Diagnostics will sometimes replace the identity args of anon consts in
+                // array repeat expr counts with inference variables so we have to handle this
+                // even though it is not something we should ever actually encounter.
+                //
+                // Array repeat expr counts are allowed to syntactically use generic parameters
+                // but must not actually depend on them in order to evalaute succesfully. This means
+                // that it is actually fine to evalaute them in their own environment rather than with
+                // the actually provided generic arguments.
+                tcx.dcx().delayed_bug(
+                    "Encountered anon const with inference variable args but no error reported",
+                );
+
+                let args = GenericArgs::identity_for_item(tcx, uv.def);
+                let param_env = tcx.param_env(uv.def);
+                (args, param_env)
+            } else {
+                // FIXME: This codepath is reachable under `associated_const_equality` and in the
+                // future will be reachable by `min_generic_const_args`. We should handle inference
+                // variables and generic parameters properly instead of doing nothing.
+                (uv.args, param_env)
+            };
+            let uv = ty::UnevaluatedConst::new(uv.def, args);
+
+            // It's not *technically* correct to be revealing opaque types here as we could still be
+            // before borrowchecking. However, CTFE itself uses `Reveal::All` unconditionally even during
+            // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821). As a result we
+            // always use a revealed env when resolving the instance to evaluate.
+            //
+            // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
+            // instead of having this logic here
+            let env = tcx.erase_regions(param_env).with_reveal_all_normalized(tcx);
+            let erased_uv = tcx.erase_regions(uv);
+
+            use rustc_middle::mir::interpret::ErrorHandled;
+            match tcx.const_eval_resolve_for_typeck(env, erased_uv, DUMMY_SP) {
+                Ok(Ok(val)) => Ok(ty::Const::new_value(
+                    tcx,
+                    val,
+                    tcx.type_of(uv.def).instantiate(tcx, uv.args),
+                )),
+                Ok(Err(_)) => {
+                    let e = tcx.dcx().delayed_bug(
+                        "Type system constant with non valtree'able type evaluated but no error emitted",
+                    );
+                    Err(EvaluateConstErr::InvalidConstParamTy(e))
+                }
+                Err(ErrorHandled::Reported(info, _)) => {
+                    Err(EvaluateConstErr::EvaluationFailure(info.into()))
+                }
+                Err(ErrorHandled::TooGeneric(_)) => Err(EvaluateConstErr::HasGenericsOrInfers),
+            }
+        }
+    }
+}
+
+/// Replaces args that reference param or infer variables with suitable
+/// placeholders. This function is meant to remove these param and infer
+/// args when they're not actually needed to evaluate a constant.
+fn replace_param_and_infer_args_with_placeholder<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    args: GenericArgsRef<'tcx>,
+) -> GenericArgsRef<'tcx> {
+    struct ReplaceParamAndInferWithPlaceholder<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        idx: u32,
+    }
+
+    impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
+        fn cx(&self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+            if let ty::Infer(_) = t.kind() {
+                let idx = {
+                    let idx = self.idx;
+                    self.idx += 1;
+                    idx
+                };
+                Ty::new_placeholder(self.tcx, ty::PlaceholderType {
+                    universe: ty::UniverseIndex::ROOT,
+                    bound: ty::BoundTy {
+                        var: ty::BoundVar::from_u32(idx),
+                        kind: ty::BoundTyKind::Anon,
+                    },
+                })
+            } else {
+                t.super_fold_with(self)
+            }
+        }
+
+        fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+            if let ty::ConstKind::Infer(_) = c.kind() {
+                ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst {
+                    universe: ty::UniverseIndex::ROOT,
+                    bound: ty::BoundVar::from_u32({
+                        let idx = self.idx;
+                        self.idx += 1;
+                        idx
+                    }),
+                })
+            } else {
+                c.super_fold_with(self)
+            }
+        }
+    }
+
+    args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
+}
+
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
 /// hold. Used when creating vtables to check for unsatisfiable methods. This should not be
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 954dfe93387..5c38d162712 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -418,8 +418,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
                 self.selcx.infcx,
                 &mut self.universes,
                 constant,
-                |constant| constant.normalize_internal(tcx, self.param_env),
+                |constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env),
             )
+            .super_fold_with(self)
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index a8d701a750d..5f89894fb82 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -342,7 +342,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
             self.infcx,
             &mut self.universes,
             constant,
-            |constant| constant.normalize_internal(self.infcx.tcx, self.param_env),
+            |constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
         );
         debug!(?constant, ?self.param_env);
         constant.try_super_fold_with(self)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 041cfc21267..712856e6a8f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -403,7 +403,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let mut assume = predicate.trait_ref.args.const_at(2);
         // FIXME(min_generic_const_exprs): We should shallowly normalize this.
         if self.tcx().features().generic_const_exprs() {
-            assume = assume.normalize_internal(self.tcx(), obligation.param_env);
+            assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
         }
         let Some(assume) =
             rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index cffb62ab559..5b4e895189b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -22,7 +22,6 @@ use rustc_infer::infer::relate::TypeRelation;
 use rustc_infer::traits::{PredicateObligations, TraitObligation};
 use rustc_middle::bug;
 use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds};
-use rustc_middle::mir::interpret::ErrorHandled;
 pub use rustc_middle::traits::select::*;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::TypeErrorToStringExt;
@@ -50,7 +49,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::solve::InferCtxtSelectExt as _;
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
-use crate::traits::{ProjectionCacheKey, Unimplemented, effects};
+use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects};
 
 mod _match;
 mod candidate_assembly;
@@ -931,11 +930,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
 
                     let evaluate = |c: ty::Const<'tcx>| {
-                        if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
-                            match self.infcx.try_const_eval_resolve(
+                        if let ty::ConstKind::Unevaluated(_) = c.kind() {
+                            match crate::traits::try_evaluate_const(
+                                self.infcx,
+                                c,
                                 obligation.param_env,
-                                unevaluated,
-                                obligation.cause.span,
                             ) {
                                 Ok(val) => Ok(val),
                                 Err(e) => Err(e),
@@ -961,10 +960,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 Err(_) => Ok(EvaluatedToErr),
                             }
                         }
-                        (Err(ErrorHandled::Reported(..)), _)
-                        | (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr),
-                        (Err(ErrorHandled::TooGeneric(..)), _)
-                        | (_, Err(ErrorHandled::TooGeneric(..))) => {
+                        (Err(EvaluateConstErr::InvalidConstParamTy(..)), _)
+                        | (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr),
+                        (Err(EvaluateConstErr::EvaluationFailure(..)), _)
+                        | (_, Err(EvaluateConstErr::EvaluationFailure(..))) => Ok(EvaluatedToErr),
+                        (Err(EvaluateConstErr::HasGenericsOrInfers), _)
+                        | (_, Err(EvaluateConstErr::HasGenericsOrInfers)) => {
                             if c1.has_non_region_infer() || c2.has_non_region_infer() {
                                 Ok(EvaluatedToAmbig)
                             } else {
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index 23b5f62b5ca..f8e8f2176c1 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -83,7 +83,7 @@ impl<'tcx> At<'_, 'tcx> {
 
             Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
         } else if self.infcx.tcx.features().generic_const_exprs() {
-            Ok(ct.normalize_internal(self.infcx.tcx, self.param_env))
+            Ok(super::evaluate_const(&self.infcx, ct, self.param_env))
         } else {
             Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
         }