about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2025-06-07 05:01:19 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2025-06-07 05:01:19 +0000
commit4c4904b54a2d9db26e8a164b8388c586c3c5fd16 (patch)
tree432eb7bbe6cc257bcfdc879c7ab5dd0ed4603782
parentcf5aea57cc741ad10a80841a3ec2fde52a939279 (diff)
parent775e0c8aeb8f63192854b27156f8b05a06b51814 (diff)
downloadrust-4c4904b54a2d9db26e8a164b8388c586c3c5fd16.tar.gz
rust-4c4904b54a2d9db26e8a164b8388c586c3c5fd16.zip
Merge from rustc
-rw-r--r--compiler/rustc_abi/src/canon_abi.rs19
-rw-r--r--compiler/rustc_abi/src/layout/ty.rs11
-rw-r--r--compiler/rustc_ast/src/ast.rs9
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs2
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs194
-rw-r--r--compiler/rustc_ast/src/ptr.rs210
-rw-r--r--compiler/rustc_ast/src/visit.rs435
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs72
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs22
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/pattern_type.rs20
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs36
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/size_of_val.rs3
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs6
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs18
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs21
-rw-r--r--compiler/rustc_const_eval/src/util/caller_location.rs14
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0783.md2
-rw-r--r--compiler/rustc_expand/src/base.rs2
-rw-r--r--compiler/rustc_expand/src/expand.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl19
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs56
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/inline_asm.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/naked_functions.rs (renamed from compiler/rustc_passes/src/naked_functions.rs)77
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs1
-rw-r--r--compiler/rustc_lexer/src/cursor.rs2
-rw-r--r--compiler/rustc_lexer/src/lib.rs16
-rw-r--r--compiler/rustc_lint/src/builtin.rs5
-rw-r--r--compiler/rustc_middle/src/error.rs2
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs2
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs6
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs14
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs2
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs2
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/into.rs2
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/test.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs7
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs31
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/drop.rs39
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs7
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drop.rs13
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs8
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs12
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs4
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs8
-rw-r--r--compiler/rustc_parse/src/parser/item.rs4
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs2
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs26
-rw-r--r--compiler/rustc_passes/messages.ftl19
-rw-r--r--compiler/rustc_passes/src/errors.rs52
-rw-r--r--compiler/rustc_passes/src/lang_items.rs20
-rw-r--r--compiler/rustc_passes/src/lib.rs4
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs53
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs9
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs6
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs4
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs13
-rw-r--r--compiler/rustc_ty_utils/src/common_traits.rs3
-rw-r--r--compiler/rustc_ty_utils/src/structural_match.rs3
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs2
-rw-r--r--library/alloc/src/slice.rs2
-rw-r--r--library/alloc/src/str.rs4
-rw-r--r--library/core/src/fmt/num.rs4
-rw-r--r--library/core/src/num/nonzero.rs33
-rw-r--r--library/std/src/ffi/mod.rs2
-rw-r--r--library/std/src/fs.rs36
-rw-r--r--library/std/src/io/mod.rs26
-rw-r--r--library/std/src/keyword_docs.rs27
-rw-r--r--library/std/src/sys/fs/hermit.rs4
-rw-r--r--library/std/src/sys/fs/solid.rs4
-rw-r--r--library/std/src/sys/fs/uefi.rs4
-rw-r--r--library/std/src/sys/fs/unix.rs9
-rw-r--r--library/std/src/sys/fs/unsupported.rs4
-rw-r--r--library/std/src/sys/fs/wasi.rs4
-rw-r--r--library/std/src/sys/fs/windows.rs8
-rw-r--r--library/std/src/sys/pal/unix/os.rs2
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt1
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs3
-rw-r--r--src/bootstrap/src/core/config/config.rs2104
-rw-r--r--src/bootstrap/src/core/config/flags.rs3
-rw-r--r--src/bootstrap/src/core/config/mod.rs411
-rw-r--r--src/bootstrap/src/core/config/target_selection.rs147
-rw-r--r--src/bootstrap/src/core/config/tests.rs6
-rw-r--r--src/bootstrap/src/core/config/toml/build.rs72
-rw-r--r--src/bootstrap/src/core/config/toml/change_id.rs34
-rw-r--r--src/bootstrap/src/core/config/toml/dist.rs52
-rw-r--r--src/bootstrap/src/core/config/toml/gcc.rs34
-rw-r--r--src/bootstrap/src/core/config/toml/install.rs43
-rw-r--r--src/bootstrap/src/core/config/toml/llvm.rs284
-rw-r--r--src/bootstrap/src/core/config/toml/mod.rs184
-rw-r--r--src/bootstrap/src/core/config/toml/rust.rs664
-rw-r--r--src/bootstrap/src/core/config/toml/target.rs174
-rw-r--r--src/bootstrap/src/core/download.rs2
-rw-r--r--src/librustdoc/clean/mod.rs150
-rw-r--r--src/librustdoc/clean/simplify.rs7
-rw-r--r--src/librustdoc/clean/types.rs14
-rw-r--r--src/librustdoc/html/format.rs45
-rw-r--r--src/librustdoc/json/conversions.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/miri/src/eval.rs8
-rw-r--r--src/tools/miri/src/helpers.rs7
-rw-r--r--src/tools/miri/src/shims/backtrace.rs12
-rw-r--r--src/tools/miri/src/shims/panic.rs2
-rw-r--r--src/tools/miri/src/shims/unix/env.rs7
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/sync.rs8
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/epoll.rs6
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs6
-rw-r--r--src/tools/rustfmt/src/modules.rs2
-rw-r--r--src/tools/rustfmt/src/parse/macros/cfg_if.rs2
-rw-r--r--tests/rustdoc/inline_cross/assoc-const-equality.rs1
-rw-r--r--tests/ui/borrowck/rvalue-borrow-scope-error.rs (renamed from tests/ui/cleanup-rvalue-scopes-cf.rs)14
-rw-r--r--tests/ui/borrowck/rvalue-borrow-scope-error.stderr (renamed from tests/ui/cleanup-rvalue-scopes-cf.stderr)14
-rw-r--r--tests/ui/cleanup-rvalue-scopes.rs128
-rw-r--r--tests/ui/close-over-big-then-small-data.rs39
-rw-r--r--tests/ui/const-generics/early/invalid-const-arguments.stderr10
-rw-r--r--tests/ui/const-generics/kind_mismatch.stderr20
-rw-r--r--tests/ui/diagnostic-width/command-line-error-format-human.rs (renamed from tests/ui/command-line-diagnostics.rs)3
-rw-r--r--tests/ui/diagnostic-width/command-line-error-format-human.stderr (renamed from tests/ui/command-line-diagnostics.stderr)2
-rw-r--r--tests/ui/drop/issue-2735-2.rs13
-rw-r--r--tests/ui/drop/issue-2735-3.rs11
-rw-r--r--tests/ui/drop/issue-2735.rs12
-rw-r--r--tests/ui/drop/issue-979.rs11
-rw-r--r--tests/ui/lang-items/lang-item-generic-requirements.rs3
-rw-r--r--tests/ui/lang-items/lang-item-generic-requirements.stderr8
-rw-r--r--tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs (renamed from tests/ui/cleanup-shortcircuit.rs)9
-rw-r--r--tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs104
-rw-r--r--tests/ui/panics/rvalue-cleanup-during-box-panic.rs (renamed from tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs)10
-rw-r--r--tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr7
-rw-r--r--triagebot.toml1
198 files changed, 3562 insertions, 3660 deletions
diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs
index 2cf7648a859..03eeb645489 100644
--- a/compiler/rustc_abi/src/canon_abi.rs
+++ b/compiler/rustc_abi/src/canon_abi.rs
@@ -50,18 +50,10 @@ pub enum CanonAbi {
 
 impl fmt::Display for CanonAbi {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.to_erased_extern_abi().as_str().fmt(f)
-    }
-}
-
-impl CanonAbi {
-    /// convert to the ExternAbi that *shares a string* with this CanonAbi
-    ///
-    /// A target-insensitive mapping of CanonAbi to ExternAbi, convenient for "forwarding" impls.
-    /// Importantly, the set of CanonAbi values is a logical *subset* of ExternAbi values,
-    /// so this is injective: if you take an ExternAbi to a CanonAbi and back, you have lost data.
-    const fn to_erased_extern_abi(self) -> ExternAbi {
-        match self {
+        // convert to the ExternAbi that *shares a string* with this CanonAbi.
+        // FIXME: ideally we'd avoid printing `CanonAbi`, and preserve `ExternAbi` everywhere
+        // that we need to generate error messages.
+        let erased_abi = match self {
             CanonAbi::C => ExternAbi::C { unwind: false },
             CanonAbi::Rust => ExternAbi::Rust,
             CanonAbi::RustCold => ExternAbi::RustCold,
@@ -87,7 +79,8 @@ impl CanonAbi {
                 X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false },
                 X86Call::Win64 => ExternAbi::Win64 { unwind: false },
             },
-        }
+        };
+        erased_abi.as_str().fmt(f)
     }
 }
 
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index 4f43c0e6f8e..b5f93351d68 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -39,6 +39,13 @@ rustc_index::newtype_index! {
     pub struct FieldIdx {}
 }
 
+impl FieldIdx {
+    /// The second field, at index 1.
+    ///
+    /// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs.
+    pub const ONE: FieldIdx = FieldIdx::from_u32(1);
+}
+
 rustc_index::newtype_index! {
     /// The *source-order* index of a variant in a type.
     ///
@@ -274,7 +281,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
 
     /// Finds the one field that is not a 1-ZST.
     /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
-    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)>
+    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
     where
         Ty: TyAbiInterface<'a, C> + Copy,
     {
@@ -288,7 +295,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
                 // More than one non-1-ZST field.
                 return None;
             }
-            found = Some((field_idx, field));
+            found = Some((FieldIdx::from_usize(field_idx), field));
         }
         found
     }
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index c9a8adec31a..cf40c3f7f6f 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1119,10 +1119,9 @@ impl Stmt {
     pub fn add_trailing_semicolon(mut self) -> Self {
         self.kind = match self.kind {
             StmtKind::Expr(expr) => StmtKind::Semi(expr),
-            StmtKind::MacCall(mac) => {
-                StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs, tokens }| {
-                    MacCallStmt { mac, style: MacStmtStyle::Semicolon, attrs, tokens }
-                }))
+            StmtKind::MacCall(mut mac) => {
+                mac.style = MacStmtStyle::Semicolon;
+                StmtKind::MacCall(mac)
             }
             kind => kind,
         };
@@ -1724,7 +1723,7 @@ pub enum ExprKind {
     ///
     /// Usually not written directly in user code but
     /// indirectly via the macro `core::mem::offset_of!(...)`.
-    OffsetOf(P<Ty>, P<[Ident]>),
+    OffsetOf(P<Ty>, Vec<Ident>),
 
     /// A macro invocation; pre-expansion.
     MacCall(P<MacCall>),
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index f165c4ddcdd..621e3042b62 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -63,7 +63,7 @@ impl Attribute {
 
     pub fn unwrap_normal_item(self) -> AttrItem {
         match self.kind {
-            AttrKind::Normal(normal) => normal.into_inner().item,
+            AttrKind::Normal(normal) => normal.item,
             AttrKind::DocComment(..) => panic!("unexpected doc comment"),
         }
     }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 08726ee6b41..77cbdde61a4 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -208,11 +208,7 @@ pub trait MutVisitor: Sized {
     }
 
     fn visit_ident(&mut self, i: &mut Ident) {
-        walk_ident(self, i);
-    }
-
-    fn visit_modifiers(&mut self, m: &mut TraitBoundModifiers) {
-        walk_modifiers(self, m);
+        self.visit_span(&mut i.span);
     }
 
     fn visit_path(&mut self, p: &mut Path) {
@@ -367,6 +363,33 @@ pub trait MutVisitor: Sized {
 
 super::common_visitor_and_walkers!((mut) MutVisitor);
 
+macro_rules! generate_flat_map_visitor_fns {
+    ($($name:ident, $Ty:ty, $flat_map_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => {
+        $(
+            fn $name<V: MutVisitor>(
+                vis: &mut V,
+                values: &mut ThinVec<$Ty>,
+                $(
+                    $param: $ParamTy,
+                )*
+            ) {
+                values.flat_map_in_place(|value| vis.$flat_map_fn(value$(,$param)*));
+            }
+        )+
+    }
+}
+
+generate_flat_map_visitor_fns! {
+    visit_items, P<Item>, flat_map_item;
+    visit_foreign_items, P<ForeignItem>, flat_map_foreign_item;
+    visit_generic_params, GenericParam, flat_map_generic_param;
+    visit_stmts, Stmt, flat_map_stmt;
+    visit_exprs, P<Expr>, filter_map_expr;
+    visit_pat_fields, PatField, flat_map_pat_field;
+    visit_variants, Variant, flat_map_variant;
+    visit_assoc_items, P<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt;
+}
+
 #[inline]
 fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F)
 where
@@ -403,15 +426,6 @@ fn visit_attrs<T: MutVisitor>(vis: &mut T, attrs: &mut AttrVec) {
     }
 }
 
-#[allow(unused)]
-fn visit_exprs<T: MutVisitor>(vis: &mut T, exprs: &mut Vec<P<Expr>>) {
-    exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr))
-}
-
-fn visit_thin_exprs<T: MutVisitor>(vis: &mut T, exprs: &mut ThinVec<P<Expr>>) {
-    exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr))
-}
-
 fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) {
     match args {
         AttrArgs::Empty => {}
@@ -430,15 +444,6 @@ fn visit_delim_args<T: MutVisitor>(vis: &mut T, args: &mut DelimArgs) {
     vis.visit_span(close);
 }
 
-pub fn walk_pat_field<T: MutVisitor>(vis: &mut T, fp: &mut PatField) {
-    let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = fp;
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    vis.visit_ident(ident);
-    vis.visit_pat(pat);
-    vis.visit_span(span);
-}
-
 pub fn walk_flat_map_pat_field<T: MutVisitor>(
     vis: &mut T,
     mut fp: PatField,
@@ -447,21 +452,13 @@ pub fn walk_flat_map_pat_field<T: MutVisitor>(
     smallvec![fp]
 }
 
-fn walk_use_tree<T: MutVisitor>(vis: &mut T, use_tree: &mut UseTree) {
-    let UseTree { prefix, kind, span } = use_tree;
-    vis.visit_path(prefix);
-    match kind {
-        UseTreeKind::Simple(rename) => visit_opt(rename, |rename| vis.visit_ident(rename)),
-        UseTreeKind::Nested { items, span } => {
-            for (tree, id) in items {
-                vis.visit_id(id);
-                vis.visit_use_tree(tree);
-            }
-            vis.visit_span(span);
-        }
-        UseTreeKind::Glob => {}
-    }
-    vis.visit_span(span);
+fn visit_nested_use_tree<V: MutVisitor>(
+    vis: &mut V,
+    nested_tree: &mut UseTree,
+    nested_id: &mut NodeId,
+) {
+    vis.visit_id(nested_id);
+    vis.visit_use_tree(nested_tree);
 }
 
 pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) {
@@ -498,31 +495,6 @@ fn walk_assoc_item_constraint<T: MutVisitor>(
     vis.visit_span(span);
 }
 
-pub fn walk_ty_pat<T: MutVisitor>(vis: &mut T, ty: &mut TyPat) {
-    let TyPat { id, kind, span, tokens: _ } = ty;
-    vis.visit_id(id);
-    match kind {
-        TyPatKind::Range(start, end, _include_end) => {
-            visit_opt(start, |c| vis.visit_anon_const(c));
-            visit_opt(end, |c| vis.visit_anon_const(c));
-        }
-        TyPatKind::Or(variants) => visit_thin_vec(variants, |p| vis.visit_ty_pat(p)),
-        TyPatKind::Err(_) => {}
-    }
-    vis.visit_span(span);
-}
-
-pub fn walk_variant<T: MutVisitor>(visitor: &mut T, variant: &mut Variant) {
-    let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant;
-    visitor.visit_id(id);
-    visit_attrs(visitor, attrs);
-    visitor.visit_vis(vis);
-    visitor.visit_ident(ident);
-    visitor.visit_variant_data(data);
-    visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr));
-    visitor.visit_span(span);
-}
-
 pub fn walk_flat_map_variant<T: MutVisitor>(
     vis: &mut T,
     mut variant: Variant,
@@ -531,25 +503,6 @@ pub fn walk_flat_map_variant<T: MutVisitor>(
     smallvec![variant]
 }
 
-fn walk_ident<T: MutVisitor>(vis: &mut T, Ident { name: _, span }: &mut Ident) {
-    vis.visit_span(span);
-}
-
-fn walk_path<T: MutVisitor>(vis: &mut T, Path { segments, span, tokens: _ }: &mut Path) {
-    for segment in segments {
-        vis.visit_path_segment(segment);
-    }
-    vis.visit_span(span);
-}
-
-fn walk_qself<T: MutVisitor>(vis: &mut T, qself: &mut Option<P<QSelf>>) {
-    visit_opt(qself, |qself| {
-        let QSelf { ty, path_span, position: _ } = &mut **qself;
-        vis.visit_ty(ty);
-        vis.visit_span(path_span);
-    })
-}
-
 fn walk_generic_args<T: MutVisitor>(vis: &mut T, generic_args: &mut GenericArgs) {
     match generic_args {
         GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
@@ -583,27 +536,6 @@ fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut Pare
     vis.visit_span(inputs_span);
 }
 
-fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut Local) {
-    let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local;
-    visit_opt(super_, |sp| vis.visit_span(sp));
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    vis.visit_pat(pat);
-    visit_opt(ty, |ty| vis.visit_ty(ty));
-    match kind {
-        LocalKind::Decl => {}
-        LocalKind::Init(init) => {
-            vis.visit_expr(init);
-        }
-        LocalKind::InitElse(init, els) => {
-            vis.visit_expr(init);
-            vis.visit_block(els);
-        }
-    }
-    visit_opt(colon_sp, |sp| vis.visit_span(sp));
-    vis.visit_span(span);
-}
-
 fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) {
     let Attribute { kind, id: _, style: _, span } = attr;
     match kind {
@@ -853,35 +785,6 @@ fn walk_variant_data<T: MutVisitor>(vis: &mut T, vdata: &mut VariantData) {
     }
 }
 
-fn walk_trait_ref<T: MutVisitor>(vis: &mut T, TraitRef { path, ref_id }: &mut TraitRef) {
-    vis.visit_id(ref_id);
-    vis.visit_path(path);
-}
-
-fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) {
-    let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p;
-    vis.visit_modifiers(modifiers);
-    bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
-    vis.visit_trait_ref(trait_ref);
-    vis.visit_span(span);
-}
-
-fn walk_modifiers<V: MutVisitor>(vis: &mut V, m: &mut TraitBoundModifiers) {
-    let TraitBoundModifiers { constness, asyncness, polarity } = m;
-    match constness {
-        BoundConstness::Never => {}
-        BoundConstness::Always(span) | BoundConstness::Maybe(span) => vis.visit_span(span),
-    }
-    match asyncness {
-        BoundAsyncness::Normal => {}
-        BoundAsyncness::Async(span) => vis.visit_span(span),
-    }
-    match polarity {
-        BoundPolarity::Positive => {}
-        BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => vis.visit_span(span),
-    }
-}
-
 pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
     let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd;
     visitor.visit_id(id);
@@ -902,15 +805,6 @@ pub fn walk_flat_map_field_def<T: MutVisitor>(
     smallvec![fd]
 }
 
-pub fn walk_expr_field<T: MutVisitor>(vis: &mut T, f: &mut ExprField) {
-    let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = f;
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    vis.visit_ident(ident);
-    vis.visit_expr(expr);
-    vis.visit_span(span);
-}
-
 pub fn walk_flat_map_expr_field<T: MutVisitor>(
     vis: &mut T,
     mut f: ExprField,
@@ -930,16 +824,6 @@ pub fn walk_item_kind<K: WalkItemKind>(
     kind.walk(span, id, visibility, ctxt, vis)
 }
 
-pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) {
-    let Crate { attrs, items, spans, id, is_placeholder: _ } = krate;
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    items.flat_map_in_place(|item| vis.flat_map_item(item));
-    let ModSpans { inner_span, inject_use_span } = spans;
-    vis.visit_span(inner_span);
-    vis.visit_span(inject_use_span);
-}
-
 pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P<Item>) -> SmallVec<[P<Item>; 1]> {
     vis.visit_item(&mut item);
     smallvec![item]
@@ -1021,7 +905,7 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     match kind {
-        ExprKind::Array(exprs) => visit_thin_exprs(vis, exprs),
+        ExprKind::Array(exprs) => visit_exprs(vis, exprs),
         ExprKind::ConstBlock(anon_const) => {
             vis.visit_anon_const(anon_const);
         }
@@ -1029,10 +913,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
             vis.visit_expr(expr);
             vis.visit_anon_const(count);
         }
-        ExprKind::Tup(exprs) => visit_thin_exprs(vis, exprs),
+        ExprKind::Tup(exprs) => visit_exprs(vis, exprs),
         ExprKind::Call(f, args) => {
             vis.visit_expr(f);
-            visit_thin_exprs(vis, args);
+            visit_exprs(vis, args);
         }
         ExprKind::MethodCall(box MethodCall {
             seg: PathSegment { ident, id, args: seg_args },
@@ -1044,7 +928,7 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
             vis.visit_id(id);
             vis.visit_ident(ident);
             visit_opt(seg_args, |args| vis.visit_generic_args(args));
-            visit_thin_exprs(vis, call_args);
+            visit_exprs(vis, call_args);
             vis.visit_span(span);
         }
         ExprKind::Binary(binop, lhs, rhs) => {
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index dd923305cdf..fffeab8bbca 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -1,209 +1,11 @@
-//! The AST pointer.
-//!
-//! Provides [`P<T>`][struct@P], an owned smart pointer.
-//!
-//! # Motivations and benefits
-//!
-//! * **Identity**: sharing AST nodes is problematic for the various analysis
-//!   passes (e.g., one may be able to bypass the borrow checker with a shared
-//!   `ExprKind::AddrOf` node taking a mutable borrow).
-//!
-//! * **Efficiency**: folding can reuse allocation space for `P<T>` and `Vec<T>`,
-//!   the latter even when the input and output types differ (as it would be the
-//!   case with arenas or a GADT AST using type parameters to toggle features).
-//!
-//! * **Maintainability**: `P<T>` provides an interface, which can remain fully
-//!   functional even if the implementation changes (using a special thread-local
-//!   heap, for example). Moreover, a switch to, e.g., `P<'a, T>` would be easy
-//!   and mostly automated.
-
-use std::fmt::{self, Debug, Display};
-use std::ops::{Deref, DerefMut};
-use std::{slice, vec};
-
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-/// An owned smart pointer.
+/// A pointer type that uniquely owns a heap allocation of type T.
 ///
-/// See the [module level documentation][crate::ptr] for details.
-pub struct P<T: ?Sized> {
-    ptr: Box<T>,
-}
+/// This used to be its own type, but now it's just a typedef for `Box` and we are planning to
+/// remove it soon.
+pub type P<T> = Box<T>;
 
 /// Construct a `P<T>` from a `T` value.
 #[allow(non_snake_case)]
-pub fn P<T: 'static>(value: T) -> P<T> {
-    P { ptr: Box::new(value) }
-}
-
-impl<T: 'static> P<T> {
-    /// Move out of the pointer.
-    /// Intended for chaining transformations not covered by `map`.
-    pub fn and_then<U, F>(self, f: F) -> U
-    where
-        F: FnOnce(T) -> U,
-    {
-        f(*self.ptr)
-    }
-
-    /// Equivalent to `and_then(|x| x)`.
-    pub fn into_inner(self) -> T {
-        *self.ptr
-    }
-
-    /// Produce a new `P<T>` from `self` without reallocating.
-    pub fn map<F>(mut self, f: F) -> P<T>
-    where
-        F: FnOnce(T) -> T,
-    {
-        let x = f(*self.ptr);
-        *self.ptr = x;
-
-        self
-    }
-
-    /// Optionally produce a new `P<T>` from `self` without reallocating.
-    pub fn filter_map<F>(mut self, f: F) -> Option<P<T>>
-    where
-        F: FnOnce(T) -> Option<T>,
-    {
-        *self.ptr = f(*self.ptr)?;
-        Some(self)
-    }
-}
-
-impl<T: ?Sized> Deref for P<T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        &self.ptr
-    }
-}
-
-impl<T: ?Sized> DerefMut for P<T> {
-    fn deref_mut(&mut self) -> &mut T {
-        &mut self.ptr
-    }
-}
-
-impl<T: 'static + Clone> Clone for P<T> {
-    fn clone(&self) -> P<T> {
-        P((**self).clone())
-    }
-}
-
-impl<T: ?Sized + Debug> Debug for P<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Debug::fmt(&self.ptr, f)
-    }
-}
-
-impl<T: Display> Display for P<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Display::fmt(&**self, f)
-    }
-}
-
-impl<T> fmt::Pointer for P<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Pointer::fmt(&self.ptr, f)
-    }
-}
-
-impl<D: Decoder, T: 'static + Decodable<D>> Decodable<D> for P<T> {
-    fn decode(d: &mut D) -> P<T> {
-        P(Decodable::decode(d))
-    }
-}
-
-impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> {
-    fn encode(&self, s: &mut S) {
-        (**self).encode(s);
-    }
-}
-
-impl<T> P<[T]> {
-    // FIXME(const-hack) make this const again
-    pub fn new() -> P<[T]> {
-        P { ptr: Box::default() }
-    }
-
-    #[inline(never)]
-    pub fn from_vec(v: Vec<T>) -> P<[T]> {
-        P { ptr: v.into_boxed_slice() }
-    }
-
-    #[inline(never)]
-    pub fn into_vec(self) -> Vec<T> {
-        self.ptr.into_vec()
-    }
-}
-
-impl<T> Default for P<[T]> {
-    /// Creates an empty `P<[T]>`.
-    fn default() -> P<[T]> {
-        P::new()
-    }
-}
-
-impl<T: Clone> Clone for P<[T]> {
-    fn clone(&self) -> P<[T]> {
-        P::from_vec(self.to_vec())
-    }
-}
-
-impl<T> From<Vec<T>> for P<[T]> {
-    fn from(v: Vec<T>) -> Self {
-        P::from_vec(v)
-    }
-}
-
-impl<T> From<P<[T]>> for Vec<T> {
-    fn from(val: P<[T]>) -> Self {
-        val.into_vec()
-    }
-}
-
-impl<T> FromIterator<T> for P<[T]> {
-    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> P<[T]> {
-        P::from_vec(iter.into_iter().collect())
-    }
-}
-
-impl<T> IntoIterator for P<[T]> {
-    type Item = T;
-    type IntoIter = vec::IntoIter<T>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.into_vec().into_iter()
-    }
-}
-
-impl<'a, T> IntoIterator for &'a P<[T]> {
-    type Item = &'a T;
-    type IntoIter = slice::Iter<'a, T>;
-    fn into_iter(self) -> Self::IntoIter {
-        self.ptr.iter()
-    }
-}
-
-impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<[T]> {
-    fn encode(&self, s: &mut S) {
-        Encodable::encode(&**self, s);
-    }
-}
-
-impl<D: Decoder, T: Decodable<D>> Decodable<D> for P<[T]> {
-    fn decode(d: &mut D) -> P<[T]> {
-        P::from_vec(Decodable::decode(d))
-    }
-}
-
-impl<CTX, T> HashStable<CTX> for P<T>
-where
-    T: ?Sized + HashStable<CTX>,
-{
-    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
-        (**self).hash_stable(hcx, hasher);
-    }
+pub fn P<T>(value: T) -> P<T> {
+    Box::new(value)
 }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1f7c97380dc..d2f22b04a67 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -219,9 +219,6 @@ pub trait Visitor<'ast>: Sized {
     fn visit_field_def(&mut self, s: &'ast FieldDef) -> Self::Result {
         walk_field_def(self, s)
     }
-    fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) -> Self::Result {
-        walk_enum_def(self, enum_definition)
-    }
     fn visit_variant(&mut self, v: &'ast Variant) -> Self::Result {
         walk_variant(self, v)
     }
@@ -246,13 +243,12 @@ pub trait Visitor<'ast>: Sized {
     fn visit_path(&mut self, path: &'ast Path) -> Self::Result {
         walk_path(self, path)
     }
-    fn visit_use_tree(
-        &mut self,
-        use_tree: &'ast UseTree,
-        id: NodeId,
-        _nested: bool,
-    ) -> Self::Result {
-        walk_use_tree(self, use_tree, id)
+    fn visit_use_tree(&mut self, use_tree: &'ast UseTree) -> Self::Result {
+        walk_use_tree(self, use_tree)
+    }
+    fn visit_nested_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId) -> Self::Result {
+        try_visit!(self.visit_id(id));
+        self.visit_use_tree(use_tree)
     }
     fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) -> Self::Result {
         walk_path_segment(self, path_segment)
@@ -378,13 +374,39 @@ macro_rules! common_visitor_and_walkers {
             }
         }
 
-        fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, polarity: &$($lt)? $($mut)? ImplPolarity) $(-> <V as Visitor<$lt>>::Result)? {
+        fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            polarity: &$($lt)? $($mut)? ImplPolarity,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
             match polarity {
                 ImplPolarity::Positive => { $(<V as Visitor<$lt>>::Result::output())? }
                 ImplPolarity::Negative(span) => visit_span(vis, span),
             }
         }
 
+        $(${ignore($lt)}
+            #[inline]
+        )?
+        fn visit_modifiers<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            m: &$($lt)? $($mut)? TraitBoundModifiers
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let TraitBoundModifiers { constness, asyncness, polarity } = m;
+            match constness {
+                BoundConstness::Never => {}
+                BoundConstness::Always(span) | BoundConstness::Maybe(span) => try_visit!(visit_span(vis, span)),
+            }
+            match asyncness {
+                BoundAsyncness::Normal => {}
+                BoundAsyncness::Async(span) => try_visit!(visit_span(vis, span)),
+            }
+            match polarity {
+                BoundPolarity::Positive => {}
+                BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => try_visit!(visit_span(vis, span)),
+            }
+            $(<V as Visitor<$lt>>::Result::output())?
+        }
+
         fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) $(-> <V as Visitor<$lt>>::Result)? {
             walk_list!(visitor, visit_param_bound, bounds, ctxt);
             $(<V as Visitor<$lt>>::Result::output())?
@@ -446,8 +468,7 @@ macro_rules! common_visitor_and_walkers {
             ) $(-> <V as Visitor<$lt>>::Result)? {
                 match self {
                     ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident),
-                    // FIXME(fee1-dead): look into this weird assymetry
-                    ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree$(${ignore($lt)}, id, false)?),
+                    ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
                     ItemKind::Static(box StaticItem {
                         ident,
                         ty,
@@ -478,12 +499,7 @@ macro_rules! common_visitor_and_walkers {
                                 ModSpans { inner_span, inject_use_span },
                                 _,
                             ) => {
-                                $(${ignore($mut)}
-                                    items.flat_map_in_place(|item| vis.flat_map_item(item));
-                                )?
-                                $(${ignore($lt)}
-                                    walk_list!(vis, visit_item, items);
-                                )?
+                                try_visit!(visit_items(vis, items));
                                 try_visit!(visit_span(vis, inner_span));
                                 try_visit!(visit_span(vis, inject_use_span));
                             }
@@ -515,10 +531,7 @@ macro_rules! common_visitor_and_walkers {
                     ItemKind::Enum(ident, generics, enum_definition) => {
                         try_visit!(vis.visit_ident(ident));
                         try_visit!(vis.visit_generics(generics));
-                        $(${ignore($mut)}
-                            enum_definition.variants.flat_map_in_place(|variant| vis.flat_map_variant(variant));
-                        )?
-                        $(${ignore($lt)}vis.visit_enum_def(enum_definition))?
+                        visit_variants(vis, &$($mut)? enum_definition.variants)
                     }
                     ItemKind::Struct(ident, generics, variant_data)
                     | ItemKind::Union(ident, generics, variant_data) => {
@@ -543,35 +556,14 @@ macro_rules! common_visitor_and_walkers {
                         try_visit!(visit_polarity(vis, polarity));
                         visit_opt!(vis, visit_trait_ref, of_trait);
                         try_visit!(vis.visit_ty(self_ty));
-                        $(${ignore($mut)}
-                            items.flat_map_in_place(|item| {
-                                vis.flat_map_assoc_item(item, AssocCtxt::Impl { of_trait: of_trait.is_some() })
-                            });
-                        )?
-                        $(${ignore($lt)}
-                            walk_list!(
-                                vis,
-                                visit_assoc_item,
-                                items,
-                                AssocCtxt::Impl { of_trait: of_trait.is_some() }
-                            );
-                            <V as Visitor<$lt>>::Result::output()
-                        )?
+                        visit_assoc_items(vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() })
                     }
                     ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => {
                         try_visit!(visit_safety(vis, safety));
                         try_visit!(vis.visit_ident(ident));
                         try_visit!(vis.visit_generics(generics));
                         try_visit!(visit_bounds(vis, bounds, BoundKind::Bound));
-                        $(${ignore($mut)}
-                            items.flat_map_in_place(|item| {
-                                vis.flat_map_assoc_item(item, AssocCtxt::Trait)
-                            });
-                        )?
-                        $(${ignore($lt)}
-                            walk_list!(vis, visit_assoc_item, items, AssocCtxt::Trait);
-                            <V as Visitor<$lt>>::Result::output()
-                        )?
+                        visit_assoc_items(vis, items, AssocCtxt::Trait)
                     }
                     ItemKind::TraitAlias(ident, generics, bounds) => {
                         try_visit!(vis.visit_ident(ident));
@@ -616,7 +608,10 @@ macro_rules! common_visitor_and_walkers {
             }
         }
 
-        fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, item: &$($lt)? $($mut)? ConstItem) $(-> <V as Visitor<$lt>>::Result)? {
+        fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            item: &$($lt)? $($mut)? ConstItem,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
             let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item;
             try_visit!(visit_defaultness(vis, defaultness));
             try_visit!(vis.visit_ident(ident));
@@ -629,13 +624,7 @@ macro_rules! common_visitor_and_walkers {
         fn walk_foreign_mod<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, foreign_mod: &$($lt)? $($mut)? ForeignMod) $(-> <V as Visitor<$lt>>::Result)? {
             let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod;
             try_visit!(visit_safety(vis, safety));
-            $(${ignore($mut)}
-                items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
-            )?
-            $(
-                walk_list!(vis, visit_foreign_item, items);
-                <V as Visitor<$lt>>::Result::output()
-            )?
+            visit_foreign_items(vis, items)
         }
 
         fn walk_define_opaques<$($lt,)? V: $Visitor$(<$lt>)?>(
@@ -780,15 +769,13 @@ macro_rules! common_visitor_and_walkers {
             vis: &mut V,
             coroutine_kind: &$($lt)? $($mut)? CoroutineKind,
         ) $(-> <V as Visitor<$lt>>::Result)? {
-            match coroutine_kind {
-                CoroutineKind::Async { span, closure_id, return_impl_trait_id }
+            let (CoroutineKind::Async { span, closure_id, return_impl_trait_id }
                 | CoroutineKind::Gen { span, closure_id, return_impl_trait_id }
-                | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id } => {
-                    try_visit!(visit_id(vis, closure_id));
-                    try_visit!(visit_id(vis, return_impl_trait_id));
-                    visit_span(vis, span)
-                }
-            }
+                | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id })
+                = coroutine_kind;
+            try_visit!(visit_id(vis, closure_id));
+            try_visit!(visit_id(vis, return_impl_trait_id));
+            visit_span(vis, span)
         }
 
         pub fn walk_pat<$($lt,)? V: $Visitor$(<$lt>)?>(
@@ -817,15 +804,7 @@ macro_rules! common_visitor_and_walkers {
                 PatKind::Struct(opt_qself, path, fields, _rest) => {
                     try_visit!(vis.visit_qself(opt_qself));
                     try_visit!(vis.visit_path(path));
-
-                    $(
-                        ${ignore($lt)}
-                        walk_list!(vis, visit_pat_field, fields);
-                    )?
-                    $(
-                        ${ignore($mut)}
-                        fields.flat_map_in_place(|field| vis.flat_map_pat_field(field));
-                    )?
+                    try_visit!(visit_pat_fields(vis, fields));
                 }
                 PatKind::Box(subpattern) | PatKind::Deref(subpattern) | PatKind::Paren(subpattern) => {
                     try_visit!(vis.visit_pat(subpattern));
@@ -876,14 +855,7 @@ macro_rules! common_visitor_and_walkers {
         ) $(-> <V as Visitor<$lt>>::Result)? {
             let Block { stmts, id, rules: _, span, tokens: _ } = block;
             try_visit!(visit_id(vis, id));
-            $(
-                ${ignore($lt)}
-                walk_list!(vis, visit_stmt, stmts);
-            )?
-            $(
-                ${ignore($mut)}
-                stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
-            )?
+            try_visit!(visit_stmts(vis, stmts));
             visit_span(vis, span)
         }
 
@@ -911,28 +883,13 @@ macro_rules! common_visitor_and_walkers {
                     let BareFnTy { safety, ext: _, generic_params, decl, decl_span } =
                         &$($mut)? **function_declaration;
                     visit_safety(vis, safety);
-                    $(
-                        ${ignore($lt)}
-                        walk_list!(vis, visit_generic_param, generic_params);
-                    )?
-                    $(
-                        ${ignore($mut)}
-                        generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
-                    )?
-
+                    try_visit!(visit_generic_params(vis, generic_params));
                     try_visit!(vis.visit_fn_decl(decl));
                     try_visit!(visit_span(vis, decl_span));
                 }
                 TyKind::UnsafeBinder(binder) => {
-                    $(
-                        ${ignore($lt)}
-                        walk_list!(vis, visit_generic_param, &binder.generic_params);
-                    )?
-                    $(
-                        ${ignore($mut)}
-                        binder.generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
-                    )?
-                    try_visit!(vis.visit_ty(&$($mut)?binder.inner_ty));
+                    try_visit!(visit_generic_params(vis, &$($mut)? binder.generic_params));
+                    try_visit!(vis.visit_ty(&$($mut)? binder.inner_ty));
                 }
                 TyKind::Path(maybe_qself, path) => {
                     try_visit!(vis.visit_qself(maybe_qself));
@@ -959,130 +916,204 @@ macro_rules! common_visitor_and_walkers {
             }
             visit_span(vis, span)
         }
-    };
-}
 
-common_visitor_and_walkers!(Visitor<'a>);
+        pub fn walk_crate<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            krate: &$($lt)? $($mut)? Crate,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let Crate { attrs, items, spans, id, is_placeholder: _ } = krate;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(visit_items(vis, items));
+            let ModSpans { inner_span, inject_use_span } = spans;
+            try_visit!(visit_span(vis, inner_span));
+            visit_span(vis, inject_use_span)
+        }
 
-pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result {
-    let Crate { attrs, items, spans: _, id: _, is_placeholder: _ } = krate;
-    walk_list!(visitor, visit_attribute, attrs);
-    walk_list!(visitor, visit_item, items);
-    V::Result::output()
-}
+        pub fn walk_local<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            local: &$($lt)? $($mut)? Local,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local;
+            if let Some(sp) = super_ {
+                try_visit!(visit_span(vis, sp));
+            }
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(vis.visit_pat(pat));
+            visit_opt!(vis, visit_ty, ty);
+            match kind {
+                LocalKind::Decl => {}
+                LocalKind::Init(init) => {
+                    try_visit!(vis.visit_expr(init))
+                }
+                LocalKind::InitElse(init, els) => {
+                    try_visit!(vis.visit_expr(init));
+                    try_visit!(vis.visit_block(els));
+                }
+            }
+            if let Some(sp) = colon_sp {
+                try_visit!(visit_span(vis, sp));
+            }
+            visit_span(vis, span)
+        }
 
-pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result {
-    let Local { id: _, super_: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local;
-    walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_pat(pat));
-    visit_opt!(visitor, visit_ty, ty);
-    if let Some((init, els)) = kind.init_else_opt() {
-        try_visit!(visitor.visit_expr(init));
-        visit_opt!(visitor, visit_block, els);
-    }
-    V::Result::output()
-}
+        pub fn walk_poly_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            p: &$($lt)? $($mut)? PolyTraitRef,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p;
+            try_visit!(visit_modifiers(vis, modifiers));
+            try_visit!(visit_generic_params(vis, bound_generic_params));
+            try_visit!(vis.visit_trait_ref(trait_ref));
+            visit_span(vis, span)
+        }
 
-pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result
-where
-    V: Visitor<'a>,
-{
-    let PolyTraitRef { bound_generic_params, modifiers: _, trait_ref, span: _ } = trait_ref;
-    walk_list!(visitor, visit_generic_param, bound_generic_params);
-    visitor.visit_trait_ref(trait_ref)
-}
+        pub fn walk_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            TraitRef { path, ref_id }: &$($lt)? $($mut)? TraitRef,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            try_visit!(vis.visit_path(path));
+            visit_id(vis, ref_id)
+        }
 
-pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) -> V::Result {
-    let TraitRef { path, ref_id } = trait_ref;
-    try_visit!(visitor.visit_path(path));
-    visitor.visit_id(*ref_id)
-}
+        pub fn walk_variant<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            variant: &$($lt)? $($mut)? Variant,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let Variant { attrs, id, span, vis: visibility, ident, data, disr_expr, is_placeholder: _ } = variant;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(vis.visit_vis(visibility));
+            try_visit!(vis.visit_ident(ident));
+            try_visit!(vis.visit_variant_data(data));
+            $(${ignore($lt)} visit_opt!(vis, visit_variant_discr, disr_expr); )?
+            $(${ignore($mut)} visit_opt!(vis, visit_anon_const, disr_expr); )?
+            visit_span(vis, span)
+        }
 
-pub fn walk_enum_def<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    EnumDef { variants }: &'a EnumDef,
-) -> V::Result {
-    walk_list!(visitor, visit_variant, variants);
-    V::Result::output()
-}
+        pub fn walk_expr_field<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            f: &$($lt)? $($mut)? ExprField,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let ExprField { attrs, id, span, ident, expr, is_shorthand: _, is_placeholder: _ } = f;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(vis.visit_ident(ident));
+            try_visit!(vis.visit_expr(expr));
+            visit_span(vis, span)
+        }
 
-pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) -> V::Result
-where
-    V: Visitor<'a>,
-{
-    let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant;
-    walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_vis(vis));
-    try_visit!(visitor.visit_ident(ident));
-    try_visit!(visitor.visit_variant_data(data));
-    visit_opt!(visitor, visit_variant_discr, disr_expr);
-    V::Result::output()
-}
+        pub fn walk_pat_field<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            fp: &$($lt)? $($mut)? PatField,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let PatField { ident, pat, is_shorthand: _, attrs, id, span, is_placeholder: _ } = fp;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(vis.visit_ident(ident));
+            try_visit!(vis.visit_pat(pat));
+            visit_span(vis, span)
+        }
 
-pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result {
-    let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f;
-    walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_ident(ident));
-    try_visit!(visitor.visit_expr(expr));
-    V::Result::output()
-}
+        pub fn walk_ty_pat<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            tp: &$($lt)? $($mut)? TyPat,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let TyPat { id, kind, span, tokens: _ } = tp;
+            try_visit!(visit_id(vis, id));
+            match kind {
+                TyPatKind::Range(start, end, _include_end) => {
+                    visit_opt!(vis, visit_anon_const, start);
+                    visit_opt!(vis, visit_anon_const, end);
+                }
+                TyPatKind::Or(variants) => walk_list!(vis, visit_ty_pat, variants),
+                TyPatKind::Err(_) => {}
+            }
+            visit_span(vis, span)
+        }
 
-pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result {
-    let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp;
-    walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_ident(ident));
-    try_visit!(visitor.visit_pat(pat));
-    V::Result::output()
-}
+        fn walk_qself<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            qself: &$($lt)? $($mut)? Option<P<QSelf>>,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            if let Some(qself) = qself {
+                let QSelf { ty, path_span, position: _ } = &$($mut)? **qself;
+                try_visit!(vis.visit_ty(ty));
+                try_visit!(visit_span(vis, path_span));
+            }
+            $(<V as Visitor<$lt>>::Result::output())?
+        }
 
-pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Result {
-    let TyPat { id: _, kind, span: _, tokens: _ } = tp;
-    match kind {
-        TyPatKind::Range(start, end, _include_end) => {
-            visit_opt!(visitor, visit_anon_const, start);
-            visit_opt!(visitor, visit_anon_const, end);
+        pub fn walk_path<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            path: &$($lt)? $($mut)? Path,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let Path { span, segments, tokens: _ } = path;
+            walk_list!(vis, visit_path_segment, segments);
+            visit_span(vis, span)
         }
-        TyPatKind::Or(variants) => walk_list!(visitor, visit_ty_pat, variants),
-        TyPatKind::Err(_) => {}
-    }
-    V::Result::output()
+
+        pub fn walk_use_tree<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            use_tree: &$($lt)? $($mut)? UseTree,
+        ) $(-> <V as Visitor<$lt>>::Result)? {
+            let UseTree { prefix, kind, span } = use_tree;
+            try_visit!(vis.visit_path(prefix));
+            match kind {
+                UseTreeKind::Simple(rename) => {
+                    // The extra IDs are handled during AST lowering.
+                    visit_opt!(vis, visit_ident, rename);
+                }
+                UseTreeKind::Glob => {}
+                UseTreeKind::Nested { items, span } => {
+                    for (nested_tree, nested_id) in items {
+                        try_visit!(visit_nested_use_tree(vis, nested_tree, nested_id));
+                    }
+                    try_visit!(visit_span(vis, span));
+                }
+            }
+            visit_span(vis, span)
+        }
+    };
 }
 
-fn walk_qself<'a, V: Visitor<'a>>(visitor: &mut V, qself: &'a Option<P<QSelf>>) -> V::Result {
-    if let Some(qself) = qself {
-        let QSelf { ty, path_span: _, position: _ } = &**qself;
-        try_visit!(visitor.visit_ty(ty));
+common_visitor_and_walkers!(Visitor<'a>);
+
+macro_rules! generate_list_visit_fns {
+    ($($name:ident, $Ty:ty, $visit_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => {
+        $(
+            fn $name<'a, V: Visitor<'a>>(
+                vis: &mut V,
+                values: &'a ThinVec<$Ty>,
+                $(
+                    $param: $ParamTy,
+                )*
+            ) -> V::Result {
+                walk_list!(vis, $visit_fn, values$(,$param)*);
+                V::Result::output()
+            }
+        )+
     }
-    V::Result::output()
 }
 
-pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) -> V::Result {
-    let Path { span: _, segments, tokens: _ } = path;
-    walk_list!(visitor, visit_path_segment, segments);
-    V::Result::output()
+generate_list_visit_fns! {
+    visit_items, P<Item>, visit_item;
+    visit_foreign_items, P<ForeignItem>, visit_foreign_item;
+    visit_generic_params, GenericParam, visit_generic_param;
+    visit_stmts, Stmt, visit_stmt;
+    visit_pat_fields, PatField, visit_pat_field;
+    visit_variants, Variant, visit_variant;
+    visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt;
 }
 
-pub fn walk_use_tree<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    use_tree: &'a UseTree,
-    id: NodeId,
+#[expect(rustc::pass_by_value)] // needed for symmetry with mut_visit
+fn visit_nested_use_tree<'a, V: Visitor<'a>>(
+    vis: &mut V,
+    nested_tree: &'a UseTree,
+    &nested_id: &NodeId,
 ) -> V::Result {
-    let UseTree { prefix, kind, span: _ } = use_tree;
-    try_visit!(visitor.visit_id(id));
-    try_visit!(visitor.visit_path(prefix));
-    match kind {
-        UseTreeKind::Simple(rename) => {
-            // The extra IDs are handled during AST lowering.
-            visit_opt!(visitor, visit_ident, rename);
-        }
-        UseTreeKind::Glob => {}
-        UseTreeKind::Nested { items, span: _ } => {
-            for &(ref nested_tree, nested_id) in items {
-                try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true));
-            }
-        }
-    }
-    V::Result::output()
+    vis.visit_nested_use_tree(nested_tree, nested_id)
 }
 
 pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) -> V::Result
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 64d4a00ea4d..3004be40334 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -732,7 +732,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         span: Span,
         args: Option<&'hir hir::GenericArgs<'hir>>,
     ) -> &'hir hir::Path<'hir> {
-        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
+        let def_id = self.tcx.require_lang_item(lang_item, span);
         let def_kind = self.tcx.def_kind(def_id);
         let res = Res::Def(def_kind, def_id);
         self.arena.alloc(hir::Path {
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index f45cf984f71..bf18e10e19f 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -74,7 +74,7 @@ pub(crate) trait AttributeParser: Default + 'static {
 pub(crate) trait SingleAttributeParser: 'static {
     const PATH: &'static [Symbol];
 
-    /// Caled when a duplicate attribute is found.
+    /// Called when a duplicate attribute is found.
     ///
     /// `first_span` is the span of the first occurrence of this attribute.
     // FIXME(jdonszelmann): default error
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index 63bccf52018..15037e802ff 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -1,31 +1,38 @@
 //! Centralized logic for parsing and attributes.
 //!
-//! Part of a series of crates:
-//! - rustc_attr_data_structures: contains types that the parsers parse into
-//! - rustc_attr_parsing: this crate
-//! - (in the future): rustc_attr_validation
+//! ## Architecture
+//! This crate is part of a series of crates that handle attribute processing.
+//! - [rustc_attr_data_structures](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_data_structures/index.html): Defines the data structures that store parsed attributes
+//! - [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html): This crate, handles the parsing of attributes
+//! - (planned) rustc_attr_validation: Will handle attribute validation
 //!
-//! History: Check out [#131229](https://github.com/rust-lang/rust/issues/131229).
-//! There used to be only one definition of attributes in the compiler: `ast::Attribute`.
-//! These were then parsed or validated or both in places distributed all over the compiler.
-//! This was a mess...
+//! The separation between data structures and parsing follows the principle of separation of concerns.
+//! Data structures (`rustc_attr_data_structures`) define what attributes look like after parsing.
+//! This crate (`rustc_attr_parsing`) handles how to convert raw tokens into those structures.
+//! This split allows other parts of the compiler to use the data structures without needing
+//! the parsing logic, making the codebase more modular and maintainable.
 //!
-//! Attributes are markers on items.
-//! Many of them are actually attribute-like proc-macros, and are expanded to some other rust syntax.
-//! This could either be a user provided proc macro, or something compiler provided.
-//! `derive` is an example of one that the compiler provides.
-//! These are built-in, but they have a valid expansion to Rust tokens and are thus called "active".
-//! I personally like calling these *active* compiler-provided attributes, built-in *macros*,
-//! because they still expand, and this helps to differentiate them from built-in *attributes*.
-//! However, I'll be the first to admit that the naming here can be confusing.
+//! ## Background
+//! Previously, the compiler had a single attribute definition (`ast::Attribute`) with parsing and
+//! validation scattered throughout the codebase. This was reorganized for better maintainability
+//! (see [#131229](https://github.com/rust-lang/rust/issues/131229)).
 //!
-//! The alternative to active attributes, are inert attributes.
-//! These can occur in user code (proc-macro helper attributes).
-//! But what's important is, many built-in attributes are inert like this.
-//! There is nothing they expand to during the macro expansion process,
-//! sometimes because they literally cannot expand to something that is valid Rust.
-//! They are really just markers to guide the compilation process.
-//! An example is `#[inline(...)]` which changes how code for functions is generated.
+//! ## Types of Attributes
+//! In Rust, attributes are markers that can be attached to items. They come in two main categories.
+//!
+//! ### 1. Active Attributes
+//! These are attribute-like proc-macros that expand into other Rust code.
+//! They can be either user-defined or compiler-provided. Examples of compiler-provided active attributes:
+//!   - `#[derive(...)]`: Expands into trait implementations
+//!   - `#[cfg()]`: Expands based on configuration
+//!   - `#[cfg_attr()]`: Conditional attribute application
+//!
+//! ### 2. Inert Attributes
+//! These are pure markers that don't expand into other code. They guide the compilation process.
+//! They can be user-defined (in proc-macro helpers) or built-in. Examples of built-in inert attributes:
+//!   - `#[stable()]`: Marks stable API items
+//!   - `#[inline()]`: Suggests function inlining
+//!   - `#[repr()]`: Controls type representation
 //!
 //! ```text
 //!                      Active                 Inert
@@ -33,27 +40,21 @@
 //!              │     (mostly in)      │    these are parsed  │
 //!              │ rustc_builtin_macros │        here!         │
 //!              │                      │                      │
-//!              │                      │                      │
 //!              │    #[derive(...)]    │    #[stable()]       │
 //!     Built-in │    #[cfg()]          │    #[inline()]       │
 //!              │    #[cfg_attr()]     │    #[repr()]         │
 //!              │                      │                      │
-//!              │                      │                      │
-//!              │                      │                      │
 //!              ├──────────────────────┼──────────────────────┤
 //!              │                      │                      │
-//!              │                      │                      │
 //!              │                      │       `b` in         │
 //!              │                      │ #[proc_macro_derive( │
 //! User created │ #[proc_macro_attr()] │    a,                │
 //!              │                      │    attributes(b)     │
 //!              │                      │ ]                    │
-//!              │                      │                      │
-//!              │                      │                      │
-//!              │                      │                      │
 //!              └──────────────────────┴──────────────────────┘
 //! ```
 //!
+//! ## How This Crate Works
 //! In this crate, syntactical attributes (sequences of tokens that look like
 //! `#[something(something else)]`) are parsed into more semantic attributes, markers on items.
 //! Multiple syntactic attributes might influence a single semantic attribute. For example,
@@ -63,18 +64,17 @@
 //! and `#[unstable()]` syntactic attributes, and at the end produce a single
 //! [`AttributeKind::Stability`](rustc_attr_data_structures::AttributeKind::Stability).
 //!
-//! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be
-//! combined into a single semantic attribute. For example:
+//! When multiple instances of the same attribute are allowed, they're combined into a single
+//! semantic attribute. For example:
 //!
-//! ```
+//! ```rust
 //! #[repr(C)]
 //! #[repr(packed)]
 //! struct Meow {}
 //! ```
 //!
-//! should result in a single `AttributeKind::Repr` containing a list of repr annotations, in this
-//! case `C` and `packed`. This is equivalent to writing `#[repr(C, packed)]` in a single
-//! syntactical annotation.
+//! This is equivalent to `#[repr(C, packed)]` and results in a single `AttributeKind::Repr`
+//! containing both `C` and `packed` annotations.
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b7b6a2da549..1b4bb11d87b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -263,7 +263,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 // something that already has `Fn`-like bounds (or is a closure), so we can't
                 // restrict anyways.
             } else {
-                let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span));
+                let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, span);
                 self.suggest_adding_bounds(&mut err, ty, copy_did, span);
             }
 
@@ -1915,7 +1915,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         let local_ty = self.body.local_decls[place.local].ty;
         let typeck_results = tcx.typeck(self.mir_def_id());
-        let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span));
+        let clone = tcx.require_lang_item(LangItem::Clone, body.span);
         for expr in expr_finder.clones {
             if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind
                 && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id)
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 4f5baeff7c3..4f75dd7e992 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -688,7 +688,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 if !self.unsized_feature_enabled() {
                     let trait_ref = ty::TraitRef::new(
                         tcx,
-                        tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
+                        tcx.require_lang_item(LangItem::Sized, self.last_span),
                         [place_ty],
                     );
                     self.prove_trait_ref(
@@ -1010,7 +1010,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             let ty = place.ty(self.body, tcx).ty;
                             let trait_ref = ty::TraitRef::new(
                                 tcx,
-                                tcx.require_lang_item(LangItem::Copy, Some(span)),
+                                tcx.require_lang_item(LangItem::Copy, span),
                                 [ty],
                             );
 
@@ -1025,11 +1025,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             }
 
             &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => {
-                let trait_ref = ty::TraitRef::new(
-                    tcx,
-                    tcx.require_lang_item(LangItem::Sized, Some(span)),
-                    [ty],
-                );
+                let trait_ref =
+                    ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [ty]);
 
                 self.prove_trait_ref(
                     trait_ref,
@@ -1041,11 +1038,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             &Rvalue::NullaryOp(NullOp::UbChecks, _) => {}
 
             Rvalue::ShallowInitBox(_operand, ty) => {
-                let trait_ref = ty::TraitRef::new(
-                    tcx,
-                    tcx.require_lang_item(LangItem::Sized, Some(span)),
-                    [*ty],
-                );
+                let trait_ref =
+                    ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [*ty]);
 
                 self.prove_trait_ref(
                     trait_ref,
@@ -1222,7 +1216,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         let &ty = ty;
                         let trait_ref = ty::TraitRef::new(
                             tcx,
-                            tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)),
+                            tcx.require_lang_item(LangItem::CoerceUnsized, span),
                             [op.ty(self.body, tcx), ty],
                         );
 
@@ -1811,7 +1805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
         if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
             let trait_ref = ty::TraitRef::new(
                 tcx,
-                tcx.require_lang_item(LangItem::Copy, Some(self.last_span)),
+                tcx.require_lang_item(LangItem::Copy, self.last_span),
                 [place_ty.ty],
             );
 
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index c11e14d214c..846299711be 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -544,10 +544,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         // (as it's created inside the body itself, not passed in from outside).
         if let DefiningTy::FnDef(def_id, _) = defining_ty {
             if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
-                let va_list_did = self.infcx.tcx.require_lang_item(
-                    LangItem::VaList,
-                    Some(self.infcx.tcx.def_span(self.mir_def)),
-                );
+                let va_list_did = self
+                    .infcx
+                    .tcx
+                    .require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def));
 
                 let reg_vid = self
                     .infcx
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 50e7b989ed8..e45d09b5796 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -57,7 +57,7 @@ impl MultiItemModifier for BuiltinDerive {
         let mut items = Vec::new();
         match item {
             Annotatable::Stmt(stmt) => {
-                if let ast::StmtKind::Item(item) = stmt.into_inner().kind {
+                if let ast::StmtKind::Item(item) = stmt.kind {
                     (self.0)(
                         ecx,
                         span,
diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs
index 3529e5525fc..b61af0b0aaa 100644
--- a/compiler/rustc_builtin_macros/src/pattern_type.rs
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -30,14 +30,12 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P
 
     let pat = pat_to_ty_pat(
         cx,
-        parser
-            .parse_pat_no_top_guard(
-                None,
-                RecoverComma::No,
-                RecoverColon::No,
-                CommaRecoveryMode::EitherTupleOrPipe,
-            )?
-            .into_inner(),
+        *parser.parse_pat_no_top_guard(
+            None,
+            RecoverComma::No,
+            RecoverColon::No,
+            CommaRecoveryMode::EitherTupleOrPipe,
+        )?,
     );
 
     if parser.token != token::Eof {
@@ -58,9 +56,9 @@ fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> P<TyPat> {
             end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })),
             include_end,
         ),
-        ast::PatKind::Or(variants) => TyPatKind::Or(
-            variants.into_iter().map(|pat| pat_to_ty_pat(cx, pat.into_inner())).collect(),
-        ),
+        ast::PatKind::Or(variants) => {
+            TyPatKind::Or(variants.into_iter().map(|pat| pat_to_ty_pat(cx, *pat)).collect())
+        }
         ast::PatKind::Err(guar) => TyPatKind::Err(guar),
         _ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")),
     };
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index a91f2d38a93..daf480a9ce4 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -354,30 +354,28 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
         })
         .collect();
 
-    let decls_static = cx
-        .item_static(
+    let mut decls_static = cx.item_static(
+        span,
+        Ident::new(sym::_DECLS, span),
+        cx.ty_ref(
             span,
-            Ident::new(sym::_DECLS, span),
-            cx.ty_ref(
+            cx.ty(
                 span,
-                cx.ty(
-                    span,
-                    ast::TyKind::Slice(
-                        cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])),
-                    ),
+                ast::TyKind::Slice(
+                    cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])),
                 ),
-                None,
-                ast::Mutability::Not,
             ),
+            None,
             ast::Mutability::Not,
-            cx.expr_array_ref(span, decls),
-        )
-        .map(|mut i| {
-            i.attrs.push(cx.attr_word(sym::rustc_proc_macro_decls, span));
-            i.attrs.push(cx.attr_word(sym::used, span));
-            i.attrs.push(cx.attr_nested_word(sym::allow, sym::deprecated, span));
-            i
-        });
+        ),
+        ast::Mutability::Not,
+        cx.expr_array_ref(span, decls),
+    );
+    decls_static.attrs.extend([
+        cx.attr_word(sym::rustc_proc_macro_decls, span),
+        cx.attr_word(sym::used, span),
+        cx.attr_nested_word(sym::allow, sym::deprecated, span),
+    ]);
 
     let block = cx.expr_block(
         cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]),
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 1cef4f9514c..b439fa34f5b 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -40,7 +40,7 @@ pub(crate) fn expand_test_case(
     let (mut item, is_stmt) = match anno_item {
         Annotatable::Item(item) => (item, false),
         Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => {
-            if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
+            if let ast::StmtKind::Item(i) = stmt.kind {
                 (i, true)
             } else {
                 unreachable!()
@@ -120,11 +120,7 @@ pub(crate) fn expand_test_or_bench(
         Annotatable::Item(i) => (i, false),
         Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => {
             // FIXME: Use an 'if let' guard once they are implemented
-            if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
-                (i, true)
-            } else {
-                unreachable!()
-            }
+            if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() }
         }
         other => {
             not_testable_error(cx, attr_sp, None);
@@ -381,10 +377,7 @@ pub(crate) fn expand_test_or_bench(
                 .into(),
             ),
         );
-    test_const = test_const.map(|mut tc| {
-        tc.vis.kind = ast::VisibilityKind::Public;
-        tc
-    });
+    test_const.vis.kind = ast::VisibilityKind::Public;
 
     // extern crate test
     let test_extern =
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 4617304105a..0b641ba64b7 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -380,7 +380,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                             rustc_hir::LangItem::PanicBoundsCheck,
                             &[index, len, location],
                             *unwind,
-                            Some(source_info.span),
+                            source_info.span,
                         );
                     }
                     AssertKind::MisalignedPointerDereference { ref required, ref found } => {
@@ -393,7 +393,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                             rustc_hir::LangItem::PanicMisalignedPointerDereference,
                             &[required, found, location],
                             *unwind,
-                            Some(source_info.span),
+                            source_info.span,
                         );
                     }
                     AssertKind::NullPointerDereference => {
@@ -404,7 +404,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                             rustc_hir::LangItem::PanicNullPointerDereference,
                             &[location],
                             *unwind,
-                            Some(source_info.span),
+                            source_info.span,
                         )
                     }
                     _ => {
@@ -415,7 +415,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                             msg.panic_function(),
                             &[location],
                             *unwind,
-                            Some(source_info.span),
+                            source_info.span,
                         );
                     }
                 }
@@ -531,7 +531,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                 );
             }
             TerminatorKind::UnwindTerminate(reason) => {
-                codegen_unwind_terminate(fx, Some(source_info.span), *reason);
+                codegen_unwind_terminate(fx, source_info.span, *reason);
             }
             TerminatorKind::UnwindResume => {
                 // FIXME implement unwinding
@@ -1074,7 +1074,7 @@ pub(crate) fn codegen_operand<'tcx>(
 pub(crate) fn codegen_panic_nounwind<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     msg_str: &str,
-    span: Option<Span>,
+    span: Span,
 ) {
     let msg_ptr = fx.anonymous_str(msg_str);
     let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
@@ -1091,7 +1091,7 @@ pub(crate) fn codegen_panic_nounwind<'tcx>(
 
 pub(crate) fn codegen_unwind_terminate<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
-    span: Option<Span>,
+    span: Span,
     reason: UnwindTerminateReason,
 ) {
     codegen_panic_inner(fx, reason.lang_item(), &[], UnwindAction::Unreachable, span);
@@ -1102,7 +1102,7 @@ fn codegen_panic_inner<'tcx>(
     lang_item: rustc_hir::LangItem,
     args: &[Value],
     _unwind: UnwindAction,
-    span: Option<Span>,
+    span: Span,
 ) {
     fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
 
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index afee5095549..120d6ff9e38 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -850,7 +850,7 @@ fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option<ty
         // Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151
         ty::Adt(adt, args) if fx.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => {
             let fields = &adt.non_enum_variant().fields;
-            let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args);
+            let ty = fields[FieldIdx::ONE].ty(fx.tcx, args);
             let ty::Adt(ty, args) = ty.kind() else {
                 unreachable!("expected first field of `MaybeUninit` to be an ADT")
             };
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index 2e02e85a997..99a5518d0b6 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -71,7 +71,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
                  See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\
                  Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues"
             );
-            crate::base::codegen_panic_nounwind(fx, &msg, None);
+            crate::base::codegen_panic_nounwind(fx, &msg, span);
             return;
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
index d22483cf177..c22f2a7b873 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
@@ -512,7 +512,7 @@ pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
                  See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\
                  Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues"
             );
-            crate::base::codegen_panic_nounwind(fx, &msg, None);
+            crate::base::codegen_panic_nounwind(fx, &msg, fx.mir.span);
             return;
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 3d67913a8ff..615f6c47d90 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -1321,7 +1321,7 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>(
                  See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\
                  Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues"
             );
-            crate::base::codegen_panic_nounwind(fx, &msg, None);
+            crate::base::codegen_panic_nounwind(fx, &msg, span);
             return;
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 0de23e55e81..27a5df8b152 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -785,7 +785,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                             }
                         })
                     });
-                    crate::base::codegen_panic_nounwind(fx, &msg_str, Some(source_info.span));
+                    crate::base::codegen_panic_nounwind(fx, &msg_str, source_info.span);
                     return Ok(());
                 }
             }
@@ -884,7 +884,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                         crate::base::codegen_panic_nounwind(
                             fx,
                             "128bit atomics not yet supported",
-                            None,
+                            source_info.span,
                         );
                         return Ok(());
                     } else {
@@ -919,7 +919,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                         crate::base::codegen_panic_nounwind(
                             fx,
                             "128bit atomics not yet supported",
-                            None,
+                            source_info.span,
                         );
                         return Ok(());
                     } else {
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 6eef97c14dd..bf756860b64 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -101,7 +101,7 @@ pub(crate) fn maybe_create_entry_wrapper(
                 let call_inst = bcx.ins().call(main_func_ref, &[]);
                 let call_results = bcx.func.dfg.inst_results(call_inst).to_owned();
 
-                let termination_trait = tcx.require_lang_item(LangItem::Termination, None);
+                let termination_trait = tcx.require_lang_item(LangItem::Termination, DUMMY_SP);
                 let report = tcx
                     .associated_items(termination_trait)
                     .find_by_ident_and_kind(
@@ -136,7 +136,7 @@ pub(crate) fn maybe_create_entry_wrapper(
                 }
             } else {
                 // Regular main fn invoked via start lang item.
-                let start_def_id = tcx.require_lang_item(LangItem::Start, None);
+                let start_def_id = tcx.require_lang_item(LangItem::Start, DUMMY_SP);
                 let start_instance = Instance::expect_resolve(
                     tcx,
                     ty::TypingEnv::fully_monomorphized(),
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index f53045df6e7..95d44dfb6d9 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -54,7 +54,7 @@ fn codegen_three_way_compare<'tcx>(
     let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs);
     let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs);
     let val = fx.bcx.ins().isub(gt, lt);
-    CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span))))
+    CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(fx.mir.span)))
 }
 
 fn codegen_compare_bin_op<'tcx>(
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index f8bbb214920..662546e4999 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -240,7 +240,7 @@ pub(crate) fn size_and_align_of<'tcx>(
                 })
             });
 
-            codegen_panic_nounwind(fx, &msg_str, None);
+            codegen_panic_nounwind(fx, &msg_str, fx.mir.span);
 
             fx.bcx.switch_to_block(next_block);
 
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 9d9e0462a9b..05a8e3c3342 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -53,7 +53,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
                     .layout()
                     .non_1zst_field(fx)
                     .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type");
-                arg = arg.value_field(fx, FieldIdx::new(idx));
+                arg = arg.value_field(fx, idx);
             }
         }
 
@@ -62,8 +62,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>(
                 let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap());
                 let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout);
                 let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr();
-                let vtable =
-                    dyn_star.place_field(fx, FieldIdx::new(1)).to_cvalue(fx).load_scalar(fx);
+                let vtable = dyn_star.place_field(fx, FieldIdx::ONE).to_cvalue(fx).load_scalar(fx);
                 break 'block (ptr, vtable);
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index f7863fe4ae2..c2d6a26de0f 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -561,7 +561,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
         let EntryFnType::Main { sigpipe } = entry_type;
         let (start_fn, start_ty, args, instance) = {
-            let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
+            let start_def_id = cx.tcx().require_lang_item(LangItem::Start, DUMMY_SP);
             let start_instance = ty::Instance::expect_resolve(
                 cx.tcx(),
                 cx.typing_env(),
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index ef0d565333e..48565e0b4de 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -110,7 +110,7 @@ mod temp_stable_hash_impls {
 
 pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &Bx,
-    span: Option<Span>,
+    span: Span,
     li: LangItem,
 ) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) {
     let tcx = bx.tcx();
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 1baab62ae43..43b87171d51 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -783,7 +783,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
         };
 
-        let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item);
+        let (fn_abi, llfn, instance) = common::build_langcall(bx, span, lang_item);
 
         // Codegen the actual panic invoke/call.
         let merging_succ =
@@ -803,7 +803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         self.set_debug_loc(bx, terminator.source_info);
 
         // Obtain the panic entry point.
-        let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item());
+        let (fn_abi, llfn, instance) = common::build_langcall(bx, span, reason.lang_item());
 
         // Codegen the actual panic invoke/call.
         let merging_succ = helper.do_call(
@@ -871,7 +871,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         // Obtain the panic entry point.
         let (fn_abi, llfn, instance) =
-            common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
+            common::build_langcall(bx, source_info.span, LangItem::PanicNounwind);
 
         // Codegen the actual panic invoke/call.
         Some(helper.do_call(
@@ -1077,7 +1077,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             let (idx, _) = op.layout.non_1zst_field(bx).expect(
                                 "not exactly one non-1-ZST field in a `DispatchFromDyn` type",
                             );
-                            op = op.extract_field(self, bx, idx);
+                            op = op.extract_field(self, bx, idx.as_usize());
                         }
 
                         // Now that we have `*dyn Trait` or `&dyn Trait`, split it up into its
@@ -1109,7 +1109,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             let (idx, _) = op.layout.non_1zst_field(bx).expect(
                                 "not exactly one non-1-ZST field in a `DispatchFromDyn` type",
                             );
-                            op = op.extract_field(self, bx, idx);
+                            op = op.extract_field(self, bx, idx.as_usize());
                         }
 
                         // Make sure that we've actually unwrapped the rcvr down
@@ -1830,7 +1830,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
 
-        let (fn_abi, fn_ptr, instance) = common::build_langcall(&bx, None, reason.lang_item());
+        let (fn_abi, fn_ptr, instance) =
+            common::build_langcall(&bx, self.mir.span, reason.lang_item());
         if is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(), instance) {
             bx.abort();
         } else {
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index b7f2277bfda..e9389ddf93b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -45,9 +45,15 @@ pub enum OperandValue<V> {
     Immediate(V),
     /// A pair of immediate LLVM values. Used by wide pointers too.
     ///
-    /// An `OperandValue` *must* be this variant for any type for which
+    /// # Invariants
+    /// - For `Pair(a, b)`, `a` is always at offset 0, but may have `FieldIdx(1..)`
+    /// - `b` is not at offset 0, because `V` is not a 1ZST type.
+    /// - `a` and `b` will have a different FieldIdx, but otherwise `b`'s may be lower
+    ///   or they may not be adjacent, due to arbitrary numbers of 1ZST fields that
+    ///   will not affect the shape of the data which determines if `Pair` will be used.
+    /// - An `OperandValue` *must* be this variant for any type for which
     /// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`.
-    /// The backend values in this variant must be the *immediate* backend types,
+    /// - The backend values in this variant must be the *immediate* backend types,
     /// as returned by [`LayoutTypeCodegenMethods::scalar_pair_element_backend_type`]
     /// with `immediate: true`.
     Pair(V, V),
diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs
index ac2366340fb..577012151e4 100644
--- a/compiler/rustc_codegen_ssa/src/size_of_val.rs
+++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs
@@ -5,6 +5,7 @@ use rustc_hir::LangItem;
 use rustc_middle::bug;
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Ty};
+use rustc_span::DUMMY_SP;
 use tracing::{debug, trace};
 
 use crate::common::IntPredicate;
@@ -62,7 +63,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
             // Obtain the panic entry point.
             let (fn_abi, llfn, _instance) =
-                common::build_langcall(bx, None, LangItem::PanicNounwind);
+                common::build_langcall(bx, DUMMY_SP, LangItem::PanicNounwind);
 
             // Generate the call. Cannot use `do_call` since we don't have a MIR terminator so we
             // can't create a `TerminationCodegenHelper`. (But we are in good company, this code is
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index d701646719a..9c30dbff99e 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -345,11 +345,7 @@ fn build_error_for_const_call<'tcx>(
                 non_or_conditionally,
             });
 
-            note_trait_if_possible(
-                &mut err,
-                self_ty,
-                tcx.require_lang_item(LangItem::Deref, Some(span)),
-            );
+            note_trait_if_possible(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, span));
             err
         }
         _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => {
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index dfcd1969a73..c1a37ab6a83 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -99,7 +99,7 @@ impl Qualif for HasMutInterior {
         // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error.
         // Instead we invoke an obligation context manually, and provide the opaque type inference settings
         // that allow the trait solver to just error out instead of cycling.
-        let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span));
+        let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, cx.body.span);
         // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR
         // typeck results without causing query cycles, we should use this here instead of defining
         // opaque types.
@@ -180,7 +180,7 @@ impl Qualif for NeedsNonConstDrop {
         // that the components of this type are also `~const Destruct`. This
         // amounts to verifying that there are no values in this ADT that may have
         // a non-const drop.
-        let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
+        let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, cx.body.span);
         let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env);
         let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(Obligation::new(
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 3922b33ea84..a68dcf29988 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -249,7 +249,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
             return Err(ConstEvalErrKind::Panic { msg, file, line, col }).into();
         } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) {
             // For panic_fmt, call const_panic_fmt instead.
-            let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None);
+            let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, self.tcx.span);
             let new_instance = ty::Instance::expect_resolve(
                 *self.tcx,
                 self.typing_env(),
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index c0438fb3ff8..6fd0b9d26e3 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -1,6 +1,6 @@
 // Not in interpret to make sure we do not use private implementation details
 
-use rustc_abi::VariantIdx;
+use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_middle::query::Key;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -60,7 +60,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
 
     let fields_iter = (0..field_count)
         .map(|i| {
-            let field_op = ecx.project_field(&down, i).discard_err()?;
+            let field_op = ecx.project_field(&down, FieldIdx::from_usize(i)).discard_err()?;
             let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true);
             Some((val, field_op.layout.ty))
         })
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 34239ae1d15..58d230af683 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,4 +1,4 @@
-use rustc_abi::{BackendRepr, VariantIdx};
+use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo};
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
@@ -40,7 +40,7 @@ fn branches<'tcx>(
     }
 
     for i in 0..field_count {
-        let field = ecx.project_field(&place, i).unwrap();
+        let field = ecx.project_field(&place, FieldIdx::from_usize(i)).unwrap();
         let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?;
         branches.push(valtree);
     }
@@ -437,7 +437,7 @@ fn valtree_into_mplace<'tcx>(
                     ty::Str | ty::Slice(_) | ty::Array(..) => {
                         ecx.project_index(place, i as u64).unwrap()
                     }
-                    _ => ecx.project_field(&place_adjusted, i).unwrap(),
+                    _ => ecx.project_field(&place_adjusted, FieldIdx::from_usize(i)).unwrap(),
                 };
 
                 debug!(?place_inner);
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 789baea0734..37677f9e048 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -62,7 +62,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     pub(super) fn fn_arg_field(
         &self,
         arg: &FnArg<'tcx, M::Provenance>,
-        field: usize,
+        field: FieldIdx,
     ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
         interp_ok(match arg {
             FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?),
@@ -600,10 +600,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                         Cow::from(
                             args.iter()
                                 .map(|a| interp_ok(a.clone()))
-                                .chain(
-                                    (0..untuple_arg.layout().fields.count())
-                                        .map(|i| self.fn_arg_field(untuple_arg, i)),
-                                )
+                                .chain((0..untuple_arg.layout().fields.count()).map(|i| {
+                                    self.fn_arg_field(untuple_arg, FieldIdx::from_usize(i))
+                                }))
                                 .collect::<InterpResult<'_, Vec<_>>>()?,
                         )
                     } else {
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 643a5805019..9e15f4572d7 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -1,6 +1,6 @@
 use std::assert_matches::assert_matches;
 
-use rustc_abi::Integer;
+use rustc_abi::{FieldIdx, Integer};
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_apfloat::{Float, FloatConvert};
 use rustc_middle::mir::CastKind;
@@ -484,6 +484,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let mut found_cast_field = false;
                 for i in 0..src.layout.fields.count() {
                     let cast_ty_field = cast_ty.field(self, i);
+                    let i = FieldIdx::from_usize(i);
                     let src_field = self.project_field(src, i)?;
                     let dst_field = self.project_field(dest, i)?;
                     if src_field.layout.is_1zst() && cast_ty_field.is_1zst() {
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 020cd65d75d..6c4b000e16b 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -26,7 +26,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 // No need to validate that the discriminant here because the
                 // `TyAndLayout::for_variant()` call earlier already checks the
                 // variant is valid.
-                let tag_dest = self.project_field(dest, tag_field.as_usize())?;
+                let tag_dest = self.project_field(dest, tag_field)?;
                 self.write_scalar(tag, &tag_dest)
             }
             None => {
@@ -96,7 +96,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?;
 
         // Read tag and sanity-check `tag_layout`.
-        let tag_val = self.read_immediate(&self.project_field(op, tag_field.as_usize())?)?;
+        let tag_val = self.read_immediate(&self.project_field(op, tag_field)?)?;
         assert_eq!(tag_layout.size, tag_val.layout.size);
         assert_eq!(tag_layout.backend_repr.is_signed(), tag_val.layout.backend_repr.is_signed());
         trace!("tag value: {}", tag_val);
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 39755169e6c..77667ba823a 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -12,6 +12,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
 use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, mir, span_bug, ty};
+use rustc_span::DUMMY_SP;
 use tracing::trace;
 
 use super::{
@@ -307,7 +308,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
     #[inline]
     pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
         // Can use any typing env, since `Ordering` is always monomorphic.
-        let ty = tcx.ty_ordering_enum(None);
+        let ty = tcx.ty_ordering_enum(DUMMY_SP);
         let layout =
             tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap();
         Self::from_scalar(Scalar::Int(c.into()), layout)
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 8ecb3e13d5c..ad47a19a14d 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -10,7 +10,7 @@
 use std::marker::PhantomData;
 use std::ops::Range;
 
-use rustc_abi::{self as abi, Size, VariantIdx};
+use rustc_abi::{self as abi, FieldIdx, Size, VariantIdx};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::{bug, mir, span_bug, ty};
@@ -144,22 +144,22 @@ where
     /// always possible without allocating, so it can take `&self`. Also return the field's layout.
     /// This supports both struct and array fields, but not slices!
     ///
-    /// This also works for arrays, but then the `usize` index type is restricting.
-    /// For indexing into arrays, use `mplace_index`.
+    /// This also works for arrays, but then the `FieldIdx` index type is restricting.
+    /// For indexing into arrays, use [`Self::project_index`].
     pub fn project_field<P: Projectable<'tcx, M::Provenance>>(
         &self,
         base: &P,
-        field: usize,
+        field: FieldIdx,
     ) -> InterpResult<'tcx, P> {
         // Slices nominally have length 0, so they will panic somewhere in `fields.offset`.
         debug_assert!(
             !matches!(base.layout().ty.kind(), ty::Slice(..)),
             "`field` projection called on a slice -- call `index` projection instead"
         );
-        let offset = base.layout().fields.offset(field);
+        let offset = base.layout().fields.offset(field.as_usize());
         // Computing the layout does normalization, so we get a normalized type out of this
         // even if the field type is non-normalized (possible e.g. via associated types).
-        let field_layout = base.layout().field(self, field);
+        let field_layout = base.layout().field(self, field.as_usize());
 
         // Offset may need adjustment for unsized fields.
         let (meta, offset) = if field_layout.is_unsized() {
@@ -244,7 +244,7 @@ where
             }
             _ => span_bug!(
                 self.cur_span(),
-                "`mplace_index` called on non-array type {:?}",
+                "`project_index` called on non-array type {:?}",
                 base.layout().ty
             ),
         };
@@ -260,7 +260,7 @@ where
     ) -> InterpResult<'tcx, (P, u64)> {
         assert!(base.layout().ty.ty_adt_def().unwrap().repr().simd());
         // SIMD types must be newtypes around arrays, so all we have to do is project to their only field.
-        let array = self.project_field(base, 0)?;
+        let array = self.project_field(base, FieldIdx::ZERO)?;
         let len = array.len(self)?;
         interp_ok((array, len))
     }
@@ -384,7 +384,7 @@ where
             UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?,
             // We don't want anything happening here, this is here as a dummy.
             Subtype(_) => base.transmute(base.layout(), self)?,
-            Field(field, _) => self.project_field(base, field.index())?,
+            Field(field, _) => self.project_field(base, field)?,
             Downcast(_, variant) => self.project_downcast(base, variant)?,
             Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
             Index(local) => {
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 975325b0c1e..833fcc38817 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -333,7 +333,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         }
         for (field_index, operand) in operands.iter_enumerated() {
             let field_index = active_field_index.unwrap_or(field_index);
-            let field_dest = self.project_field(&variant_dest, field_index.as_usize())?;
+            let field_dest = self.project_field(&variant_dest, field_index)?;
             let op = self.eval_operand(operand, Some(field_dest.layout))?;
             self.copy_op(&op, &field_dest)?;
         }
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index a5029eea5a7..7249ef23bf6 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -1,4 +1,4 @@
-use rustc_abi::{Align, Size};
+use rustc_abi::{Align, FieldIdx, Size};
 use rustc_middle::mir::interpret::{InterpResult, Pointer};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry};
@@ -137,8 +137,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
             "`unpack_dyn_star` only makes sense on `dyn*` types"
         );
-        let data = self.project_field(val, 0)?;
-        let vtable = self.project_field(val, 1)?;
+        let data = self.project_field(val, FieldIdx::ZERO)?;
+        let vtable = self.project_field(val, FieldIdx::ONE)?;
         let vtable = self.read_pointer(&vtable.to_op(self)?)?;
         let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?;
         // `data` is already the right thing but has the wrong type. So we transmute it.
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 3647c109a6e..5aea91233bd 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -112,8 +112,10 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
                 // So we transmute it to a raw pointer.
                 let raw_ptr_ty = Ty::new_mut_ptr(*self.ecx().tcx, self.ecx().tcx.types.unit);
                 let raw_ptr_ty = self.ecx().layout_of(raw_ptr_ty)?;
-                let vtable_field =
-                    self.ecx().project_field(v, 1)?.transmute(raw_ptr_ty, self.ecx())?;
+                let vtable_field = self
+                    .ecx()
+                    .project_field(v, FieldIdx::ONE)?
+                    .transmute(raw_ptr_ty, self.ecx())?;
                 self.visit_field(v, 1, &vtable_field)?;
 
                 // Then unpack the first field, and continue.
@@ -140,14 +142,16 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
 
                 // `Box` has two fields: the pointer we care about, and the allocator.
                 assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields");
-                let (unique_ptr, alloc) =
-                    (self.ecx().project_field(v, 0)?, self.ecx().project_field(v, 1)?);
+                let (unique_ptr, alloc) = (
+                    self.ecx().project_field(v, FieldIdx::ZERO)?,
+                    self.ecx().project_field(v, FieldIdx::ONE)?,
+                );
                 // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`...
                 // (which means another 2 fields, the second of which is a `PhantomData`)
                 assert_eq!(unique_ptr.layout().fields.count(), 2);
                 let (nonnull_ptr, phantom) = (
-                    self.ecx().project_field(&unique_ptr, 0)?,
-                    self.ecx().project_field(&unique_ptr, 1)?,
+                    self.ecx().project_field(&unique_ptr, FieldIdx::ZERO)?,
+                    self.ecx().project_field(&unique_ptr, FieldIdx::ONE)?,
                 );
                 assert!(
                     phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
@@ -156,7 +160,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
                 );
                 // ... that contains a `NonNull`... (gladly, only a single field here)
                 assert_eq!(nonnull_ptr.layout().fields.count(), 1);
-                let raw_ptr = self.ecx().project_field(&nonnull_ptr, 0)?; // the actual raw ptr
+                let raw_ptr = self.ecx().project_field(&nonnull_ptr, FieldIdx::ZERO)?; // the actual raw ptr
                 // ... whose only field finally is a raw ptr we can dereference.
                 self.visit_box(ty, &raw_ptr)?;
 
@@ -188,9 +192,8 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
             }
             FieldsShape::Arbitrary { memory_index, .. } => {
                 for idx in Self::aggregate_field_iter(memory_index) {
-                    let idx = idx.as_usize();
                     let field = self.ecx().project_field(v, idx)?;
-                    self.visit_field(v, idx, &field)?;
+                    self.visit_field(v, idx.as_usize(), &field)?;
                 }
             }
             FieldsShape::Array { .. } => {
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 9c867cc615e..671214002a0 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -1,3 +1,4 @@
+use rustc_abi::FieldIdx;
 use rustc_hir::LangItem;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, TyCtxt};
@@ -35,17 +36,20 @@ fn alloc_caller_location<'tcx>(
     // Allocate memory for `CallerLocation` struct.
     let loc_ty = ecx
         .tcx
-        .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, None))
+        .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, ecx.tcx.span))
         .instantiate(*ecx.tcx, ecx.tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()]));
     let loc_layout = ecx.layout_of(loc_ty).unwrap();
     let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
 
     // Initialize fields.
-    ecx.write_immediate(file_wide_ptr, &ecx.project_field(&location, 0).unwrap())
+    ecx.write_immediate(
+        file_wide_ptr,
+        &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap(),
+    )
+    .expect("writing to memory we just allocated cannot fail");
+    ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap())
         .expect("writing to memory we just allocated cannot fail");
-    ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap())
-        .expect("writing to memory we just allocated cannot fail");
-    ecx.write_scalar(col, &ecx.project_field(&location, 2).unwrap())
+    ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap())
         .expect("writing to memory we just allocated cannot fail");
 
     location
diff --git a/compiler/rustc_error_codes/src/error_codes/E0783.md b/compiler/rustc_error_codes/src/error_codes/E0783.md
index 73981e59e0d..ac8641cfc5a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0783.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0783.md
@@ -9,7 +9,7 @@ match 2u8 {
 }
 ```
 
-Older Rust code using previous editions allowed `...` to stand for exclusive
+Older Rust code using previous editions allowed `...` to stand for inclusive
 ranges which are now signified using `..=`.
 
 To make this code compile replace the `...` with `..=`.
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 2accfba383e..c7b975d8f3e 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -167,7 +167,7 @@ impl Annotatable {
 
     pub fn expect_stmt(self) -> ast::Stmt {
         match self {
-            Annotatable::Stmt(stmt) => stmt.into_inner(),
+            Annotatable::Stmt(stmt) => *stmt,
             _ => panic!("expected statement"),
         }
     }
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 82a2719ca96..569165a64e5 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1183,9 +1183,8 @@ impl InvocationCollectorNode for P<ast::Item> {
         matches!(self.kind, ItemKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let node = self.into_inner();
-        match node.kind {
-            ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+        match self.kind {
+            ItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No),
             _ => unreachable!(),
         }
     }
@@ -1339,7 +1338,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag>
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let item = self.wrapped.into_inner();
+        let item = self.wrapped;
         match item.kind {
             AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
             _ => unreachable!(),
@@ -1380,7 +1379,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag>
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let item = self.wrapped.into_inner();
+        let item = self.wrapped;
         match item.kind {
             AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
             _ => unreachable!(),
@@ -1421,7 +1420,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitImplItem
         matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let item = self.wrapped.into_inner();
+        let item = self.wrapped;
         match item.kind {
             AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
             _ => unreachable!(),
@@ -1459,9 +1458,8 @@ impl InvocationCollectorNode for P<ast::ForeignItem> {
         matches!(self.kind, ForeignItemKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let node = self.into_inner();
-        match node.kind {
-            ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+        match self.kind {
+            ForeignItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No),
             _ => unreachable!(),
         }
     }
@@ -1596,16 +1594,16 @@ impl InvocationCollectorNode for ast::Stmt {
         // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
         let (add_semicolon, mac, attrs) = match self.kind {
             StmtKind::MacCall(mac) => {
-                let ast::MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
+                let ast::MacCallStmt { mac, style, attrs, .. } = *mac;
                 (style == MacStmtStyle::Semicolon, mac, attrs)
             }
-            StmtKind::Item(item) => match item.into_inner() {
+            StmtKind::Item(item) => match *item {
                 ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
                     (mac.args.need_semicolon(), mac, attrs)
                 }
                 _ => unreachable!(),
             },
-            StmtKind::Semi(expr) => match expr.into_inner() {
+            StmtKind::Semi(expr) => match *expr {
                 ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => {
                     (mac.args.need_semicolon(), mac, attrs)
                 }
@@ -1686,8 +1684,7 @@ impl InvocationCollectorNode for P<ast::Ty> {
         matches!(self.kind, ast::TyKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let node = self.into_inner();
-        match node.kind {
+        match self.kind {
             TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),
             _ => unreachable!(),
         }
@@ -1710,8 +1707,7 @@ impl InvocationCollectorNode for P<ast::Pat> {
         matches!(self.kind, PatKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let node = self.into_inner();
-        match node.kind {
+        match self.kind {
             PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No),
             _ => unreachable!(),
         }
@@ -1737,9 +1733,8 @@ impl InvocationCollectorNode for P<ast::Expr> {
         matches!(self.kind, ExprKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let node = self.into_inner();
-        match node.kind {
-            ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+        match self.kind {
+            ExprKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No),
             _ => unreachable!(),
         }
     }
@@ -1763,7 +1758,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> {
         matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let node = self.wrapped.into_inner();
+        let node = self.wrapped;
         match node.kind {
             ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
             _ => unreachable!(),
@@ -1797,7 +1792,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag>
         matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
     }
     fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) {
-        let node = self.wrapped.into_inner();
+        let node = self.wrapped;
         match node.kind {
             ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
             _ => unreachable!(),
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index bcf0353498e..8c52f5dbbbe 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -97,7 +97,7 @@ fn allowed_union_or_unsafe_field<'tcx>(
     let def_id = tcx
         .lang_items()
         .get(LangItem::BikeshedGuaranteedNoDrop)
-        .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, Some(span)));
+        .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, span));
     let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) else {
         tcx.dcx().span_delayed_bug(span, "could not normalize field type");
         return true;
@@ -1142,7 +1142,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
             return;
         };
 
-        if let Some(second_field) = fields.get(FieldIdx::from_u32(1)) {
+        if let Some(second_field) = fields.get(FieldIdx::ONE) {
             struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields")
                 .with_span_label(tcx.def_span(second_field.did), "excess field")
                 .emit();
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 09610a2f3ec..234520c1583 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -180,7 +180,7 @@ pub(crate) fn check_intrinsic_type(
         ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),
     ]);
     let mk_va_list_ty = |mutbl| {
-        let did = tcx.require_lang_item(LangItem::VaList, Some(span));
+        let did = tcx.require_lang_item(LangItem::VaList, span);
         let region = ty::Region::new_bound(
             tcx,
             ty::INNERMOST,
@@ -442,9 +442,7 @@ pub(crate) fn check_intrinsic_type(
 
             sym::bswap | sym::bitreverse => (1, 0, vec![param(0)], param(0)),
 
-            sym::three_way_compare => {
-                (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span)))
-            }
+            sym::three_way_compare => (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(span)),
 
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
                 (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
@@ -520,7 +518,7 @@ pub(crate) fn check_intrinsic_type(
 
             sym::discriminant_value => {
                 let assoc_items = tcx.associated_item_def_ids(
-                    tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
+                    tcx.require_lang_item(hir::LangItem::DiscriminantKind, span),
                 );
                 let discriminant_def_id = assoc_items[0];
 
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 00316682df8..b8dc01cbc03 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -969,7 +969,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                         ),
                         wfcx.param_env,
                         ty,
-                        tcx.require_lang_item(LangItem::UnsizedConstParamTy, Some(hir_ty.span)),
+                        tcx.require_lang_item(LangItem::UnsizedConstParamTy, hir_ty.span),
                     );
                     Ok(())
                 })
@@ -983,7 +983,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                         ),
                         wfcx.param_env,
                         ty,
-                        tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)),
+                        tcx.require_lang_item(LangItem::ConstParamTy, hir_ty.span),
                     );
                     Ok(())
                 })
@@ -1232,7 +1232,7 @@ fn check_type_defn<'tcx>(
                     ),
                     wfcx.param_env,
                     ty,
-                    tcx.require_lang_item(LangItem::Sized, Some(hir_ty.span)),
+                    tcx.require_lang_item(LangItem::Sized, hir_ty.span),
                 );
             }
 
@@ -1356,7 +1356,7 @@ fn check_static_item(
                 ),
                 wfcx.param_env,
                 item_ty,
-                tcx.require_lang_item(LangItem::Sized, Some(ty_span)),
+                tcx.require_lang_item(LangItem::Sized, ty_span),
             );
         }
 
@@ -1375,7 +1375,7 @@ fn check_static_item(
                 ),
                 wfcx.param_env,
                 item_ty,
-                tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
+                tcx.require_lang_item(LangItem::Sync, ty_span),
             );
         }
         Ok(())
@@ -1401,7 +1401,7 @@ fn check_const_item(
             ),
             wfcx.param_env,
             ty,
-            tcx.require_lang_item(LangItem::Sized, None),
+            tcx.require_lang_item(LangItem::Sized, ty_span),
         );
 
         check_where_clauses(wfcx, item_span, def_id);
@@ -1725,13 +1725,13 @@ fn check_fn_or_method<'tcx>(
                 ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall),
                 wfcx.param_env,
                 *ty,
-                tcx.require_lang_item(hir::LangItem::Tuple, Some(span)),
+                tcx.require_lang_item(hir::LangItem::Tuple, span),
             );
             wfcx.register_bound(
                 ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall),
                 wfcx.param_env,
                 *ty,
-                tcx.require_lang_item(hir::LangItem::Sized, Some(span)),
+                tcx.require_lang_item(hir::LangItem::Sized, span),
             );
         } else {
             tcx.dcx().span_err(
@@ -1776,7 +1776,7 @@ fn check_sized_if_body<'tcx>(
             ObligationCause::new(span, def_id, code),
             wfcx.param_env,
             ty,
-            tcx.require_lang_item(LangItem::Sized, Some(span)),
+            tcx.require_lang_item(LangItem::Sized, span),
         );
     }
 }
@@ -2013,7 +2013,7 @@ fn receiver_is_valid<'tcx>(
         // deref chain implement `LegacyReceiver`.
         if arbitrary_self_types_enabled.is_none() {
             let legacy_receiver_trait_def_id =
-                tcx.require_lang_item(LangItem::LegacyReceiver, Some(span));
+                tcx.require_lang_item(LangItem::LegacyReceiver, span);
             if !legacy_receiver_is_implemented(
                 wfcx,
                 legacy_receiver_trait_def_id,
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b92d1d7104f..4779f4fb702 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -225,7 +225,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
     // redundant errors for `DispatchFromDyn`. This is best effort, though.
     let mut res = Ok(());
     tcx.for_each_relevant_impl(
-        tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)),
+        tcx.require_lang_item(LangItem::CoerceUnsized, span),
         source,
         |impl_def_id| {
             res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id));
@@ -379,8 +379,8 @@ pub(crate) fn coerce_unsized_info<'tcx>(
     let span = tcx.def_span(impl_did);
     let trait_name = "CoerceUnsized";
 
-    let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
-    let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
+    let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span);
+    let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);
 
     let source = tcx.type_of(impl_did).instantiate_identity();
     let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
@@ -591,7 +591,7 @@ fn infringing_fields_error<'tcx>(
     impl_did: LocalDefId,
     impl_span: Span,
 ) -> ErrorGuaranteed {
-    let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
+    let trait_did = tcx.require_lang_item(lang_item, impl_span);
 
     let trait_name = tcx.def_path_str(trait_did);
 
@@ -748,7 +748,7 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
                         ObligationCause::misc(impl_span, checker.impl_def_id),
                         param_env,
                         nontrivial_field_ty,
-                        tcx.require_lang_item(LangItem::PointerLike, Some(impl_span)),
+                        tcx.require_lang_item(LangItem::PointerLike, impl_span),
                     );
                     // FIXME(dyn-star): We should regionck this implementation.
                     if ocx.select_all_or_error().is_empty() {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index 21f0f9648ea..3a26b8331f8 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -73,7 +73,7 @@ fn generic_arg_mismatch_err(
                     let param_name = tcx.hir_ty_param_name(param_local_id);
                     let param_type = tcx.type_of(param.def_id).instantiate_identity();
                     if param_type.is_suggestable(tcx, false) {
-                        err.span_suggestion(
+                        err.span_suggestion_verbose(
                             tcx.def_span(src_def_id),
                             "consider changing this type parameter to a const parameter",
                             format!("const {param_name}: {param_type}"),
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 2a37a8bdbd4..4c65d0d0510 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2590,7 +2590,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
             }
             &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
-                let def_id = tcx.require_lang_item(lang_item, Some(span));
+                let def_id = tcx.require_lang_item(lang_item, span);
                 let (args, _) = self.lower_generic_args_of_path(
                     span,
                     def_id,
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 5e79d10612d..6c33dfb4ec0 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -137,6 +137,18 @@ hir_typeck_lossy_provenance_ptr2int =
 
 hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
 
+hir_typeck_naked_asm_outside_naked_fn =
+    the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
+
+hir_typeck_naked_functions_asm_block =
+    naked functions must contain a single `naked_asm!` invocation
+    .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
+    .label_non_asm = not allowed in naked functions
+
+hir_typeck_naked_functions_must_naked_asm =
+    the `asm!` macro is not allowed in naked functions
+    .label = consider using the `naked_asm!` macro instead
+
 hir_typeck_never_type_fallback_flowing_into_unsafe_call = never type fallback affects this call to an `unsafe` function
     .help = specify the type explicitly
 hir_typeck_never_type_fallback_flowing_into_unsafe_deref = never type fallback affects this raw pointer dereference
@@ -159,6 +171,9 @@ hir_typeck_no_field_on_variant = no field named `{$field}` on enum variant `{$co
 hir_typeck_no_field_on_variant_enum = this enum variant...
 hir_typeck_no_field_on_variant_field = ...does not have this field
 
+hir_typeck_no_patterns =
+    patterns not allowed in naked function parameters
+
 hir_typeck_note_caller_chooses_ty_for_ty_param = the caller chooses a type for `{$ty_param_name}` which can be different from `{$found_ty}`
 
 hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
@@ -167,6 +182,10 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
 hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
 hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
 
+hir_typeck_params_not_allowed =
+    referencing function parameters is not allowed in naked functions
+    .help = follow the calling convention in asm block to use parameters
+
 hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function
     .suggestion = cast the value to `{$cast_ty}`
     .teach_help = certain types, like `{$ty}`, must be cast before passing them to a variadic function to match the implicit cast that a C compiler would perform as part of C's numeric promotion rules
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index f555d116c52..d173fe7c2c2 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -508,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let Some(ty) = fn_sig.inputs().last().copied() {
                 self.register_bound(
                     ty,
-                    self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
+                    self.tcx.require_lang_item(hir::LangItem::Tuple, sp),
                     self.cause(sp, ObligationCauseCode::RustCall),
                 );
                 self.require_type_is_sized(ty, sp, ObligationCauseCode::RustCall);
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 99103f14d68..ac42eebf08c 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -57,7 +57,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     // (as it's created inside the body itself, not passed in from outside).
     let maybe_va_list = fn_sig.c_variadic.then(|| {
         let span = body.params.last().unwrap().span;
-        let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span));
+        let va_list_did = tcx.require_lang_item(LangItem::VaList, span);
         let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span));
 
         tcx.type_of(va_list_did).instantiate(tcx, &[region.into()])
@@ -178,7 +178,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>
         tcx.dcx().span_err(span, "should have no const parameters");
     }
 
-    let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, Some(span));
+    let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, span);
 
     // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !`
     let panic_info_ty = tcx.type_of(panic_info_did).instantiate(
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index cd3746be1d1..459c0498d50 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -142,13 +142,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                         Ty::new_adt(
                             tcx,
-                            tcx.adt_def(
-                                tcx.require_lang_item(hir::LangItem::Poll, Some(expr_span)),
-                            ),
+                            tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, expr_span)),
                             tcx.mk_args(&[Ty::new_adt(
                                 tcx,
                                 tcx.adt_def(
-                                    tcx.require_lang_item(hir::LangItem::Option, Some(expr_span)),
+                                    tcx.require_lang_item(hir::LangItem::Option, expr_span),
                                 ),
                                 tcx.mk_args(&[yield_ty.into()]),
                             )
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index ddc80fab2ce..d9fa56fefeb 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -760,8 +760,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     self.param_env,
                     ty::TraitRef::new(
                         self.tcx,
-                        self.tcx
-                            .require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)),
+                        self.tcx.require_lang_item(hir::LangItem::PointerLike, self.cause.span),
                         [a],
                     ),
                 ),
@@ -1969,7 +1968,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 fcx.param_env,
                 ty::TraitRef::new(
                     fcx.tcx,
-                    fcx.tcx.require_lang_item(hir::LangItem::Sized, None),
+                    fcx.tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP),
                     [sig.output()],
                 ),
             ))
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 06103fe1c91..97a90548fc5 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -4,8 +4,8 @@ use std::borrow::Cow;
 
 use rustc_errors::codes::*;
 use rustc_errors::{
-    Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan,
-    Subdiagnostic,
+    Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic,
+    EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
@@ -983,3 +983,55 @@ pub(crate) struct RegisterTypeUnstable<'a> {
     pub span: Span,
     pub ty: Ty<'a>,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_naked_asm_outside_naked_fn)]
+pub(crate) struct NakedAsmOutsideNakedFn {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_no_patterns)]
+pub(crate) struct NoPatterns {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_params_not_allowed)]
+#[help]
+pub(crate) struct ParamsNotAllowed {
+    #[primary_span]
+    pub span: Span,
+}
+
+pub(crate) struct NakedFunctionsAsmBlock {
+    pub span: Span,
+    pub multiple_asms: Vec<Span>,
+    pub non_asms: Vec<Span>,
+}
+
+impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
+    #[track_caller]
+    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+        let mut diag = Diag::new(dcx, level, fluent::hir_typeck_naked_functions_asm_block);
+        diag.span(self.span);
+        diag.code(E0787);
+        for span in self.multiple_asms.iter() {
+            diag.span_label(*span, fluent::hir_typeck_label_multiple_asm);
+        }
+        for span in self.non_asms.iter() {
+            diag.span_label(*span, fluent::hir_typeck_label_non_asm);
+        }
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_naked_functions_must_naked_asm, code = E0787)]
+pub(crate) struct NakedFunctionsMustNakedAsm {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 082ddac7e5a..dfc7935d02b 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -44,9 +44,9 @@ use crate::errors::{
     AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr,
     BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove,
     CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
-    HelpUseLatestEdition, NoFieldOnType, NoFieldOnVariant, ReturnLikeStatementKind,
-    ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo,
-    YieldExprOutsideOfCoroutine,
+    HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, NoFieldOnVariant,
+    ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive,
+    TypeMismatchFruTypo, YieldExprOutsideOfCoroutine,
 };
 use crate::{
     BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs,
@@ -524,7 +524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             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)
+                self.check_expr_asm(asm, expr.span)
             }
             ExprKind::OffsetOf(container, fields) => {
                 self.check_expr_offset_of(container, fields, expr)
@@ -1407,7 +1407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let lhs_deref_ty_is_sized = self
                     .infcx
                     .type_implements_trait(
-                        self.tcx.require_lang_item(LangItem::Sized, None),
+                        self.tcx.require_lang_item(LangItem::Sized, span),
                         [lhs_deref_ty],
                         self.param_env,
                     )
@@ -3761,7 +3761,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> {
+    fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) -> Ty<'tcx> {
+        if let rustc_ast::AsmMacro::NakedAsm = asm.asm_macro {
+            if !self.tcx.has_attr(self.body_id, sym::naked) {
+                self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span });
+            }
+        }
+
         let mut diverge = asm.asm_macro.diverges(asm.options);
 
         for (op, _op_sp) in asm.operands {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 362c7d8efac..8a90e768d70 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         code: traits::ObligationCauseCode<'tcx>,
     ) {
         if !ty.references_error() {
-            let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+            let lang_item = self.tcx.require_lang_item(LangItem::Sized, span);
             self.require_type_meets(ty, span, code, lang_item);
         }
     }
@@ -443,7 +443,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Nothing else is required here.
             } else {
                 // We can't be sure, let's required full `Sized`.
-                let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+                let lang_item = self.tcx.require_lang_item(LangItem::Sized, span);
                 self.require_type_meets(ty, span, ObligationCauseCode::Misc, lang_item);
             }
         }
@@ -732,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         hir_id: HirId,
     ) -> (Res, Ty<'tcx>) {
-        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
+        let def_id = self.tcx.require_lang_item(lang_item, span);
         let def_kind = self.tcx.def_kind(def_id);
 
         let item_ty = if let DefKind::Variant = def_kind {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 59aba6fae5e..95c7f251c88 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -165,7 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => traits::IsConstable::No,
             };
 
-            let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
+            let lang_item = self.tcx.require_lang_item(LangItem::Copy, element.span);
             let code = traits::ObligationCauseCode::RepeatElementCopy {
                 is_constable,
                 elt_span: element.span,
@@ -1680,8 +1680,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ast::LitKind::CStr(_, _) => Ty::new_imm_ref(
                 tcx,
                 tcx.lifetimes.re_static,
-                tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
-                    .skip_binder(),
+                tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, lit.span)).skip_binder(),
             ),
             ast::LitKind::Err(guar) => Ty::new_error(tcx, guar),
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 1c3bc338d85..66af085cfd4 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -2679,7 +2679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let mut sugg_sp = sp;
                     if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind {
                         let clone_trait =
-                            self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
+                            self.tcx.require_lang_item(LangItem::Clone, segment.ident.span);
                         if args.is_empty()
                             && self
                                 .typeck_results
diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs
index 6399f0a78ae..b59c1752c25 100644
--- a/compiler/rustc_hir_typeck/src/inline_asm.rs
+++ b/compiler/rustc_hir_typeck/src/inline_asm.rs
@@ -171,7 +171,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             _ if ty.references_error() => return None,
             ty::Adt(adt, args) if self.tcx().is_lang_item(adt.did(), LangItem::MaybeUninit) => {
                 let fields = &adt.non_enum_variant().fields;
-                let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx(), args);
+                let ty = fields[FieldIdx::ONE].ty(self.tcx(), args);
                 // FIXME: Are we just trying to map to the `T` in `MaybeUninit<T>`?
                 // If so, just get it from the args.
                 let ty::Adt(ty, args) = ty.kind() else {
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 5a814822163..b0346f8d32e 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -31,6 +31,7 @@ mod fn_ctxt;
 mod gather_locals;
 mod intrinsicck;
 mod method;
+mod naked_functions;
 mod op;
 mod opaque_types;
 mod pat;
@@ -55,8 +56,8 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config;
-use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
+use rustc_span::{Span, sym};
 use tracing::{debug, instrument};
 use typeck_root_ctxt::TypeckRootCtxt;
 
@@ -170,6 +171,10 @@ fn typeck_with_inspect<'tcx>(
                 .map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)),
         );
 
+        if tcx.has_attr(def_id, sym::naked) {
+            naked_functions::typeck_naked_fn(tcx, def_id, body);
+        }
+
         check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params());
     } else {
         let expected_type = if let Some(infer_ty) = infer_type_if_missing(&fcx, node) {
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_hir_typeck/src/naked_functions.rs
index 3c9f8b72c36..2518d6478e6 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_hir_typeck/src/naked_functions.rs
@@ -1,56 +1,29 @@
 //! Checks validity of naked functions.
 
 use rustc_hir as hir;
-use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{LocalDefId, LocalModDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ExprKind, HirIdSet, StmtKind};
-use rustc_middle::hir::nested_filter::OnlyBodies;
-use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::{Span, sym};
 
 use crate::errors::{
-    NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
-    ParamsNotAllowed,
+    NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed,
 };
 
-pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { check_mod_naked_functions, ..*providers };
-}
-
-fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
-    let items = tcx.hir_module_items(module_def_id);
-    for def_id in items.definitions() {
-        if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
-            continue;
-        }
-
-        let body = match tcx.hir_node_by_def_id(def_id) {
-            hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Fn { body: body_id, .. }, ..
-            })
-            | hir::Node::TraitItem(hir::TraitItem {
-                kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)),
-                ..
-            })
-            | hir::Node::ImplItem(hir::ImplItem {
-                kind: hir::ImplItemKind::Fn(_, body_id), ..
-            }) => tcx.hir_body(*body_id),
-            _ => continue,
-        };
-
-        if tcx.has_attr(def_id, sym::naked) {
-            check_no_patterns(tcx, body.params);
-            check_no_parameters_use(tcx, body);
-            check_asm(tcx, def_id, body);
-        } else {
-            // `naked_asm!` is not allowed outside of functions marked as `#[naked]`
-            let mut visitor = CheckNakedAsmInNakedFn { tcx };
-            visitor.visit_body(body);
-        }
-    }
+/// Naked fns can only have trivial binding patterns in arguments,
+/// may not actually use those arguments, and the body must consist of just
+/// a single asm statement.
+pub(crate) fn typeck_naked_fn<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    def_id: LocalDefId,
+    body: &'tcx hir::Body<'tcx>,
+) {
+    debug_assert!(tcx.has_attr(def_id, sym::naked));
+    check_no_patterns(tcx, body.params);
+    check_no_parameters_use(tcx, body);
+    check_asm(tcx, def_id, body);
 }
 
 /// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
@@ -231,25 +204,3 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly {
         self.check_expr(expr, expr.span);
     }
 }
-
-struct CheckNakedAsmInNakedFn<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> Visitor<'tcx> for CheckNakedAsmInNakedFn<'tcx> {
-    type NestedFilter = OnlyBodies;
-
-    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
-        self.tcx
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        if let ExprKind::InlineAsm(inline_asm) = expr.kind {
-            if let rustc_ast::AsmMacro::NakedAsm = inline_asm.asm_macro {
-                self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span: expr.span });
-            }
-        }
-
-        hir::intravisit::walk_expr(self, expr);
-    }
-}
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 17d48184dd9..432eeae8016 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -796,7 +796,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if *negated {
                     self.register_bound(
                         ty,
-                        self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)),
+                        self.tcx.require_lang_item(LangItem::Neg, lt.span),
                         ObligationCause::dummy_with_span(lt.span),
                     );
                 }
@@ -2553,13 +2553,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
         self.register_bound(
             source_ty,
-            tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)),
+            tcx.require_lang_item(hir::LangItem::DerefPure, span),
             self.misc(span),
         );
         // The expected type for the deref pat's inner pattern is `<expected as Deref>::Target`.
         let target_ty = Ty::new_projection(
             tcx,
-            tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
+            tcx.require_lang_item(hir::LangItem::DerefTarget, span),
             [source_ty],
         );
         let target_ty = self.normalize(span, target_ty);
@@ -2580,7 +2580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             for mutably_derefed_ty in derefed_tys {
                 self.register_bound(
                     mutably_derefed_ty,
-                    self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
+                    self.tcx.require_lang_item(hir::LangItem::DerefMut, span),
                     self.misc(span),
                 );
             }
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 4b2e87f5674..5b5253c7e7e 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -1560,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let is_drop_defined_for_ty = |ty: Ty<'tcx>| {
-            let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span));
+            let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, closure_span);
             self.infcx
                 .type_implements_trait(drop_trait, [ty], self.tcx.param_env(closure_def_id))
                 .must_apply_modulo_regions()
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index ab65da3913d..df5a66243fc 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -53,7 +53,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
         assert!(entry.is_some());
     }
 
-    pub(crate) fn is_empty(&self) -> bool {
+    pub fn is_empty(&self) -> bool {
         let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
         opaque_types.is_empty() && duplicate_entries.is_empty()
     }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index f4045eeea4d..ee41df6b1f6 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -956,7 +956,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
                 tcx.par_hir_for_each_module(|module| {
                     tcx.ensure_ok().check_mod_loops(module);
                     tcx.ensure_ok().check_mod_attrs(module);
-                    tcx.ensure_ok().check_mod_naked_functions(module);
                     tcx.ensure_ok().check_mod_unstable_api_usage(module);
                 });
             },
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index 526693d3de1..165262b82c7 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -68,7 +68,7 @@ impl<'a> Cursor<'a> {
 
     /// Peeks the third symbol from the input stream without consuming it.
     pub fn third(&self) -> char {
-        // `.next()` optimizes better than `.nth(1)`
+        // `.next()` optimizes better than `.nth(2)`
         let mut iter = self.chars.clone();
         iter.next();
         iter.next();
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index ece3f9107b0..b2bd5e188ef 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -30,14 +30,13 @@ mod cursor;
 #[cfg(test)]
 mod tests;
 
+use LiteralKind::*;
+use TokenKind::*;
+use cursor::EOF_CHAR;
+pub use cursor::{Cursor, FrontmatterAllowed};
 use unicode_properties::UnicodeEmoji;
 pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION;
 
-use self::LiteralKind::*;
-use self::TokenKind::*;
-use crate::cursor::EOF_CHAR;
-pub use crate::cursor::{Cursor, FrontmatterAllowed};
-
 /// Parsed token.
 /// It doesn't contain information about data that has been parsed,
 /// only the type of the token and its size.
@@ -372,9 +371,8 @@ pub fn is_ident(string: &str) -> bool {
 impl Cursor<'_> {
     /// Parses a token from the input string.
     pub fn advance_token(&mut self) -> Token {
-        let first_char = match self.bump() {
-            Some(c) => c,
-            None => return Token::new(TokenKind::Eof, 0),
+        let Some(first_char) = self.bump() else {
+            return Token::new(TokenKind::Eof, 0);
         };
 
         let token_kind = match first_char {
@@ -788,7 +786,7 @@ impl Cursor<'_> {
         } else {
             // No base prefix, parse number in the usual way.
             self.eat_decimal_digits();
-        };
+        }
 
         match self.first() {
             // Don't be greedy if this is actually an
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 47b80135bae..69e9f8e1b2c 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -39,7 +39,7 @@ pub use rustc_session::lint::builtin::*;
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
-use rustc_span::{BytePos, Ident, InnerSpan, Span, Symbol, kw, sym};
+use rustc_span::{BytePos, DUMMY_SP, Ident, InnerSpan, Span, Symbol, kw, sym};
 use rustc_target::asm::InlineAsmArch;
 use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
 use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy;
@@ -635,7 +635,8 @@ fn type_implements_negative_copy_modulo_regions<'tcx>(
     typing_env: ty::TypingEnv<'tcx>,
 ) -> bool {
     let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
-    let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]);
+    let trait_ref =
+        ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, DUMMY_SP), [ty]);
     let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative };
     let obligation = traits::Obligation {
         cause: traits::ObligationCause::dummy(),
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index bd315577efb..6c6b12fed67 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -95,7 +95,7 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence {
 #[diag(middle_requires_lang_item)]
 pub(crate) struct RequiresLangItem {
     #[primary_span]
-    pub span: Option<Span>,
+    pub span: Span,
     pub name: Symbol,
 }
 
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index 0f92c1910f1..93264f02cc2 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -17,7 +17,7 @@ use crate::ty::{self, TyCtxt};
 impl<'tcx> TyCtxt<'tcx> {
     /// Returns the `DefId` for a given `LangItem`.
     /// If not found, fatally aborts compilation.
-    pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId {
+    pub fn require_lang_item(self, lang_item: LangItem, span: Span) -> DefId {
         self.lang_items().get(lang_item).unwrap_or_else(|| {
             self.dcx().emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() });
         })
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 06e41e64fdc..d98b40f0fcf 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -835,7 +835,7 @@ impl<'tcx> BinOp {
             &BinOp::Cmp => {
                 // these should be integer-like types of the same size.
                 assert_eq!(lhs_ty, rhs_ty);
-                tcx.ty_ordering_enum(None)
+                tcx.ty_ordering_enum(DUMMY_SP)
             }
         }
     }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d900e16b005..d03f01bf863 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1120,10 +1120,6 @@ rustc_queries! {
         desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
     }
 
-    query check_mod_naked_functions(key: LocalModDefId) {
-        desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) }
-    }
-
     query check_mod_privacy(key: LocalModDefId) {
         desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
     }
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index a61a6c571a2..3bacdfe5ac8 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -128,8 +128,8 @@ impl OverloadedDeref {
     /// for this overloaded deref's mutability.
     pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>) -> DefId {
         let trait_def_id = match self.mutbl {
-            hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None),
-            hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None),
+            hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, self.span),
+            hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, self.span),
         };
         tcx.associated_items(trait_def_id)
             .in_definition_order()
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 57b20a1bba6..0b1e9852d2a 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -458,7 +458,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     }
 
     fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId {
-        self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None)
+        self.require_lang_item(trait_lang_item_to_lang_item(lang_item), DUMMY_SP)
     }
 
     fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool {
@@ -1710,7 +1710,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Gets a `Ty` representing the [`LangItem::OrderingEnum`]
     #[track_caller]
-    pub fn ty_ordering_enum(self, span: Option<Span>) -> Ty<'tcx> {
+    pub fn ty_ordering_enum(self, span: Span) -> Ty<'tcx> {
         let ordering_enum = self.require_lang_item(hir::LangItem::OrderingEnum, span);
         self.type_of(ordering_enum).no_bound_vars().unwrap()
     }
@@ -2253,7 +2253,7 @@ impl<'tcx> TyCtxt<'tcx> {
         Ty::new_imm_ref(
             self,
             self.lifetimes.re_static,
-            self.type_of(self.require_lang_item(LangItem::PanicLocation, None))
+            self.type_of(self.require_lang_item(LangItem::PanicLocation, DUMMY_SP))
                 .instantiate(self, self.mk_args(&[self.lifetimes.re_static.into()])),
         )
     }
@@ -2712,7 +2712,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Given a `ty`, return whether it's an `impl Future<...>`.
     pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool {
         let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
-        let future_trait = self.require_lang_item(LangItem::Future, None);
+        let future_trait = self.require_lang_item(LangItem::Future, DUMMY_SP);
 
         self.explicit_item_self_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| {
             let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 0d99a1b5149..5ba4e5446e9 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -786,7 +786,7 @@ impl<'tcx> Instance<'tcx> {
     }
 
     pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
-        let def_id = tcx.require_lang_item(LangItem::DropInPlace, None);
+        let def_id = tcx.require_lang_item(LangItem::DropInPlace, DUMMY_SP);
         let args = tcx.mk_args(&[ty.into()]);
         Instance::expect_resolve(
             tcx,
@@ -798,7 +798,7 @@ impl<'tcx> Instance<'tcx> {
     }
 
     pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
-        let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None);
+        let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, DUMMY_SP);
         let args = tcx.mk_args(&[ty.into()]);
         Instance::expect_resolve(
             tcx,
@@ -824,7 +824,7 @@ impl<'tcx> Instance<'tcx> {
         closure_did: DefId,
         args: ty::GenericArgsRef<'tcx>,
     ) -> Instance<'tcx> {
-        let fn_once = tcx.require_lang_item(LangItem::FnOnce, None);
+        let fn_once = tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP);
         let call_once = tcx
             .associated_items(fn_once)
             .in_definition_order()
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 404674c359e..cbf545c01c5 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -593,7 +593,7 @@ impl<'tcx> Ty<'tcx> {
         ty: Ty<'tcx>,
         mutbl: ty::Mutability,
     ) -> Ty<'tcx> {
-        let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None));
+        let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, DUMMY_SP));
         Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()]))
     }
 
@@ -857,19 +857,19 @@ impl<'tcx> Ty<'tcx> {
 
     #[inline]
     pub fn new_box(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let def_id = tcx.require_lang_item(LangItem::OwnedBox, None);
+        let def_id = tcx.require_lang_item(LangItem::OwnedBox, DUMMY_SP);
         Ty::new_generic_adt(tcx, def_id, ty)
     }
 
     #[inline]
     pub fn new_maybe_uninit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None);
+        let def_id = tcx.require_lang_item(LangItem::MaybeUninit, DUMMY_SP);
         Ty::new_generic_adt(tcx, def_id, ty)
     }
 
     /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes.
     pub fn new_task_context(tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        let context_did = tcx.require_lang_item(LangItem::Context, None);
+        let context_did = tcx.require_lang_item(LangItem::Context, DUMMY_SP);
         let context_adt_ref = tcx.adt_def(context_did);
         let context_args = tcx.mk_args(&[tcx.lifetimes.re_erased.into()]);
         let context_ty = Ty::new_adt(tcx, context_adt_ref, context_args);
@@ -1549,7 +1549,7 @@ impl<'tcx> Ty<'tcx> {
 
             ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => {
                 let assoc_items = tcx.associated_item_def_ids(
-                    tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
+                    tcx.require_lang_item(hir::LangItem::DiscriminantKind, DUMMY_SP),
                 );
                 Ty::new_projection_from_args(tcx, assoc_items[0], tcx.mk_args(&[self.into()]))
             }
@@ -1629,7 +1629,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Str | ty::Slice(_) => Ok(tcx.types.usize),
 
             ty::Dynamic(_, _, ty::Dyn) => {
-                let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
+                let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, DUMMY_SP);
                 Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]))
             }
 
@@ -1683,7 +1683,7 @@ impl<'tcx> Ty<'tcx> {
             match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) {
                 Ok(metadata_ty) => metadata_ty,
                 Err(tail_ty) => {
-                    let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
+                    let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, DUMMY_SP);
                     Ty::new_projection(tcx, metadata_def_id, [tail_ty])
                 }
             }
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index cc3887079d8..88583407d25 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -199,7 +199,7 @@ pub struct TypeckResults<'tcx> {
 
     /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
     /// by applying extended parameter rules.
-    /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`.
+    /// Details may be found in `rustc_hir_analysis::check::rvalue_scopes`.
     pub rvalue_scopes: RvalueScopes,
 
     /// Stores the predicates that apply on coroutine witness types.
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
index 5a97b08db28..b23bc089cd4 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs
@@ -145,7 +145,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // malloc some memory of suitable size and align:
                 let exchange_malloc = Operand::function_handle(
                     tcx,
-                    tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)),
+                    tcx.require_lang_item(LangItem::ExchangeMalloc, expr_span),
                     [],
                     expr_span,
                 );
diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs
index a9a07997410..2074fbce0ae 100644
--- a/compiler/rustc_mir_build/src/builder/expr/into.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/into.rs
@@ -307,7 +307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) {
                     // Convert `expr.use` to a call like `Clone::clone(&expr)`
                     let success = this.cfg.start_new_block();
-                    let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None);
+                    let clone_trait = this.tcx.require_lang_item(LangItem::Clone, span);
                     let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0];
                     let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span);
                     let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty);
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index 210b9cce581..a4609a6053e 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -364,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let borrow_kind = super::util::ref_pat_borrow_kind(mutability);
         let source_info = self.source_info(span);
         let re_erased = self.tcx.lifetimes.re_erased;
-        let trait_item = self.tcx.require_lang_item(trait_item, None);
+        let trait_item = self.tcx.require_lang_item(trait_item, span);
         let method = trait_method(self.tcx, trait_item, method, [ty]);
         let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span);
         // `let ref_src = &src_place;`
@@ -437,7 +437,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         val: Operand<'tcx>,
     ) {
         let str_ty = self.tcx.types.str_;
-        let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
+        let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, source_info.span);
         let method = trait_method(self.tcx, eq_def_id, sym::eq, [str_ty, str_ty]);
 
         let bool_ty = self.tcx.types.bool;
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 226dc920a49..3baeccf6409 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -38,7 +38,10 @@ impl<'tcx> ThirBuildCx<'tcx> {
     }
 
     pub(crate) fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> {
-        exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()
+        // `mirror_exprs` may also recurse deeply, so it needs protection from stack overflow.
+        // Note that we *could* forward to `mirror_expr` for that, but we can consolidate the
+        // overhead of stack growth by doing it outside the iteration.
+        ensure_sufficient_stack(|| exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect())
     }
 
     #[instrument(level = "trace", skip(self, hir_expr))]
@@ -220,7 +223,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 });
 
                 // kind = Pin { __pointer: pointer }
-                let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span));
+                let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span);
                 let args = self.tcx.mk_args(&[new_pin_target.into()]);
                 let kind = ExprKind::Adt(Box::new(AdtExpr {
                     adt_def: self.tcx.adt_def(pin_did),
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 8c817605847..24d4136c642 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -189,7 +189,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
             // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
             // (as it's created inside the body itself, not passed in from outside).
             let ty = if fn_decl.c_variadic && index == fn_decl.inputs.len() {
-                let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span));
+                let va_list_did = self.tcx.require_lang_item(LangItem::VaList, param.span);
 
                 self.tcx
                     .type_of(va_list_did)
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 84a0190a7fa..003ad170861 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
@@ -15,7 +15,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::{mir, span_bug};
 use rustc_span::def_id::DefId;
-use rustc_span::{Span, sym};
+use rustc_span::{DUMMY_SP, Span, sym};
 use rustc_trait_selection::traits::ObligationCause;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use tracing::{debug, instrument, trace};
@@ -480,8 +480,9 @@ fn type_has_partial_eq_impl<'tcx>(
     // (If there isn't, then we can safely issue a hard
     // error, because that's never worked, due to compiler
     // using `PartialEq::eq` in this scenario in the past.)
-    let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, None);
-    let structural_partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::StructuralPeq, None);
+    let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, DUMMY_SP);
+    let structural_partial_eq_trait_id =
+        tcx.require_lang_item(hir::LangItem::StructuralPeq, DUMMY_SP);
 
     let partial_eq_obligation = Obligation::new(
         tcx,
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index cddb2f84778..d5d0d56f528 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -225,7 +225,7 @@ impl<'tcx> TransformVisitor<'tcx> {
             CoroutineKind::Coroutine(_) => span_bug!(body.span, "`Coroutine`s cannot be fused"),
             // `gen` continues return `None`
             CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {
-                let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
+                let option_def_id = self.tcx.require_lang_item(LangItem::Option, body.span);
                 make_aggregate_adt(
                     option_def_id,
                     VariantIdx::ZERO,
@@ -242,7 +242,7 @@ impl<'tcx> TransformVisitor<'tcx> {
                     span: source_info.span,
                     const_: Const::Unevaluated(
                         UnevaluatedConst::new(
-                            self.tcx.require_lang_item(LangItem::AsyncGenFinished, None),
+                            self.tcx.require_lang_item(LangItem::AsyncGenFinished, body.span),
                             self.tcx.mk_args(&[yield_ty.into()]),
                         ),
                         self.old_yield_ty,
@@ -282,7 +282,7 @@ impl<'tcx> TransformVisitor<'tcx> {
         const ONE: VariantIdx = VariantIdx::from_usize(1);
         let rvalue = match self.coroutine_kind {
             CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
-                let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, None);
+                let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, source_info.span);
                 let args = self.tcx.mk_args(&[self.old_ret_ty.into()]);
                 let (variant_idx, operands) = if is_return {
                     (ZERO, IndexVec::from_raw(vec![val])) // Poll::Ready(val)
@@ -292,7 +292,7 @@ impl<'tcx> TransformVisitor<'tcx> {
                 make_aggregate_adt(poll_def_id, variant_idx, args, operands)
             }
             CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {
-                let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
+                let option_def_id = self.tcx.require_lang_item(LangItem::Option, source_info.span);
                 let args = self.tcx.mk_args(&[self.old_yield_ty.into()]);
                 let (variant_idx, operands) = if is_return {
                     (ZERO, IndexVec::new()) // None
@@ -310,7 +310,10 @@ impl<'tcx> TransformVisitor<'tcx> {
                         span: source_info.span,
                         const_: Const::Unevaluated(
                             UnevaluatedConst::new(
-                                self.tcx.require_lang_item(LangItem::AsyncGenFinished, None),
+                                self.tcx.require_lang_item(
+                                    LangItem::AsyncGenFinished,
+                                    source_info.span,
+                                ),
                                 self.tcx.mk_args(&[yield_ty.into()]),
                             ),
                             self.old_yield_ty,
@@ -323,7 +326,7 @@ impl<'tcx> TransformVisitor<'tcx> {
             }
             CoroutineKind::Coroutine(_) => {
                 let coroutine_state_def_id =
-                    self.tcx.require_lang_item(LangItem::CoroutineState, None);
+                    self.tcx.require_lang_item(LangItem::CoroutineState, source_info.span);
                 let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]);
                 let variant_idx = if is_return {
                     ONE // CoroutineState::Complete(val)
@@ -496,7 +499,7 @@ fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Bo
 fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let ref_coroutine_ty = body.local_decls.raw[1].ty;
 
-    let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span));
+    let pin_did = tcx.require_lang_item(LangItem::Pin, body.span);
     let pin_adt_ref = tcx.adt_def(pin_did);
     let args = tcx.mk_args(&[ref_coroutine_ty.into()]);
     let pin_ref_coroutine_ty = Ty::new_adt(tcx, pin_adt_ref, args);
@@ -557,7 +560,7 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ty
     // replace the type of the `resume` argument
     replace_resume_ty_local(tcx, body, CTX_ARG, context_mut_ref);
 
-    let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
+    let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, body.span);
 
     for bb in body.basic_blocks.indices() {
         let bb_data = &body[bb];
@@ -618,7 +621,7 @@ fn replace_resume_ty_local<'tcx>(
     #[cfg(debug_assertions)]
     {
         if let ty::Adt(resume_ty_adt, _) = local_ty.kind() {
-            let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
+            let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, body.span));
             assert_eq!(*resume_ty_adt, expected_adt);
         } else {
             panic!("expected `ResumeTy`, found `{:?}`", local_ty);
@@ -1095,7 +1098,7 @@ fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) ->
 
 fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> {
     // Poll::Ready(())
-    let poll_def_id = tcx.require_lang_item(LangItem::Poll, None);
+    let poll_def_id = tcx.require_lang_item(LangItem::Poll, source_info.span);
     let args = tcx.mk_args(&[tcx.types.unit.into()]);
     let val = Operand::Constant(Box::new(ConstOperand {
         span: source_info.span,
@@ -1437,7 +1440,7 @@ fn check_field_tys_sized<'tcx>(
             ),
             param_env,
             field_ty.ty,
-            tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)),
+            tcx.require_lang_item(hir::LangItem::Sized, field_ty.source_info.span),
         );
     }
 
@@ -1473,14 +1476,14 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
         let new_ret_ty = match coroutine_kind {
             CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
                 // Compute Poll<return_ty>
-                let poll_did = tcx.require_lang_item(LangItem::Poll, None);
+                let poll_did = tcx.require_lang_item(LangItem::Poll, body.span);
                 let poll_adt_ref = tcx.adt_def(poll_did);
                 let poll_args = tcx.mk_args(&[old_ret_ty.into()]);
                 Ty::new_adt(tcx, poll_adt_ref, poll_args)
             }
             CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {
                 // Compute Option<yield_ty>
-                let option_did = tcx.require_lang_item(LangItem::Option, None);
+                let option_did = tcx.require_lang_item(LangItem::Option, body.span);
                 let option_adt_ref = tcx.adt_def(option_did);
                 let option_args = tcx.mk_args(&[old_yield_ty.into()]);
                 Ty::new_adt(tcx, option_adt_ref, option_args)
@@ -1491,7 +1494,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
             }
             CoroutineKind::Coroutine(_) => {
                 // Compute CoroutineState<yield_ty, return_ty>
-                let state_did = tcx.require_lang_item(LangItem::CoroutineState, None);
+                let state_did = tcx.require_lang_item(LangItem::CoroutineState, body.span);
                 let state_adt_ref = tcx.adt_def(state_did);
                 let state_args = tcx.mk_args(&[old_yield_ty.into(), old_ret_ty.into()]);
                 Ty::new_adt(tcx, state_adt_ref, state_args)
diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs
index 625e53f9959..6021e795d21 100644
--- a/compiler/rustc_mir_transform/src/coroutine/drop.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs
@@ -42,7 +42,7 @@ fn build_poll_call<'tcx>(
     context_ref_place: &Place<'tcx>,
     unwind: UnwindAction,
 ) -> BasicBlock {
-    let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, None);
+    let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, DUMMY_SP);
     let poll_fn = Ty::new_fn_def(tcx, poll_fn, [fut_ty]);
     let poll_fn = Operand::Constant(Box::new(ConstOperand {
         span: DUMMY_SP,
@@ -77,11 +77,8 @@ fn build_pin_fut<'tcx>(
     let fut_ty = fut_place.ty(&body.local_decls, tcx).ty;
     let fut_ref_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fut_ty);
     let fut_ref_place = Place::from(body.local_decls.push(LocalDecl::new(fut_ref_ty, span)));
-    let pin_fut_new_unchecked_fn = Ty::new_fn_def(
-        tcx,
-        tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)),
-        [fut_ref_ty],
-    );
+    let pin_fut_new_unchecked_fn =
+        Ty::new_fn_def(tcx, tcx.require_lang_item(LangItem::PinNewUnchecked, span), [fut_ref_ty]);
     let fut_pin_ty = pin_fut_new_unchecked_fn.fn_sig(tcx).output().skip_binder();
     let fut_pin_place = Place::from(body.local_decls.push(LocalDecl::new(fut_pin_ty, span)));
     let pin_fut_new_unchecked_fn = Operand::Constant(Box::new(ConstOperand {
@@ -143,13 +140,15 @@ fn build_poll_switch<'tcx>(
     let Discr { val: poll_ready_discr, ty: poll_discr_ty } = poll_enum
         .discriminant_for_variant(
             tcx,
-            poll_enum_adt.variant_index_with_id(tcx.require_lang_item(LangItem::PollReady, None)),
+            poll_enum_adt
+                .variant_index_with_id(tcx.require_lang_item(LangItem::PollReady, DUMMY_SP)),
         )
         .unwrap();
     let poll_pending_discr = poll_enum
         .discriminant_for_variant(
             tcx,
-            poll_enum_adt.variant_index_with_id(tcx.require_lang_item(LangItem::PollPending, None)),
+            poll_enum_adt
+                .variant_index_with_id(tcx.require_lang_item(LangItem::PollPending, DUMMY_SP)),
         )
         .unwrap()
         .val;
@@ -316,16 +315,17 @@ pub(super) fn expand_async_drops<'tcx>(
         //  pending => return rv (yield)
         //  ready => *continue_bb|drop_bb*
 
+        let source_info = body[bb].terminator.as_ref().unwrap().source_info;
+
         // Compute Poll<> (aka Poll with void return)
-        let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None));
+        let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, source_info.span));
         let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()]));
-        let poll_decl = LocalDecl::new(poll_enum, body.span);
+        let poll_decl = LocalDecl::new(poll_enum, source_info.span);
         let poll_unit_place = Place::from(body.local_decls.push(poll_decl));
 
         // First state-loop yield for mainline
         let context_ref_place =
-            Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, body.span)));
-        let source_info = body[bb].terminator.as_ref().unwrap().source_info;
+            Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)));
         let arg = Rvalue::Use(Operand::Move(Place::from(CTX_ARG)));
         body[bb].statements.push(Statement {
             source_info,
@@ -353,8 +353,9 @@ pub(super) fn expand_async_drops<'tcx>(
         let mut dropline_context_ref: Option<Place<'_>> = None;
         let mut dropline_call_bb: Option<BasicBlock> = None;
         if !is_dropline_bb {
-            let context_ref_place2: Place<'_> =
-                Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, body.span)));
+            let context_ref_place2: Place<'_> = Place::from(
+                body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)),
+            );
             let drop_yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield
             let drop_switch_block = build_poll_switch(
                 tcx,
@@ -394,7 +395,7 @@ pub(super) fn expand_async_drops<'tcx>(
                     span: source_info.span,
                     const_: Const::Unevaluated(
                         UnevaluatedConst::new(
-                            tcx.require_lang_item(LangItem::AsyncGenPending, None),
+                            tcx.require_lang_item(LangItem::AsyncGenPending, source_info.span),
                             tcx.mk_args(&[yield_ty.into()]),
                         ),
                         full_yield_ty,
@@ -404,7 +405,7 @@ pub(super) fn expand_async_drops<'tcx>(
             } else {
                 // value needed only for return-yields or gen-coroutines, so just const here
                 Operand::Constant(Box::new(ConstOperand {
-                    span: body.span,
+                    span: source_info.span,
                     user_ty: None,
                     const_: Const::from_bool(tcx, false),
                 }))
@@ -595,7 +596,7 @@ pub(super) fn create_coroutine_drop_shim<'tcx>(
 
     // Update the body's def to become the drop glue.
     let coroutine_instance = body.source.instance;
-    let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None);
+    let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, body.span);
     let drop_instance = InstanceKind::DropGlue(drop_in_place, Some(coroutine_ty));
 
     // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible
@@ -666,7 +667,7 @@ pub(super) fn create_coroutine_drop_shim_async<'tcx>(
     }
 
     // Replace the return variable: Poll<RetT> to Poll<()>
-    let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None));
+    let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span));
     let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()]));
     body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info);
 
@@ -717,7 +718,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>(
     let source_info = SourceInfo::outermost(body.span);
 
     // Replace the return variable: Poll<RetT> to Poll<()>
-    let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None));
+    let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span));
     let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()]));
     body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info);
 
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 99b95e7312b..0cf8142a560 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -616,7 +616,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             place,
             operand,
             &mut |elem, op| match elem {
-                TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(),
+                TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(),
                 TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(),
                 TrackElem::Discriminant => {
                     let variant = self.ecx.read_discriminant(op).discard_err()?;
@@ -890,7 +890,8 @@ fn try_write_constant<'tcx>(
 
         ty::Tuple(elem_tys) => {
             for (i, elem) in elem_tys.iter().enumerate() {
-                let Some(field) = map.apply(place, TrackElem::Field(FieldIdx::from_usize(i))) else {
+                let i = FieldIdx::from_usize(i);
+                let Some(field) = map.apply(place, TrackElem::Field(i)) else {
                     throw_machine_stop_str!("missing field in tuple")
                 };
                 let field_dest = ecx.project_field(dest, i)?;
@@ -928,7 +929,7 @@ fn try_write_constant<'tcx>(
                 let Some(field) = map.apply(variant_place, TrackElem::Field(i)) else {
                     throw_machine_stop_str!("missing field in ADT")
                 };
-                let field_dest = ecx.project_field(&variant_dest, i.as_usize())?;
+                let field_dest = ecx.project_field(&variant_dest, i)?;
                 try_write_constant(ecx, &field_dest, field, ty, state, map)?;
             }
             ecx.write_discriminant(variant_idx, dest)?;
diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs
index c15d7d6f732..3a5e2620b14 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drop.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs
@@ -235,11 +235,8 @@ where
 
         let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only {
             // Resolving obj.<AsyncDrop::drop>()
-            let trait_ref = ty::TraitRef::new(
-                tcx,
-                tcx.require_lang_item(LangItem::AsyncDrop, Some(span)),
-                [drop_ty],
-            );
+            let trait_ref =
+                ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::AsyncDrop, span), [drop_ty]);
             let (drop_trait, trait_args) = match tcx.codegen_select_candidate(
                 ty::TypingEnv::fully_monomorphized().as_query_input(trait_ref),
             ) {
@@ -292,7 +289,7 @@ where
             (sig.output(), drop_fn_def_id, trait_args)
         } else {
             // Resolving async_drop_in_place<T> function for drop_ty
-            let drop_fn_def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, Some(span));
+            let drop_fn_def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, span);
             let trait_args = tcx.mk_args(&[drop_ty.into()]);
             let sig = tcx.fn_sig(drop_fn_def_id).instantiate(tcx, trait_args);
             let sig = tcx.instantiate_bound_regions_with_erased(sig);
@@ -319,7 +316,7 @@ where
         // pin_obj_place preparation
         let pin_obj_new_unchecked_fn = Ty::new_fn_def(
             tcx,
-            tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)),
+            tcx.require_lang_item(LangItem::PinNewUnchecked, span),
             [GenericArg::from(obj_ref_ty)],
         );
         let pin_obj_ty = pin_obj_new_unchecked_fn.fn_sig(tcx).output().no_bound_vars().unwrap();
@@ -937,7 +934,7 @@ where
     fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock {
         debug!("destructor_call_block_sync({:?}, {:?})", self, succ);
         let tcx = self.tcx();
-        let drop_trait = tcx.require_lang_item(LangItem::Drop, None);
+        let drop_trait = tcx.require_lang_item(LangItem::Drop, DUMMY_SP);
         let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
         let ty = self.place_ty(self.place);
 
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index a91d46ec406..92c30d239b5 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -438,8 +438,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                         dest.clone()
                     };
                     for (field_index, op) in fields.into_iter().enumerate() {
-                        let field_dest =
-                            self.ecx.project_field(&variant_dest, field_index).discard_err()?;
+                        let field_dest = self
+                            .ecx
+                            .project_field(&variant_dest, FieldIdx::from_usize(field_index))
+                            .discard_err()?;
                         self.ecx.copy_op(op, &field_dest).discard_err()?;
                     }
                     self.ecx
@@ -1583,7 +1585,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             // We needed to check the variant to avoid trying to read the tag
             // field from an enum where no fields have variants, since that tag
             // field isn't in the `Aggregate` from which we're getting values.
-            Some((FieldIdx::from_usize(field_idx), field_layout.ty))
+            Some((field_idx, field_layout.ty))
         } else if let ty::Adt(adt, args) = ty.kind()
             && adt.is_struct()
             && adt.repr().transparent()
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 31b361ec1a9..48db536c122 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -388,7 +388,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
             lhs,
             constant,
             &mut |elem, op| match elem {
-                TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(),
+                TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(),
                 TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(),
                 TrackElem::Discriminant => {
                     let variant = self.ecx.read_discriminant(op).discard_err()?;
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 9688ac8ed2e..6d45bbc6e16 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -98,7 +98,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
             build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
         }
         ty::InstanceKind::ClosureOnceShim { call_once: _, track_caller: _ } => {
-            let fn_mut = tcx.require_lang_item(LangItem::FnMut, None);
+            let fn_mut = tcx.require_lang_item(LangItem::FnMut, DUMMY_SP);
             let call_mut = tcx
                 .associated_items(fn_mut)
                 .in_definition_order()
diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
index fbc8ee9b06c..fd7b7362cd9 100644
--- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
+++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
@@ -64,7 +64,7 @@ pub(super) fn build_async_drop_shim<'tcx>(
     let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env);
     let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env);
 
-    let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
+    let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
     let resume_ty = Ty::new_adt(tcx, resume_adt, ty::List::empty());
 
     let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
@@ -220,7 +220,7 @@ fn build_adrop_for_coroutine_shim<'tcx>(
     body.source.instance = instance;
     body.phase = MirPhase::Runtime(RuntimePhase::Initial);
     body.var_debug_info.clear();
-    let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, Some(span)));
+    let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
     let args = tcx.mk_args(&[proxy_ref.into()]);
     let pin_proxy_ref = Ty::new_adt(tcx, pin_adt_ref, args);
 
@@ -308,10 +308,10 @@ fn build_adrop_for_adrop_shim<'tcx>(
     let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty);
 
     // ret_ty = `Poll<()>`
-    let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None));
+    let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, span));
     let ret_ty = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()]));
     // env_ty = `Pin<&mut proxy_ty>`
-    let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None));
+    let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span));
     let env_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[proxy_ref.into()]));
     // sig = `fn (Pin<&mut proxy_ty>, &mut Context) -> Poll<()>`
     let sig = tcx.mk_fn_sig(
@@ -376,7 +376,7 @@ fn build_adrop_for_adrop_shim<'tcx>(
     let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()]));
     let cor_pin_place = Place::from(locals.push(LocalDecl::new(cor_pin_ty, span)));
 
-    let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span));
+    let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span);
     // call Pin<FutTy>::new_unchecked(&mut impl_cor)
     blocks.push(BasicBlockData {
         statements,
@@ -396,7 +396,7 @@ fn build_adrop_for_adrop_shim<'tcx>(
     });
     // When dropping async drop coroutine, we continue its execution:
     // we call impl::poll (impl_layout, ctx)
-    let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, None);
+    let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span);
     let resume_ctx = Place::from(Local::new(2));
     blocks.push(BasicBlockData {
         statements: vec![],
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index c8aa7588d03..fd91508cc11 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1253,7 +1253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             self.tcx,
                             self.tcx.require_lang_item(
                                 LangItem::CoerceUnsized,
-                                Some(self.body.source_info(location).span),
+                                self.body.source_info(location).span,
                             ),
                             [op_ty, *target_type],
                         )) {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 1ee977a5457..173030e0326 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -781,7 +781,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
 
         let tcx = self.tcx;
         let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| {
-            let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
+            let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, source));
             if tcx.should_codegen_locally(instance) {
                 this.used_items.push(create_fn_mono_item(tcx, instance, source));
             }
@@ -921,7 +921,7 @@ fn visit_instance_use<'tcx>(
             // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any
             // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to
             // codegen a call to that function without generating code for the function itself.
-            let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None);
+            let def_id = tcx.require_lang_item(LangItem::PanicNounwind, source);
             let panic_instance = Instance::mono(tcx, def_id);
             if tcx.should_codegen_locally(panic_instance) {
                 output.push(create_fn_mono_item(tcx, panic_instance, source));
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 5c66017bc61..05683940cba 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -29,7 +29,7 @@ fn custom_coerce_unsize_info<'tcx>(
 ) -> Result<CustomCoerceUnsized, ErrorGuaranteed> {
     let trait_ref = ty::TraitRef::new(
         tcx.tcx,
-        tcx.require_lang_item(LangItem::CoerceUnsized, Some(tcx.span)),
+        tcx.require_lang_item(LangItem::CoerceUnsized, tcx.span),
         [source_ty, target_ty],
     );
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 6277dde7c97..b49a13ce584 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2273,9 +2273,9 @@ impl<'a> Parser<'a> {
                     ),
                     // Also catches `fn foo(&a)`.
                     PatKind::Ref(ref inner_pat, mutab)
-                        if matches!(inner_pat.clone().into_inner().kind, PatKind::Ident(..)) =>
+                        if matches!(inner_pat.clone().kind, PatKind::Ident(..)) =>
                     {
-                        match inner_pat.clone().into_inner().kind {
+                        match inner_pat.clone().kind {
                             PatKind::Ident(_, ident, _) => {
                                 let mutab = mutab.prefix_str();
                                 (
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index adfea3641e6..a298c4d4dec 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1119,7 +1119,7 @@ impl<'a> Parser<'a> {
     /// Parse the field access used in offset_of, matched by `$(e:expr)+`.
     /// Currently returns a list of idents. However, it should be possible in
     /// future to also do array indices, which might be arbitrary expressions.
-    fn parse_floating_field_access(&mut self) -> PResult<'a, P<[Ident]>> {
+    fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> {
         let mut fields = Vec::new();
         let mut trailing_dot = None;
 
@@ -3468,10 +3468,8 @@ impl<'a> Parser<'a> {
                 // Detect and recover from `($pat if $cond) => $arm`.
                 // FIXME(guard_patterns): convert this to a normal guard instead
                 let span = pat.span;
-                let ast::PatKind::Paren(subpat) = pat.into_inner().kind else { unreachable!() };
-                let ast::PatKind::Guard(_, mut cond) = subpat.into_inner().kind else {
-                    unreachable!()
-                };
+                let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() };
+                let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() };
                 self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
                 CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
                 let right = self.prev_token.span;
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c7b0eb11e5a..a325c2a57ab 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -145,7 +145,7 @@ impl<'a> Parser<'a> {
         {
             let mut item = item.expect("an actual item");
             attrs.prepend_to_nt_inner(&mut item.attrs);
-            return Ok(Some(item.into_inner()));
+            return Ok(Some(*item));
         }
 
         self.collect_tokens(None, attrs, force_collect, |this, mut attrs| {
@@ -637,7 +637,7 @@ impl<'a> Parser<'a> {
                     self.dcx().emit_err(errors::MissingForInTraitImpl { span: missing_for_span });
                 }
 
-                let ty_first = ty_first.into_inner();
+                let ty_first = *ty_first;
                 let path = match ty_first.kind {
                     // This notably includes paths passed through `ty` macro fragments (#46438).
                     TyKind::Path(None, path) => path,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index d6ff80b2eb4..7a226136e23 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1086,7 +1086,7 @@ impl<'a> Parser<'a> {
         if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(_), Mutability::Mut), ..)) {
             self.psess.gated_spans.gate(sym::mut_ref, pat.span);
         }
-        Ok(pat.into_inner().kind)
+        Ok(pat.kind)
     }
 
     /// Turn all by-value immutable bindings in a pattern into mutable bindings.
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 17481731b11..9ddfc179e9b 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -7,6 +7,7 @@ use rustc_ast::{
     Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
     TyKind, UnsafeBinderTy,
 };
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Applicability, Diag, PResult};
 use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
 use thin_vec::{ThinVec, thin_vec};
@@ -104,14 +105,17 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
 impl<'a> Parser<'a> {
     /// Parses a type.
     pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
-        self.parse_ty_common(
-            AllowPlus::Yes,
-            AllowCVariadic::No,
-            RecoverQPath::Yes,
-            RecoverReturnSign::Yes,
-            None,
-            RecoverQuestionMark::Yes,
-        )
+        // Make sure deeply nested types don't overflow the stack.
+        ensure_sufficient_stack(|| {
+            self.parse_ty_common(
+                AllowPlus::Yes,
+                AllowCVariadic::No,
+                RecoverQPath::Yes,
+                RecoverReturnSign::Yes,
+                None,
+                RecoverQuestionMark::Yes,
+            )
+        })
     }
 
     pub(super) fn parse_ty_with_generics_recovery(
@@ -404,7 +408,7 @@ impl<'a> Parser<'a> {
         })?;
 
         if ts.len() == 1 && matches!(trailing, Trailing::No) {
-            let ty = ts.into_iter().next().unwrap().into_inner();
+            let ty = ts.into_iter().next().unwrap();
             let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
             match ty.kind {
                 // `(TY_BOUND_NOPAREN) + BOUND + ...`.
@@ -420,7 +424,7 @@ impl<'a> Parser<'a> {
                     self.parse_remaining_bounds(bounds, true)
                 }
                 // `(TYPE)`
-                _ => Ok(TyKind::Paren(P(ty))),
+                _ => Ok(TyKind::Paren(ty)),
             }
         } else {
             Ok(TyKind::Tup(ts))
@@ -1295,7 +1299,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, ()> {
         let fn_path_segment = fn_path.segments.last_mut().unwrap();
         let generic_args = if let Some(p_args) = &fn_path_segment.args {
-            p_args.clone().into_inner()
+            *p_args.clone()
         } else {
             // Normally it wouldn't come here because the upstream should have parsed
             // generic parameters (otherwise it's impossible to call this function).
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 6d815e510ea..983e562cdf3 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -509,23 +509,11 @@ passes_must_not_suspend =
 passes_must_use_no_effect =
     `#[must_use]` has no effect when applied to {$article} {$target}
 
-passes_naked_asm_outside_naked_fn =
-    the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
-
-passes_naked_functions_asm_block =
-    naked functions must contain a single `naked_asm!` invocation
-    .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions
-    .label_non_asm = not allowed in naked functions
-
 passes_naked_functions_incompatible_attribute =
     attribute incompatible with `#[unsafe(naked)]`
     .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
     .naked_attribute = function marked with `#[unsafe(naked)]` here
 
-passes_naked_functions_must_naked_asm =
-    the `asm!` macro is not allowed in naked functions
-    .label = consider using the `naked_asm!` macro instead
-
 passes_no_link =
     attribute should be applied to an `extern crate` item
     .label = not an `extern crate` item
@@ -556,9 +544,6 @@ passes_no_mangle_foreign =
     .note = symbol names in extern blocks are not mangled
     .suggestion = remove this attribute
 
-passes_no_patterns =
-    patterns not allowed in naked function parameters
-
 passes_no_sanitize =
     `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
     .label = not {$accepted_kind}
@@ -606,10 +591,6 @@ passes_panic_unwind_without_std =
     .note = since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
     .help = using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
 
-passes_params_not_allowed =
-    referencing function parameters is not allowed in naked functions
-    .help = follow the calling convention in asm block to use parameters
-
 passes_parent_info =
     {$num ->
       [one] {$descr}
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 00682a9c7a7..b995781719b 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1197,51 +1197,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_no_patterns)]
-pub(crate) struct NoPatterns {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_params_not_allowed)]
-#[help]
-pub(crate) struct ParamsNotAllowed {
-    #[primary_span]
-    pub span: Span,
-}
-
-pub(crate) struct NakedFunctionsAsmBlock {
-    pub span: Span,
-    pub multiple_asms: Vec<Span>,
-    pub non_asms: Vec<Span>,
-}
-
-impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock {
-    #[track_caller]
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        let mut diag = Diag::new(dcx, level, fluent::passes_naked_functions_asm_block);
-        diag.span(self.span);
-        diag.code(E0787);
-        for span in self.multiple_asms.iter() {
-            diag.span_label(*span, fluent::passes_label_multiple_asm);
-        }
-        for span in self.non_asms.iter() {
-            diag.span_label(*span, fluent::passes_label_non_asm);
-        }
-        diag
-    }
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_naked_functions_must_naked_asm, code = E0787)]
-pub(crate) struct NakedFunctionsMustNakedAsm {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_naked_functions_incompatible_attribute, code = E0736)]
 pub(crate) struct NakedFunctionIncompatibleAttribute {
     #[primary_span]
@@ -1253,13 +1208,6 @@ pub(crate) struct NakedFunctionIncompatibleAttribute {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_naked_asm_outside_naked_fn)]
-pub(crate) struct NakedAsmOutsideNakedFn {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_attr_only_in_functions)]
 pub(crate) struct AttrOnlyInFunctions {
     #[primary_span]
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 275714c2d0e..3afed9784de 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -307,18 +307,14 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> {
         self.parent_item = parent_item;
     }
 
-    fn visit_enum_def(&mut self, enum_definition: &'ast ast::EnumDef) {
-        for variant in &enum_definition.variants {
-            self.check_for_lang(
-                Target::Variant,
-                self.resolver.node_id_to_def_id[&variant.id],
-                &variant.attrs,
-                variant.span,
-                None,
-            );
-        }
-
-        visit::walk_enum_def(self, enum_definition);
+    fn visit_variant(&mut self, variant: &'ast ast::Variant) {
+        self.check_for_lang(
+            Target::Variant,
+            self.resolver.node_id_to_def_id[&variant.id],
+            &variant.attrs,
+            variant.span,
+            None,
+        );
     }
 
     fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) {
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index f9445485f60..639ca683cf6 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -14,7 +14,7 @@
 #![feature(try_blocks)]
 // tidy-alphabetical-end
 
-use rustc_middle::query::Providers;
+use rustc_middle::util::Providers;
 
 pub mod abi_test;
 mod check_attr;
@@ -32,7 +32,6 @@ pub mod layout_test;
 mod lib_features;
 mod liveness;
 pub mod loops;
-mod naked_functions;
 mod reachable;
 pub mod stability;
 mod upvars;
@@ -49,7 +48,6 @@ pub fn provide(providers: &mut Providers) {
     lang_items::provide(providers);
     lib_features::provide(providers);
     loops::provide(providers);
-    naked_functions::provide(providers);
     liveness::provide(providers);
     reachable::provide(providers);
     stability::provide(providers);
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 9b824572b66..2e870c47f8e 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -100,6 +100,21 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
         }
     }
 
+    fn check_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) {
+        if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) {
+            self.check_import_as_underscore(use_tree, id);
+            return;
+        }
+
+        if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind {
+            if items.is_empty() {
+                self.unused_import(self.base_id).add(id);
+            }
+        } else {
+            self.check_import(id);
+        }
+    }
+
     fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport {
         let use_tree_id = self.base_id;
         let use_tree = self.base_use_tree.unwrap().clone();
@@ -225,13 +240,21 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
 
 impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
     fn visit_item(&mut self, item: &'a ast::Item) {
-        match item.kind {
+        self.item_span = item.span_with_attributes();
+        match &item.kind {
             // Ignore is_public import statements because there's no way to be sure
             // whether they're used or not. Also ignore imports with a dummy span
             // because this means that they were generated in some fashion by the
             // compiler and we don't need to consider them.
             ast::ItemKind::Use(..) if item.span.is_dummy() => return,
-            ast::ItemKind::ExternCrate(orig_name, ident) => {
+            // Use the base UseTree's NodeId as the item id
+            // This allows the grouping of all the lints in the same item
+            ast::ItemKind::Use(use_tree) => {
+                self.base_id = item.id;
+                self.base_use_tree = Some(use_tree);
+                self.check_use_tree(use_tree, item.id);
+            }
+            &ast::ItemKind::ExternCrate(orig_name, ident) => {
                 self.extern_crate_items.push(ExternCrateToLint {
                     id: item.id,
                     span: item.span,
@@ -245,32 +268,12 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
             _ => {}
         }
 
-        self.item_span = item.span_with_attributes();
         visit::walk_item(self, item);
     }
 
-    fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId, nested: bool) {
-        // Use the base UseTree's NodeId as the item id
-        // This allows the grouping of all the lints in the same item
-        if !nested {
-            self.base_id = id;
-            self.base_use_tree = Some(use_tree);
-        }
-
-        if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) {
-            self.check_import_as_underscore(use_tree, id);
-            return;
-        }
-
-        if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind {
-            if items.is_empty() {
-                self.unused_import(self.base_id).add(id);
-            }
-        } else {
-            self.check_import(id);
-        }
-
-        visit::walk_use_tree(self, use_tree, id);
+    fn visit_nested_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) {
+        self.check_use_tree(use_tree, id);
+        visit::walk_use_tree(self, use_tree);
     }
 }
 
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 25485be5622..dc16fe212b1 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -147,7 +147,10 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                 DefKind::Macro(macro_kind)
             }
             ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
-            ItemKind::Use(..) => return visit::walk_item(self, i),
+            ItemKind::Use(use_tree) => {
+                self.create_def(i.id, None, DefKind::Use, use_tree.span);
+                return visit::walk_item(self, i);
+            }
             ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
                 return self.visit_macro_invoc(i.id);
             }
@@ -232,9 +235,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
         }
     }
 
-    fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
+    fn visit_nested_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId) {
         self.create_def(id, None, DefKind::Use, use_tree.span);
-        visit::walk_use_tree(self, use_tree, id);
+        visit::walk_use_tree(self, use_tree);
     }
 
     fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index d2917478e4e..c69991f3fb2 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{
     TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy,
 };
 use rustc_span::def_id::DefId;
-use rustc_span::sym;
+use rustc_span::{DUMMY_SP, sym};
 use rustc_trait_selection::traits;
 use tracing::{debug, instrument};
 
@@ -414,7 +414,7 @@ pub(crate) fn transform_instance<'tcx>(
                 }
                 ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() {
                     hir::CoroutineKind::Coroutine(..) => (
-                        tcx.require_lang_item(LangItem::Coroutine, None),
+                        tcx.require_lang_item(LangItem::Coroutine, DUMMY_SP),
                         Some(instance.args.as_coroutine().resume_ty()),
                     ),
                     hir::CoroutineKind::Desugared(desugaring, _) => {
@@ -423,11 +423,11 @@ pub(crate) fn transform_instance<'tcx>(
                             hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator,
                             hir::CoroutineDesugaring::Gen => LangItem::Iterator,
                         };
-                        (tcx.require_lang_item(lang_item, None), None)
+                        (tcx.require_lang_item(lang_item, DUMMY_SP), None)
                     }
                 },
                 ty::CoroutineClosure(..) => (
-                    tcx.require_lang_item(LangItem::FnOnce, None),
+                    tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP),
                     Some(
                         tcx.instantiate_bound_regions_with_erased(
                             instance.args.as_coroutine_closure().coroutine_closure_sig(),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 8e2137da655..2c16672d786 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -73,7 +73,7 @@ use rustc_middle::ty::{
     TypeVisitableExt,
 };
 use rustc_span::def_id::LOCAL_CRATE;
-use rustc_span::{BytePos, DesugaringKind, Pos, Span, sym};
+use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym};
 use tracing::{debug, instrument};
 
 use crate::error_reporting::TypeErrCtxt;
@@ -194,7 +194,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             _ => return None,
         };
 
-        let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+        let future_trait = self.tcx.require_lang_item(LangItem::Future, DUMMY_SP);
         let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
 
         self.tcx
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
index d8b405e904c..8a67e4ccd45 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
@@ -6,7 +6,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, lang_items};
 use rustc_middle::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv};
-use rustc_span::{DesugaringKind, Ident, Span, sym};
+use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, sym};
 use tracing::debug;
 
 use crate::traits::specialization_graph;
@@ -31,9 +31,9 @@ impl CallDesugaringKind {
     pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId {
         match self {
             Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
-            Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, None),
+            Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, DUMMY_SP),
             Self::QuestionBranch | Self::TryBlockFromOutput => {
-                tcx.require_lang_item(LangItem::Try, None)
+                tcx.require_lang_item(LangItem::Try, DUMMY_SP)
             }
             Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
             Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 9c301373cf9..3b7fd8b7a20 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -955,7 +955,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 return false;
             };
 
-            let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
+            let clone_trait = self.tcx.require_lang_item(LangItem::Clone, obligation.cause.span);
             let has_clone = |ty| {
                 self.type_implements_trait(clone_trait, [ty], obligation.param_env)
                     .must_apply_modulo_regions()
@@ -3625,7 +3625,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         trait_pred: ty::PolyTraitPredicate<'tcx>,
         span: Span,
     ) {
-        let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+        let future_trait = self.tcx.require_lang_item(LangItem::Future, span);
 
         let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
         let impls_future = self.type_implements_trait(
@@ -4141,7 +4141,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         let pred = ty::Binder::dummy(ty::TraitPredicate {
                             trait_ref: ty::TraitRef::new(
                                 tcx,
-                                tcx.require_lang_item(LangItem::Clone, Some(span)),
+                                tcx.require_lang_item(LangItem::Clone, span),
                                 [*ty],
                             ),
                             polarity: ty::PredicatePolarity::Positive,
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 0dab3adadb0..0118321befb 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -38,7 +38,7 @@ impl<'tcx> InferCtxt<'tcx> {
             return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty);
         }
 
-        let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
+        let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP);
 
         // This can get called from typeck (by euv), and `moves_by_default`
         // rightly refuses to work with inference variables, but
@@ -49,7 +49,7 @@ impl<'tcx> InferCtxt<'tcx> {
 
     fn type_is_clone_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
         let ty = self.resolve_vars_if_possible(ty);
-        let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, None);
+        let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, DUMMY_SP);
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id)
     }
 
@@ -59,12 +59,12 @@ impl<'tcx> InferCtxt<'tcx> {
         ty: Ty<'tcx>,
     ) -> bool {
         let ty = self.resolve_vars_if_possible(ty);
-        let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None);
+        let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, DUMMY_SP);
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id)
     }
 
     fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
-        let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+        let lang_item = self.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index e92e37b8738..69a0c0809b5 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -64,6 +64,16 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         span: Span,
     ) -> Option<Certainty> {
         if let Some(trait_pred) = goal.predicate.as_trait_clause() {
+            if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var()
+                // We don't do this fast path when opaques are defined since we may
+                // eventually use opaques to incompletely guide inference via ty var
+                // self types.
+                // FIXME: Properly consider opaques here.
+                && self.inner.borrow_mut().opaque_types().is_empty()
+            {
+                return Some(Certainty::AMBIGUOUS);
+            }
+
             if trait_pred.polarity() == ty::PredicatePolarity::Positive {
                 match self.0.tcx.as_lang_item(trait_pred.def_id()) {
                     Some(LangItem::Sized)
@@ -115,6 +125,17 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
 
                 Some(Certainty::Yes)
             }
+            ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. })
+            | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+                if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() {
+                    // FIXME: We also need to register a subtype relation between these vars
+                    // when those are added, and if they aren't in the same sub root then
+                    // we should mark this goal as `has_changed`.
+                    Some(Certainty::AMBIGUOUS)
+                } else {
+                    None
+                }
+            }
             _ => None,
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
index cc5861b5a1f..e77d9e32cb9 100644
--- a/compiler/rustc_trait_selection/src/traits/effects.rs
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -248,7 +248,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
     obligation: &HostEffectObligation<'tcx>,
 ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
     let tcx = selcx.tcx();
-    let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, None);
+    let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, obligation.cause.span);
     let self_ty = obligation.predicate.self_ty();
 
     let const_conditions = match *self_ty.kind() {
@@ -267,7 +267,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>(
                 Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution),
                 // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold.
                 Some(hir::Constness::Const) => {
-                    let drop_def_id = tcx.require_lang_item(LangItem::Drop, None);
+                    let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span);
                     let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]);
                     const_conditions.push(drop_trait_ref);
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index a4b6f330b9d..393f458bea2 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -157,7 +157,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
             parent_cause.clone(),
             param_env,
             inner_ty,
-            tcx.require_lang_item(lang_item, Some(parent_cause.span)),
+            tcx.require_lang_item(lang_item, parent_cause.span),
         );
 
         let errors = ocx.select_all_or_error();
@@ -193,7 +193,7 @@ pub fn all_fields_implement_trait<'tcx>(
     parent_cause: ObligationCause<'tcx>,
     lang_item: LangItem,
 ) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> {
-    let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span));
+    let trait_def_id = tcx.require_lang_item(lang_item, parent_cause.span);
 
     let mut infringing = Vec::new();
     for variant in adt.variants() {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index ed0f34b5aa9..6dd80551980 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1117,7 +1117,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                                                 selcx.tcx(),
                                                 selcx.tcx().require_lang_item(
                                                     LangItem::Sized,
-                                                    Some(obligation.cause.span),
+                                                    obligation.cause.span,
                                                 ),
                                                 [self_ty],
                                             ),
@@ -1317,7 +1317,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
 
     let tcx = selcx.tcx();
 
-    let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None);
+    let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, obligation.cause.span);
 
     let (trait_ref, yield_ty, return_ty) = super::util::coroutine_trait_ref_and_outputs(
         tcx,
@@ -1375,7 +1375,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
     debug!(?obligation, ?coroutine_sig, ?obligations, "confirm_future_candidate");
 
     let tcx = selcx.tcx();
-    let fut_def_id = tcx.require_lang_item(LangItem::Future, None);
+    let fut_def_id = tcx.require_lang_item(LangItem::Future, obligation.cause.span);
 
     let (trait_ref, return_ty) = super::util::future_trait_ref_and_outputs(
         tcx,
@@ -1421,7 +1421,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
     debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate");
 
     let tcx = selcx.tcx();
-    let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None);
+    let iter_def_id = tcx.require_lang_item(LangItem::Iterator, obligation.cause.span);
 
     let (trait_ref, yield_ty) = super::util::iterator_trait_ref_and_outputs(
         tcx,
@@ -1467,7 +1467,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
     debug!(?obligation, ?gen_sig, ?obligations, "confirm_async_iterator_candidate");
 
     let tcx = selcx.tcx();
-    let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, None);
+    let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, obligation.cause.span);
 
     let (trait_ref, yield_ty) = super::util::async_iterator_trait_ref_and_outputs(
         tcx,
@@ -1511,12 +1511,13 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
     let trait_def_id = tcx.trait_of_item(item_def_id).unwrap();
     let args = tcx.mk_args(&[self_ty.into()]);
     let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) {
-        let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
+        let discriminant_def_id =
+            tcx.require_lang_item(LangItem::Discriminant, obligation.cause.span);
         assert_eq!(discriminant_def_id, item_def_id);
 
         (self_ty.discriminant_ty(tcx).into(), PredicateObligations::new())
     } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) {
-        let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
+        let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, obligation.cause.span);
         assert_eq!(metadata_def_id, item_def_id);
 
         let mut obligations = PredicateObligations::new();
@@ -1538,7 +1539,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
                 // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
                 let sized_predicate = ty::TraitRef::new(
                     tcx,
-                    tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)),
+                    tcx.require_lang_item(LangItem::Sized, obligation.cause.span),
                     [self_ty],
                 );
                 obligations.push(obligation.with(tcx, sized_predicate));
@@ -1620,7 +1621,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
                     )
                 } else {
                     let upvars_projection_def_id =
-                        tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None);
+                        tcx.require_lang_item(LangItem::AsyncFnKindUpvars, obligation.cause.span);
                     let tupled_upvars_ty = Ty::new_projection(
                         tcx,
                         upvars_projection_def_id,
@@ -1681,8 +1682,9 @@ fn confirm_callable_candidate<'cx, 'tcx>(
 
     debug!(?obligation, ?fn_sig, "confirm_callable_candidate");
 
-    let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None);
-    let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None);
+    let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, obligation.cause.span);
+    let fn_once_output_def_id =
+        tcx.require_lang_item(LangItem::FnOnceOutput, obligation.cause.span);
 
     let predicate = super::util::closure_trait_ref_and_return_type(
         tcx,
@@ -1740,8 +1742,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
                             args.coroutine_captures_by_ref_ty(),
                         )
                     } else {
-                        let upvars_projection_def_id =
-                            tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None);
+                        let upvars_projection_def_id = tcx
+                            .require_lang_item(LangItem::AsyncFnKindUpvars, obligation.cause.span);
                         // When we don't know the closure kind (and therefore also the closure's upvars,
                         // which are computed at the same time), we must delay the computation of the
                         // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
@@ -1798,7 +1800,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
             let term = match item_name {
                 sym::CallOnceFuture | sym::CallRefFuture => sig.output(),
                 sym::Output => {
-                    let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None);
+                    let future_output_def_id =
+                        tcx.require_lang_item(LangItem::FutureOutput, obligation.cause.span);
                     Ty::new_projection(tcx, future_output_def_id, [sig.output()])
                 }
                 name => bug!("no such associated type: {name}"),
@@ -1831,7 +1834,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
             let term = match item_name {
                 sym::CallOnceFuture | sym::CallRefFuture => sig.output(),
                 sym::Output => {
-                    let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None);
+                    let future_output_def_id =
+                        tcx.require_lang_item(LangItem::FutureOutput, obligation.cause.span);
                     Ty::new_projection(tcx, future_output_def_id, [sig.output()])
                 }
                 name => bug!("no such associated type: {name}"),
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index c9169127e0b..7acf0f990d1 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -318,7 +318,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             let make_freeze_obl = |ty| {
                 let trait_ref = ty::TraitRef::new(
                     tcx,
-                    tcx.require_lang_item(LangItem::Freeze, None),
+                    tcx.require_lang_item(LangItem::Freeze, obligation.cause.span),
                     [ty::GenericArg::from(ty)],
                 );
                 Obligation::with_depth(
@@ -657,7 +657,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         );
         let tr = ty::TraitRef::new(
             self.tcx(),
-            self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)),
+            self.tcx().require_lang_item(LangItem::Sized, cause.span),
             [output_ty],
         );
         nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr));
@@ -877,14 +877,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 });
 
                 // We must additionally check that the return type impls `Future + Sized`.
-                let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
+                let future_trait_def_id =
+                    tcx.require_lang_item(LangItem::Future, obligation.cause.span);
                 nested.push(obligation.with(
                     tcx,
                     sig.output().map_bound(|output_ty| {
                         ty::TraitRef::new(tcx, future_trait_def_id, [output_ty])
                     }),
                 ));
-                let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None);
+                let sized_trait_def_id =
+                    tcx.require_lang_item(LangItem::Sized, obligation.cause.span);
                 nested.push(obligation.with(
                     tcx,
                     sig.output().map_bound(|output_ty| {
@@ -906,13 +908,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 });
 
                 // We must additionally check that the return type impls `Future + Sized`.
-                let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
+                let future_trait_def_id =
+                    tcx.require_lang_item(LangItem::Future, obligation.cause.span);
                 let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output());
                 nested.push(obligation.with(
                     tcx,
                     ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]),
                 ));
-                let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None);
+                let sized_trait_def_id =
+                    tcx.require_lang_item(LangItem::Sized, obligation.cause.span);
                 nested.push(obligation.with(
                     tcx,
                     sig.output().map_bound(|output_ty| {
@@ -946,10 +950,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 obligation.param_env,
                 ty::TraitRef::new(
                     self.tcx(),
-                    self.tcx().require_lang_item(
-                        LangItem::AsyncFnKindHelper,
-                        Some(obligation.cause.span),
-                    ),
+                    self.tcx()
+                        .require_lang_item(LangItem::AsyncFnKindHelper, obligation.cause.span),
                     [kind_ty, Ty::from_closure_kind(self.tcx(), goal_kind)],
                 ),
             ));
@@ -1165,7 +1167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // We can only make objects from sized types.
                 let tr = ty::TraitRef::new(
                     tcx,
-                    tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)),
+                    tcx.require_lang_item(LangItem::Sized, obligation.cause.span),
                     [source],
                 );
                 nested.push(predicate_to_obligation(tr.upcast(tcx)));
@@ -1359,7 +1361,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     self_ty.map_bound(|ty| {
                         ty::TraitRef::new(
                             tcx,
-                            tcx.require_lang_item(LangItem::Copy, Some(obligation.cause.span)),
+                            tcx.require_lang_item(LangItem::Copy, obligation.cause.span),
                             [ty],
                         )
                     }),
@@ -1411,7 +1413,7 @@ fn pointer_like_goal_for_rpitit<'tcx>(
     ty::Binder::bind_with_vars(
         ty::TraitRef::new(
             tcx,
-            tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)),
+            tcx.require_lang_item(LangItem::PointerLike, cause.span),
             [Ty::new_projection_from_args(tcx, rpitit_item, args)],
         ),
         tcx.mk_bound_variable_kinds(&bound_vars),
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 3018dad8e09..416865e861e 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -541,7 +541,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
             let cause = self.cause(cause);
             let trait_ref = ty::TraitRef::new(
                 self.tcx(),
-                self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)),
+                self.tcx().require_lang_item(LangItem::Sized, cause.span),
                 [subty],
             );
             self.out.push(traits::Obligation::with_depth(
@@ -895,7 +895,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                                 self.tcx(),
                                 self.tcx().require_lang_item(
                                     LangItem::BikeshedGuaranteedNoDrop,
-                                    Some(self.span),
+                                    self.span,
                                 ),
                                 [ty],
                             )
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 83d7416b03e..bb5187e4f5c 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -11,6 +11,7 @@ use rustc_middle::ty::layout::{
 };
 use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt};
 use rustc_session::config::OptLevel;
+use rustc_span::DUMMY_SP;
 use rustc_span::def_id::DefId;
 use rustc_target::callconv::{
     AbiMap, ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, FnAbi, PassMode,
@@ -124,7 +125,7 @@ fn fn_sig_for_fn_abi<'tcx>(
 
             let env_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
 
-            let pin_did = tcx.require_lang_item(LangItem::Pin, None);
+            let pin_did = tcx.require_lang_item(LangItem::Pin, DUMMY_SP);
             let pin_adt_ref = tcx.adt_def(pin_did);
             let pin_args = tcx.mk_args(&[env_ty.into()]);
             let env_ty = match coroutine_kind {
@@ -149,7 +150,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                     // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll<Output>`
                     assert_eq!(sig.yield_ty, tcx.types.unit);
 
-                    let poll_did = tcx.require_lang_item(LangItem::Poll, None);
+                    let poll_did = tcx.require_lang_item(LangItem::Poll, DUMMY_SP);
                     let poll_adt_ref = tcx.adt_def(poll_did);
                     let poll_args = tcx.mk_args(&[sig.return_ty.into()]);
                     let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_args);
@@ -160,7 +161,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                     {
                         if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
                             let expected_adt =
-                                tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
+                                tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
                             assert_eq!(*resume_ty_adt, expected_adt);
                         } else {
                             panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
@@ -172,7 +173,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 }
                 hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => {
                     // The signature should be `Iterator::next(_) -> Option<Yield>`
-                    let option_did = tcx.require_lang_item(LangItem::Option, None);
+                    let option_did = tcx.require_lang_item(LangItem::Option, DUMMY_SP);
                     let option_adt_ref = tcx.adt_def(option_did);
                     let option_args = tcx.mk_args(&[sig.yield_ty.into()]);
                     let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args);
@@ -196,7 +197,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                     {
                         if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() {
                             let expected_adt =
-                                tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None));
+                                tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP));
                             assert_eq!(*resume_ty_adt, expected_adt);
                         } else {
                             panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty);
@@ -208,7 +209,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 }
                 hir::CoroutineKind::Coroutine(_) => {
                     // The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>`
-                    let state_did = tcx.require_lang_item(LangItem::CoroutineState, None);
+                    let state_did = tcx.require_lang_item(LangItem::CoroutineState, DUMMY_SP);
                     let state_adt_ref = tcx.adt_def(state_did);
                     let state_args = tcx.mk_args(&[sig.yield_ty.into(), sig.return_ty.into()]);
                     let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_args);
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index bb2c4172b08..7219f40710e 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -4,6 +4,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits;
 
 fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
@@ -42,7 +43,7 @@ fn is_item_raw<'tcx>(
     item: LangItem,
 ) -> bool {
     let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(query.typing_env);
-    let trait_def_id = tcx.require_lang_item(item, None);
+    let trait_def_id = tcx.require_lang_item(item, DUMMY_SP);
     traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, query.value, trait_def_id)
 }
 
diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs
index 0b4efab1d9c..e900264a76c 100644
--- a/compiler/rustc_ty_utils/src/structural_match.rs
+++ b/compiler/rustc_ty_utils/src/structural_match.rs
@@ -16,8 +16,7 @@ fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
 
     let ocx = ObligationCtxt::new(infcx);
     // require `#[derive(PartialEq)]`
-    let structural_peq_def_id =
-        infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
+    let structural_peq_def_id = infcx.tcx.require_lang_item(LangItem::StructuralPeq, cause.span);
     ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id);
 
     // We deliberately skip *reporting* fulfillment errors (via
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 330aaa25d13..e39fd6b947b 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -104,7 +104,7 @@ fn adt_sized_constraint<'tcx>(
 
     // perf hack: if there is a `constraint_ty: Sized` bound, then we know
     // that the type is sized and do not need to check it on the impl.
-    let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None);
+    let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
     let predicates = tcx.predicates_of(def.did()).predicates;
     if predicates.iter().any(|(p, _)| {
         p.as_trait_clause().is_some_and(|trait_pred| {
diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs
index b49b3f41a76..b4da56578c8 100644
--- a/library/alloc/src/slice.rs
+++ b/library/alloc/src/slice.rs
@@ -493,8 +493,6 @@ impl<T> [T] {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
     /// ```
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index f1b1734b8b2..22cdd8ecde0 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -246,8 +246,6 @@ impl str {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = "this is old";
     ///
@@ -303,8 +301,6 @@ impl str {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// let s = "foo foo 123 foo";
     /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2));
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index ba30518d70b..dd9c379b666 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -678,8 +678,8 @@ impl fmt::Display for i128 {
 /// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas
 /// 10^20 > 2^64 > 10^19.
 fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    // 2^128 is about 3*10^38, so 39 gives an extra byte of space
-    let mut buf = [MaybeUninit::<u8>::uninit(); 39];
+    const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1;
+    let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
     let mut curr = buf.len();
 
     let (n, rem) = udiv_1e19(n);
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index a279f002772..511807b409f 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -551,8 +551,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// # use std::num::NonZero;
             /// #
@@ -583,8 +581,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// # use std::num::NonZero;
             /// #
@@ -612,8 +608,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Example
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(isolate_most_least_significant_one)]
             ///
@@ -644,8 +638,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Example
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(isolate_most_least_significant_one)]
             ///
@@ -676,8 +668,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// # use std::num::NonZero;
             /// #
@@ -713,8 +703,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(nonzero_bitwise)]
             /// # use std::num::NonZero;
@@ -746,8 +734,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(nonzero_bitwise)]
             /// # use std::num::NonZero;
@@ -775,8 +761,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(nonzero_bitwise)]
             /// # use std::num::NonZero;
@@ -805,8 +789,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(nonzero_bitwise)]
             /// # use std::num::NonZero;
@@ -837,8 +819,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(nonzero_bitwise)]
             /// # use std::num::NonZero;
@@ -872,8 +852,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(nonzero_bitwise)]
             /// # use std::num::NonZero;
@@ -907,8 +885,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(nonzero_bitwise)]
             /// # use std::num::NonZero;
@@ -942,8 +918,6 @@ macro_rules! nonzero_integer {
             ///
             /// # Examples
             ///
-            /// Basic usage:
-            ///
             /// ```
             /// #![feature(nonzero_bitwise)]
             /// # use std::num::NonZero;
@@ -1635,8 +1609,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
         ///
         /// # Examples
         ///
-        /// Basic usage:
-        ///
         /// ```
         /// # use std::num::NonZero;
         /// #
@@ -1666,7 +1638,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
         ///
         /// # Examples
         ///
-        /// Basic usage:
         /// ```
         /// # use std::num::NonZero;
         /// #
@@ -1699,8 +1670,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
         ///
         /// # Examples
         ///
-        /// Basic usage:
-        ///
         /// ```
         /// # use std::num::NonZero;
         ///
@@ -2138,8 +2107,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
         ///
         /// # Examples
         ///
-        /// Basic usage:
-        ///
         /// ```
         /// # use std::num::NonZero;
         ///
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index 024cb71b915..f44e12d48ad 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -178,6 +178,8 @@ pub use core::ffi::{
     c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
     c_ulong, c_ulonglong, c_ushort,
 };
+#[unstable(feature = "c_size_t", issue = "88345")]
+pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t};
 
 #[doc(inline)]
 #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 711efc7d011..6cbf8301e01 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1311,9 +1311,39 @@ impl Write for &File {
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Seek for &File {
+    /// Seek to an offset, in bytes in a file.
+    ///
+    /// See [`Seek::seek`] docs for more info.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `lseek64` function on Unix
+    /// and the `SetFilePointerEx` function on Windows. Note that this [may
+    /// change in the future][changes].
+    ///
+    /// [changes]: io#platform-specific-behavior
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         self.inner.seek(pos)
     }
+
+    /// Returns the length of this file (in bytes).
+    ///
+    /// See [`Seek::stream_len`] docs for more info.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `statx` function on Linux
+    /// (with fallbacks) and the `GetFileSizeEx` function on Windows. Note that
+    /// this [may change in the future][changes].
+    ///
+    /// [changes]: io#platform-specific-behavior
+    fn stream_len(&mut self) -> io::Result<u64> {
+        if let Some(result) = self.inner.size() {
+            return result;
+        }
+        io::stream_len_default(self)
+    }
+
     fn stream_position(&mut self) -> io::Result<u64> {
         self.inner.tell()
     }
@@ -1363,6 +1393,9 @@ impl Seek for File {
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         (&*self).seek(pos)
     }
+    fn stream_len(&mut self) -> io::Result<u64> {
+        (&*self).stream_len()
+    }
     fn stream_position(&mut self) -> io::Result<u64> {
         (&*self).stream_position()
     }
@@ -1412,6 +1445,9 @@ impl Seek for Arc<File> {
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
         (&**self).seek(pos)
     }
+    fn stream_len(&mut self) -> io::Result<u64> {
+        (&**self).stream_len()
+    }
     fn stream_position(&mut self) -> io::Result<u64> {
         (&**self).stream_position()
     }
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 03f5f838311..20c82b64bcc 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -2028,7 +2028,7 @@ pub trait Seek {
 
     /// Returns the length of this stream (in bytes).
     ///
-    /// This method is implemented using up to three seek operations. If this
+    /// The default implementation uses up to three seek operations. If this
     /// method returns successfully, the seek position is unchanged (i.e. the
     /// position before calling this method is the same as afterwards).
     /// However, if this method returns an error, the seek position is
@@ -2062,16 +2062,7 @@ pub trait Seek {
     /// ```
     #[unstable(feature = "seek_stream_len", issue = "59359")]
     fn stream_len(&mut self) -> Result<u64> {
-        let old_pos = self.stream_position()?;
-        let len = self.seek(SeekFrom::End(0))?;
-
-        // Avoid seeking a third time when we were already at the end of the
-        // stream. The branch is usually way cheaper than a seek operation.
-        if old_pos != len {
-            self.seek(SeekFrom::Start(old_pos))?;
-        }
-
-        Ok(len)
+        stream_len_default(self)
     }
 
     /// Returns the current seek position from the start of the stream.
@@ -2132,6 +2123,19 @@ pub trait Seek {
     }
 }
 
+pub(crate) fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> {
+    let old_pos = self_.stream_position()?;
+    let len = self_.seek(SeekFrom::End(0))?;
+
+    // Avoid seeking a third time when we were already at the end of the
+    // stream. The branch is usually way cheaper than a seek operation.
+    if old_pos != len {
+        self_.seek(SeekFrom::Start(old_pos))?;
+    }
+
+    Ok(len)
+}
+
 /// Enumeration of possible methods to seek within an I/O object.
 ///
 /// It is used by the [`Seek`] trait.
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 79b25040ef6..1c55824ab90 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1916,10 +1916,6 @@ mod type_keyword {}
 /// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe
 /// {}` and `unsafe impl`, but also `unsafe fn` -- see below).
 ///
-/// They are not mutually exclusive, as can be seen in `unsafe fn`: the body of an `unsafe fn` is,
-/// by default, treated like an unsafe block. The `unsafe_op_in_unsafe_fn` lint can be enabled to
-/// change that.
-///
 /// # Unsafe abilities
 ///
 /// **No matter what, Safe Rust can't cause Undefined Behavior**. This is
@@ -1961,13 +1957,6 @@ mod type_keyword {}
 /// - `unsafe impl`: the contract necessary to implement the trait has been
 /// checked by the programmer and is guaranteed to be respected.
 ///
-/// By default, `unsafe fn` also acts like an `unsafe {}` block
-/// around the code inside the function. This means it is not just a signal to
-/// the caller, but also promises that the preconditions for the operations
-/// inside the function are upheld. Mixing these two meanings can be confusing, so the
-/// `unsafe_op_in_unsafe_fn` lint can be enabled to warn against that and require explicit unsafe
-/// blocks even inside `unsafe fn`.
-///
 /// See the [Rustonomicon] and the [Reference] for more information.
 ///
 /// # Examples
@@ -2109,6 +2098,7 @@ mod type_keyword {}
 /// impl Indexable for i32 {
 ///     const LEN: usize = 1;
 ///
+///     /// See `Indexable` for the safety contract.
 ///     unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
 ///         debug_assert_eq!(idx, 0);
 ///         *self
@@ -2120,6 +2110,7 @@ mod type_keyword {}
 /// impl Indexable for [i32; 42] {
 ///     const LEN: usize = 42;
 ///
+///     /// See `Indexable` for the safety contract.
 ///     unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
 ///         // SAFETY: As per this trait's documentation, the caller ensures
 ///         // that `idx < 42`.
@@ -2132,6 +2123,7 @@ mod type_keyword {}
 /// impl Indexable for ! {
 ///     const LEN: usize = 0;
 ///
+///     /// See `Indexable` for the safety contract.
 ///     unsafe fn idx_unchecked(&self, idx: usize) -> i32 {
 ///         // SAFETY: As per this trait's documentation, the caller ensures
 ///         // that `idx < 0`, which is impossible, so this is dead code.
@@ -2153,11 +2145,14 @@ mod type_keyword {}
 /// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing
 /// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation
 /// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation
-/// to contend with. Of course, the implementation of `Indexable` may choose to call other unsafe
-/// operations, and then it needs an `unsafe` *block* to indicate it discharged the proof
-/// obligations of its callees. (We enabled `unsafe_op_in_unsafe_fn`, so the body of `idx_unchecked`
-/// is not implicitly an unsafe block.) For that purpose it can make use of the contract that all
-/// its callers must uphold -- the fact that `idx < LEN`.
+/// to contend with. Of course, the implementation may choose to call other unsafe operations, and
+/// then it needs an `unsafe` *block* to indicate it discharged the proof obligations of its
+/// callees. For that purpose it can make use of the contract that all its callers must uphold --
+/// the fact that `idx < LEN`.
+///
+/// Note that unlike normal `unsafe fn`, an `unsafe fn` in a trait implementation does not get to
+/// just pick an arbitrary safety contract! It *has* to use the safety contract defined by the trait
+/// (or one with weaker preconditions).
 ///
 /// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond
 /// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare
diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs
index a9774bef9e3..175d919c289 100644
--- a/library/std/src/sys/fs/hermit.rs
+++ b/library/std/src/sys/fs/hermit.rs
@@ -422,6 +422,10 @@ impl File {
         self.0.seek(pos)
     }
 
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        None
+    }
+
     pub fn tell(&self) -> io::Result<u64> {
         self.0.tell()
     }
diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs
index 3bfb39bac95..808a9582911 100644
--- a/library/std/src/sys/fs/solid.rs
+++ b/library/std/src/sys/fs/solid.rs
@@ -459,6 +459,10 @@ impl File {
         self.tell()
     }
 
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        None
+    }
+
     pub fn tell(&self) -> io::Result<u64> {
         unsafe {
             let mut out_offset = MaybeUninit::uninit();
diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs
index 416c90b98b6..5763d7862f5 100644
--- a/library/std/src/sys/fs/uefi.rs
+++ b/library/std/src/sys/fs/uefi.rs
@@ -280,6 +280,10 @@ impl File {
         self.0
     }
 
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        self.0
+    }
+
     pub fn tell(&self) -> io::Result<u64> {
         self.0
     }
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index a3e520fdeef..dc278274f00 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -1464,6 +1464,15 @@ impl File {
         Ok(n as u64)
     }
 
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        match self.file_attr().map(|attr| attr.size()) {
+            // Fall back to default implementation if the returned size is 0,
+            // we might be in a proc mount.
+            Ok(0) => None,
+            result => Some(result),
+        }
+    }
+
     pub fn tell(&self) -> io::Result<u64> {
         self.seek(SeekFrom::Current(0))
     }
diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs
index 0ff9533c047..efaddb51b37 100644
--- a/library/std/src/sys/fs/unsupported.rs
+++ b/library/std/src/sys/fs/unsupported.rs
@@ -259,6 +259,10 @@ impl File {
         self.0
     }
 
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        self.0
+    }
+
     pub fn tell(&self) -> io::Result<u64> {
         self.0
     }
diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs
index ebfc7377a2e..b65d86de12a 100644
--- a/library/std/src/sys/fs/wasi.rs
+++ b/library/std/src/sys/fs/wasi.rs
@@ -516,6 +516,10 @@ impl File {
         self.fd.seek(pos)
     }
 
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        None
+    }
+
     pub fn tell(&self) -> io::Result<u64> {
         self.fd.tell()
     }
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index d01a572ac73..a95709b4891 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -616,6 +616,14 @@ impl File {
         Ok(newpos as u64)
     }
 
+    pub fn size(&self) -> Option<io::Result<u64>> {
+        let mut result = 0;
+        Some(
+            cvt(unsafe { c::GetFileSizeEx(self.handle.as_raw_handle(), &mut result) })
+                .map(|_| result as u64),
+        )
+    }
+
     pub fn tell(&self) -> io::Result<u64> {
         self.seek(SeekFrom::Current(0))
     }
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 48609030aed..850bdfdf5b5 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -282,7 +282,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
         return getcwd().map(|cwd| cwd.join(path))?.canonicalize();
     }
     // Search PATH to infer current_exe.
-    if let Some(p) = getenv(OsStr::from_bytes("PATH".as_bytes())) {
+    if let Some(p) = env::var_os(OsStr::from_bytes("PATH".as_bytes())) {
         for search_path in split_paths(&p) {
             let pb = search_path.join(&path);
             if pb.is_file()
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index d5fbb453c6f..a99c474c763 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2156,6 +2156,7 @@ GetExitCodeProcess
 GetFileAttributesW
 GetFileInformationByHandle
 GetFileInformationByHandleEx
+GetFileSizeEx
 GetFileType
 GETFINALPATHNAMEBYHANDLE_FLAGS
 GetFinalPathNameByHandleW
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index eb2914b8644..95bf8040229 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -44,6 +44,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess :
 windows_targets::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32);
 windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL);
+windows_targets::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, lpfilesize : *mut i64) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE);
 windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32);
 windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32);
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index d52b9dd1f3a..5ecce31fe15 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -668,7 +668,8 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
 
     // Enable frame pointers by default for the library. Note that they are still controlled by a
     // separate setting for the compiler.
-    cargo.rustflag("-Cforce-frame-pointers=yes");
+    cargo.rustflag("-Zunstable-options");
+    cargo.rustflag("-Cforce-frame-pointers=non-leaf");
 
     let html_root =
         format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),);
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 00e46875908..491f55ccaf3 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1,36 +1,56 @@
-//! Serialized configuration of a build.
+//! This module defines the central `Config` struct, which aggregates all components
+//! of the bootstrap configuration into a single unit.
 //!
-//! This module implements parsing `bootstrap.toml` configuration files to tweak
-//! how the build runs.
+//! It serves as the primary public interface for accessing the bootstrap configuration.
+//! The module coordinates the overall configuration parsing process using logic from `parsing.rs`
+//! and provides top-level methods such as `Config::parse()` for initialization, as well as
+//! utility methods for querying and manipulating the complete configuration state.
+//!
+//! Additionally, this module contains the core logic for parsing, validating, and inferring
+//! the final `Config` from various raw inputs.
+//!
+//! It manages the process of reading command-line arguments, environment variables,
+//! and the `bootstrap.toml` file—merging them, applying defaults, and performing
+//! cross-component validation. The main `parse_inner` function and its supporting
+//! helpers reside here, transforming raw `Toml` data into the structured `Config` type.
 
 use std::cell::Cell;
 use std::collections::{BTreeSet, HashMap, HashSet};
-use std::fmt::{self, Display};
-use std::hash::Hash;
 use std::io::IsTerminal;
 use std::path::{Path, PathBuf, absolute};
-use std::process::Command;
 use std::str::FromStr;
-use std::sync::{Arc, Mutex, OnceLock};
+use std::sync::{Arc, Mutex};
 use std::{cmp, env, fs};
 
 use build_helper::ci::CiEnv;
 use build_helper::exit;
 use build_helper::git::{GitConfig, PathFreshness, check_path_modifications, output_result};
-use serde::{Deserialize, Deserializer};
-use serde_derive::Deserialize;
+use serde::Deserialize;
+#[cfg(feature = "tracing")]
+use tracing::{instrument, span};
 #[cfg(feature = "tracing")]
 use tracing::{instrument, span};
 
-use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
 use crate::core::build_steps::llvm;
 use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS;
 pub use crate::core::config::flags::Subcommand;
-use crate::core::config::flags::{Color, Flags, Warnings};
+use crate::core::config::flags::{Color, Flags};
+use crate::core::config::target_selection::TargetSelectionList;
+use crate::core::config::toml::TomlConfig;
+use crate::core::config::toml::build::Build;
+use crate::core::config::toml::change_id::ChangeId;
+use crate::core::config::toml::rust::{
+    LldMode, RustOptimize, check_incompatible_options_for_ci_rustc,
+};
+use crate::core::config::toml::target::Target;
+use crate::core::config::{
+    DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo,
+    StringOrBool, set, threads_from_config,
+};
 use crate::core::download::is_download_ci_available;
-use crate::utils::cache::{INTERNER, Interned};
-use crate::utils::channel::{self, GitInfo};
-use crate::utils::helpers::{self, exe, output, t};
+use crate::utils::channel;
+use crate::utils::helpers::exe;
+use crate::{Command, GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, output, t};
 
 /// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic.
 /// This means they can be modified and changes to these paths should never trigger a compiler build
@@ -44,7 +64,7 @@ use crate::utils::helpers::{self, exe, output, t};
 /// For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the
 /// final output/compiler, which can be significantly affected by changes made to the bootstrap sources.
 #[rustfmt::skip] // We don't want rustfmt to oneline this list
-pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[
+pub const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[
     ":!library",
     ":!src/tools",
     ":!src/librustdoc",
@@ -53,138 +73,6 @@ pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[
     ":!triagebot.toml",
 ];
 
-macro_rules! check_ci_llvm {
-    ($name:expr) => {
-        assert!(
-            $name.is_none(),
-            "setting {} is incompatible with download-ci-llvm.",
-            stringify!($name).replace("_", "-")
-        );
-    };
-}
-
-/// This file is embedded in the overlay directory of the tarball sources. It is
-/// useful in scenarios where developers want to see how the tarball sources were
-/// generated.
-///
-/// We also use this file to compare the host's bootstrap.toml against the CI rustc builder
-/// configuration to detect any incompatible options.
-pub(crate) const BUILDER_CONFIG_FILENAME: &str = "builder-config";
-
-#[derive(Clone, Default)]
-pub enum DryRun {
-    /// This isn't a dry run.
-    #[default]
-    Disabled,
-    /// This is a dry run enabled by bootstrap itself, so it can verify that no work is done.
-    SelfCheck,
-    /// This is a dry run enabled by the `--dry-run` flag.
-    UserSelected,
-}
-
-#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
-pub enum DebuginfoLevel {
-    #[default]
-    None,
-    LineDirectivesOnly,
-    LineTablesOnly,
-    Limited,
-    Full,
-}
-
-// NOTE: can't derive(Deserialize) because the intermediate trip through toml::Value only
-// deserializes i64, and derive() only generates visit_u64
-impl<'de> Deserialize<'de> for DebuginfoLevel {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        use serde::de::Error;
-
-        Ok(match Deserialize::deserialize(deserializer)? {
-            StringOrInt::String(s) if s == "none" => DebuginfoLevel::None,
-            StringOrInt::Int(0) => DebuginfoLevel::None,
-            StringOrInt::String(s) if s == "line-directives-only" => {
-                DebuginfoLevel::LineDirectivesOnly
-            }
-            StringOrInt::String(s) if s == "line-tables-only" => DebuginfoLevel::LineTablesOnly,
-            StringOrInt::String(s) if s == "limited" => DebuginfoLevel::Limited,
-            StringOrInt::Int(1) => DebuginfoLevel::Limited,
-            StringOrInt::String(s) if s == "full" => DebuginfoLevel::Full,
-            StringOrInt::Int(2) => DebuginfoLevel::Full,
-            StringOrInt::Int(n) => {
-                let other = serde::de::Unexpected::Signed(n);
-                return Err(D::Error::invalid_value(other, &"expected 0, 1, or 2"));
-            }
-            StringOrInt::String(s) => {
-                let other = serde::de::Unexpected::Str(&s);
-                return Err(D::Error::invalid_value(
-                    other,
-                    &"expected none, line-tables-only, limited, or full",
-                ));
-            }
-        })
-    }
-}
-
-/// Suitable for passing to `-C debuginfo`
-impl Display for DebuginfoLevel {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use DebuginfoLevel::*;
-        f.write_str(match self {
-            None => "0",
-            LineDirectivesOnly => "line-directives-only",
-            LineTablesOnly => "line-tables-only",
-            Limited => "1",
-            Full => "2",
-        })
-    }
-}
-
-/// LLD in bootstrap works like this:
-/// - Self-contained lld: use `rust-lld` from the compiler's sysroot
-/// - External: use an external `lld` binary
-///
-/// It is configured depending on the target:
-/// 1) Everything except MSVC
-/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker`
-/// - External: `-Clinker-flavor=gnu-lld-cc`
-/// 2) MSVC
-/// - Self-contained: `-Clinker=<path to rust-lld>`
-/// - External: `-Clinker=lld`
-#[derive(Copy, Clone, Default, Debug, PartialEq)]
-pub enum LldMode {
-    /// Do not use LLD
-    #[default]
-    Unused,
-    /// Use `rust-lld` from the compiler's sysroot
-    SelfContained,
-    /// Use an externally provided `lld` binary.
-    /// Note that the linker name cannot be overridden, the binary has to be named `lld` and it has
-    /// to be in $PATH.
-    External,
-}
-
-impl LldMode {
-    pub fn is_used(&self) -> bool {
-        match self {
-            LldMode::SelfContained | LldMode::External => true,
-            LldMode::Unused => false,
-        }
-    }
-}
-
-/// Determines how will GCC be provided.
-#[derive(Default, Clone)]
-pub enum GccCiMode {
-    /// Build GCC from the local `src/gcc` submodule.
-    #[default]
-    BuildLocally,
-    /// Try to download GCC from CI.
-    /// If it is not available on CI, it will be built locally instead.
-    DownloadFromCi,
-}
-
 /// Global configuration for the entire build and/or bootstrap.
 ///
 /// This structure is parsed from `bootstrap.toml`, and some of the fields are inferred from `git` or build-time parameters.
@@ -250,9 +138,6 @@ pub struct Config {
     pub free_args: Vec<String>,
 
     /// `None` if we shouldn't download CI compiler artifacts, or the commit to download if we should.
-    #[cfg(not(test))]
-    download_rustc_commit: Option<String>,
-    #[cfg(test)]
     pub download_rustc_commit: Option<String>,
 
     pub deny_warnings: bool,
@@ -269,10 +154,6 @@ pub struct Config {
     pub llvm_release_debuginfo: bool,
     pub llvm_static_stdcpp: bool,
     pub llvm_libzstd: bool,
-    /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
-    #[cfg(not(test))]
-    llvm_link_shared: Cell<Option<bool>>,
-    #[cfg(test)]
     pub llvm_link_shared: Cell<Option<bool>>,
     pub llvm_clang_cl: Option<String>,
     pub llvm_targets: Option<String>,
@@ -345,9 +226,6 @@ pub struct Config {
     pub hosts: Vec<TargetSelection>,
     pub targets: Vec<TargetSelection>,
     pub local_rebuild: bool,
-    #[cfg(not(test))]
-    jemalloc: bool,
-    #[cfg(test)]
     pub jemalloc: bool,
     pub control_flow_guard: bool,
     pub ehcont_guard: bool,
@@ -430,932 +308,6 @@ pub struct Config {
     pub skip_std_check_if_no_download_rustc: bool,
 }
 
-#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
-pub enum LlvmLibunwind {
-    #[default]
-    No,
-    InTree,
-    System,
-}
-
-impl FromStr for LlvmLibunwind {
-    type Err = String;
-
-    fn from_str(value: &str) -> Result<Self, Self::Err> {
-        match value {
-            "no" => Ok(Self::No),
-            "in-tree" => Ok(Self::InTree),
-            "system" => Ok(Self::System),
-            invalid => Err(format!("Invalid value '{invalid}' for rust.llvm-libunwind config.")),
-        }
-    }
-}
-
-#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum SplitDebuginfo {
-    Packed,
-    Unpacked,
-    #[default]
-    Off,
-}
-
-impl std::str::FromStr for SplitDebuginfo {
-    type Err = ();
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "packed" => Ok(SplitDebuginfo::Packed),
-            "unpacked" => Ok(SplitDebuginfo::Unpacked),
-            "off" => Ok(SplitDebuginfo::Off),
-            _ => Err(()),
-        }
-    }
-}
-
-impl SplitDebuginfo {
-    /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for
-    /// `rust.split-debuginfo` in `bootstrap.example.toml`.
-    fn default_for_platform(target: TargetSelection) -> Self {
-        if target.contains("apple") {
-            SplitDebuginfo::Unpacked
-        } else if target.is_windows() {
-            SplitDebuginfo::Packed
-        } else {
-            SplitDebuginfo::Off
-        }
-    }
-}
-
-/// LTO mode used for compiling rustc itself.
-#[derive(Default, Clone, PartialEq, Debug)]
-pub enum RustcLto {
-    Off,
-    #[default]
-    ThinLocal,
-    Thin,
-    Fat,
-}
-
-impl std::str::FromStr for RustcLto {
-    type Err = String;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "thin-local" => Ok(RustcLto::ThinLocal),
-            "thin" => Ok(RustcLto::Thin),
-            "fat" => Ok(RustcLto::Fat),
-            "off" => Ok(RustcLto::Off),
-            _ => Err(format!("Invalid value for rustc LTO: {s}")),
-        }
-    }
-}
-
-#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
-// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy.
-// Making !Copy is highly nontrivial!
-pub struct TargetSelection {
-    pub triple: Interned<String>,
-    file: Option<Interned<String>>,
-    synthetic: bool,
-}
-
-/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
-#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-pub struct TargetSelectionList(Vec<TargetSelection>);
-
-pub fn target_selection_list(s: &str) -> Result<TargetSelectionList, String> {
-    Ok(TargetSelectionList(
-        s.split(',').filter(|s| !s.is_empty()).map(TargetSelection::from_user).collect(),
-    ))
-}
-
-impl TargetSelection {
-    pub fn from_user(selection: &str) -> Self {
-        let path = Path::new(selection);
-
-        let (triple, file) = if path.exists() {
-            let triple = path
-                .file_stem()
-                .expect("Target specification file has no file stem")
-                .to_str()
-                .expect("Target specification file stem is not UTF-8");
-
-            (triple, Some(selection))
-        } else {
-            (selection, None)
-        };
-
-        let triple = INTERNER.intern_str(triple);
-        let file = file.map(|f| INTERNER.intern_str(f));
-
-        Self { triple, file, synthetic: false }
-    }
-
-    pub fn create_synthetic(triple: &str, file: &str) -> Self {
-        Self {
-            triple: INTERNER.intern_str(triple),
-            file: Some(INTERNER.intern_str(file)),
-            synthetic: true,
-        }
-    }
-
-    pub fn rustc_target_arg(&self) -> &str {
-        self.file.as_ref().unwrap_or(&self.triple)
-    }
-
-    pub fn contains(&self, needle: &str) -> bool {
-        self.triple.contains(needle)
-    }
-
-    pub fn starts_with(&self, needle: &str) -> bool {
-        self.triple.starts_with(needle)
-    }
-
-    pub fn ends_with(&self, needle: &str) -> bool {
-        self.triple.ends_with(needle)
-    }
-
-    // See src/bootstrap/synthetic_targets.rs
-    pub fn is_synthetic(&self) -> bool {
-        self.synthetic
-    }
-
-    pub fn is_msvc(&self) -> bool {
-        self.contains("msvc")
-    }
-
-    pub fn is_windows(&self) -> bool {
-        self.contains("windows")
-    }
-
-    pub fn is_windows_gnu(&self) -> bool {
-        self.ends_with("windows-gnu")
-    }
-
-    pub fn is_cygwin(&self) -> bool {
-        self.is_windows() &&
-        // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html
-        env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin"))
-    }
-
-    pub fn needs_crt_begin_end(&self) -> bool {
-        self.contains("musl") && !self.contains("unikraft")
-    }
-
-    /// Path to the file defining the custom target, if any.
-    pub fn filepath(&self) -> Option<&Path> {
-        self.file.as_ref().map(Path::new)
-    }
-}
-
-impl fmt::Display for TargetSelection {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.triple)?;
-        if let Some(file) = self.file {
-            write!(f, "({file})")?;
-        }
-        Ok(())
-    }
-}
-
-impl fmt::Debug for TargetSelection {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{self}")
-    }
-}
-
-impl PartialEq<&str> for TargetSelection {
-    fn eq(&self, other: &&str) -> bool {
-        self.triple == *other
-    }
-}
-
-// Targets are often used as directory names throughout bootstrap.
-// This impl makes it more ergonomics to use them as such.
-impl AsRef<Path> for TargetSelection {
-    fn as_ref(&self) -> &Path {
-        self.triple.as_ref()
-    }
-}
-
-/// Per-target configuration stored in the global configuration structure.
-#[derive(Debug, Default, Clone, PartialEq, Eq)]
-pub struct Target {
-    /// Some(path to llvm-config) if using an external LLVM.
-    pub llvm_config: Option<PathBuf>,
-    pub llvm_has_rust_patches: Option<bool>,
-    /// Some(path to FileCheck) if one was specified.
-    pub llvm_filecheck: Option<PathBuf>,
-    pub llvm_libunwind: Option<LlvmLibunwind>,
-    pub cc: Option<PathBuf>,
-    pub cxx: Option<PathBuf>,
-    pub ar: Option<PathBuf>,
-    pub ranlib: Option<PathBuf>,
-    pub default_linker: Option<PathBuf>,
-    pub linker: Option<PathBuf>,
-    pub split_debuginfo: Option<SplitDebuginfo>,
-    pub sanitizers: Option<bool>,
-    pub profiler: Option<StringOrBool>,
-    pub rpath: Option<bool>,
-    pub crt_static: Option<bool>,
-    pub musl_root: Option<PathBuf>,
-    pub musl_libdir: Option<PathBuf>,
-    pub wasi_root: Option<PathBuf>,
-    pub qemu_rootfs: Option<PathBuf>,
-    pub runner: Option<String>,
-    pub no_std: bool,
-    pub codegen_backends: Option<Vec<String>>,
-    pub optimized_compiler_builtins: Option<bool>,
-    pub jemalloc: Option<bool>,
-}
-
-impl Target {
-    pub fn from_triple(triple: &str) -> Self {
-        let mut target: Self = Default::default();
-        if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") {
-            target.no_std = true;
-        }
-        if triple.contains("emscripten") {
-            target.runner = Some("node".into());
-        }
-        target
-    }
-}
-/// Structure of the `bootstrap.toml` file that configuration is read from.
-///
-/// This structure uses `Decodable` to automatically decode a TOML configuration
-/// file into this format, and then this is traversed and written into the above
-/// `Config` structure.
-#[derive(Deserialize, Default)]
-#[serde(deny_unknown_fields, rename_all = "kebab-case")]
-pub(crate) struct TomlConfig {
-    #[serde(flatten)]
-    change_id: ChangeIdWrapper,
-    build: Option<Build>,
-    install: Option<Install>,
-    llvm: Option<Llvm>,
-    gcc: Option<Gcc>,
-    rust: Option<Rust>,
-    target: Option<HashMap<String, TomlTarget>>,
-    dist: Option<Dist>,
-    profile: Option<String>,
-    include: Option<Vec<PathBuf>>,
-}
-
-/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`.
-#[derive(Clone, Debug, PartialEq)]
-pub enum ChangeId {
-    Ignore,
-    Id(usize),
-}
-
-/// Since we use `#[serde(deny_unknown_fields)]` on `TomlConfig`, we need a wrapper type
-/// for the "change-id" field to parse it even if other fields are invalid. This ensures
-/// that if deserialization fails due to other fields, we can still provide the changelogs
-/// to allow developers to potentially find the reason for the failure in the logs..
-#[derive(Deserialize, Default)]
-pub(crate) struct ChangeIdWrapper {
-    #[serde(alias = "change-id", default, deserialize_with = "deserialize_change_id")]
-    pub(crate) inner: Option<ChangeId>,
-}
-
-fn deserialize_change_id<'de, D: Deserializer<'de>>(
-    deserializer: D,
-) -> Result<Option<ChangeId>, D::Error> {
-    let value = toml::Value::deserialize(deserializer)?;
-    Ok(match value {
-        toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore),
-        toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)),
-        _ => {
-            return Err(serde::de::Error::custom(
-                "expected \"ignore\" or an integer for change-id",
-            ));
-        }
-    })
-}
-
-/// Describes how to handle conflicts in merging two [`TomlConfig`]
-#[derive(Copy, Clone, Debug)]
-enum ReplaceOpt {
-    /// Silently ignore a duplicated value
-    IgnoreDuplicate,
-    /// Override the current value, even if it's `Some`
-    Override,
-    /// Exit with an error on duplicate values
-    ErrorOnDuplicate,
-}
-
-trait Merge {
-    fn merge(
-        &mut self,
-        parent_config_path: Option<PathBuf>,
-        included_extensions: &mut HashSet<PathBuf>,
-        other: Self,
-        replace: ReplaceOpt,
-    );
-}
-
-impl Merge for TomlConfig {
-    fn merge(
-        &mut self,
-        parent_config_path: Option<PathBuf>,
-        included_extensions: &mut HashSet<PathBuf>,
-        TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self,
-        replace: ReplaceOpt,
-    ) {
-        fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) {
-            if let Some(new) = y {
-                if let Some(original) = x {
-                    original.merge(None, &mut Default::default(), new, replace);
-                } else {
-                    *x = Some(new);
-                }
-            }
-        }
-
-        self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace);
-        self.profile.merge(None, &mut Default::default(), profile, replace);
-
-        do_merge(&mut self.build, build, replace);
-        do_merge(&mut self.install, install, replace);
-        do_merge(&mut self.llvm, llvm, replace);
-        do_merge(&mut self.gcc, gcc, replace);
-        do_merge(&mut self.rust, rust, replace);
-        do_merge(&mut self.dist, dist, replace);
-
-        match (self.target.as_mut(), target) {
-            (_, None) => {}
-            (None, Some(target)) => self.target = Some(target),
-            (Some(original_target), Some(new_target)) => {
-                for (triple, new) in new_target {
-                    if let Some(original) = original_target.get_mut(&triple) {
-                        original.merge(None, &mut Default::default(), new, replace);
-                    } else {
-                        original_target.insert(triple, new);
-                    }
-                }
-            }
-        }
-
-        let parent_dir = parent_config_path
-            .as_ref()
-            .and_then(|p| p.parent().map(ToOwned::to_owned))
-            .unwrap_or_default();
-
-        // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to
-        // keep the upper-level configuration to take precedence.
-        for include_path in include.clone().unwrap_or_default().iter().rev() {
-            let include_path = parent_dir.join(include_path);
-            let include_path = include_path.canonicalize().unwrap_or_else(|e| {
-                eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display());
-                exit!(2);
-            });
-
-            let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| {
-                eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
-                exit!(2);
-            });
-
-            assert!(
-                included_extensions.insert(include_path.clone()),
-                "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.",
-                include_path.display()
-            );
-
-            self.merge(
-                Some(include_path.clone()),
-                included_extensions,
-                included_toml,
-                // Ensures that parent configuration always takes precedence
-                // over child configurations.
-                ReplaceOpt::IgnoreDuplicate,
-            );
-
-            included_extensions.remove(&include_path);
-        }
-    }
-}
-
-// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap.
-macro_rules! define_config {
-    ($(#[$attr:meta])* struct $name:ident {
-        $($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
-    }) => {
-        $(#[$attr])*
-        struct $name {
-            $($field: Option<$field_ty>,)*
-        }
-
-        impl Merge for $name {
-            fn merge(
-                &mut self,
-                _parent_config_path: Option<PathBuf>,
-                _included_extensions: &mut HashSet<PathBuf>,
-                other: Self,
-                replace: ReplaceOpt
-            ) {
-                $(
-                    match replace {
-                        ReplaceOpt::IgnoreDuplicate => {
-                            if self.$field.is_none() {
-                                self.$field = other.$field;
-                            }
-                        },
-                        ReplaceOpt::Override => {
-                            if other.$field.is_some() {
-                                self.$field = other.$field;
-                            }
-                        }
-                        ReplaceOpt::ErrorOnDuplicate => {
-                            if other.$field.is_some() {
-                                if self.$field.is_some() {
-                                    if cfg!(test) {
-                                        panic!("overriding existing option")
-                                    } else {
-                                        eprintln!("overriding existing option: `{}`", stringify!($field));
-                                        exit!(2);
-                                    }
-                                } else {
-                                    self.$field = other.$field;
-                                }
-                            }
-                        }
-                    }
-                )*
-            }
-        }
-
-        // The following is a trimmed version of what serde_derive generates. All parts not relevant
-        // for toml deserialization have been removed. This reduces the binary size and improves
-        // compile time of bootstrap.
-        impl<'de> Deserialize<'de> for $name {
-            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-            where
-                D: Deserializer<'de>,
-            {
-                struct Field;
-                impl<'de> serde::de::Visitor<'de> for Field {
-                    type Value = $name;
-                    fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                        f.write_str(concat!("struct ", stringify!($name)))
-                    }
-
-                    #[inline]
-                    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
-                    where
-                        A: serde::de::MapAccess<'de>,
-                    {
-                        $(let mut $field: Option<$field_ty> = None;)*
-                        while let Some(key) =
-                            match serde::de::MapAccess::next_key::<String>(&mut map) {
-                                Ok(val) => val,
-                                Err(err) => {
-                                    return Err(err);
-                                }
-                            }
-                        {
-                            match &*key {
-                                $($field_key => {
-                                    if $field.is_some() {
-                                        return Err(<A::Error as serde::de::Error>::duplicate_field(
-                                            $field_key,
-                                        ));
-                                    }
-                                    $field = match serde::de::MapAccess::next_value::<$field_ty>(
-                                        &mut map,
-                                    ) {
-                                        Ok(val) => Some(val),
-                                        Err(err) => {
-                                            return Err(err);
-                                        }
-                                    };
-                                })*
-                                key => {
-                                    return Err(serde::de::Error::unknown_field(key, FIELDS));
-                                }
-                            }
-                        }
-                        Ok($name { $($field),* })
-                    }
-                }
-                const FIELDS: &'static [&'static str] = &[
-                    $($field_key,)*
-                ];
-                Deserializer::deserialize_struct(
-                    deserializer,
-                    stringify!($name),
-                    FIELDS,
-                    Field,
-                )
-            }
-        }
-    }
-}
-
-impl<T> Merge for Option<T> {
-    fn merge(
-        &mut self,
-        _parent_config_path: Option<PathBuf>,
-        _included_extensions: &mut HashSet<PathBuf>,
-        other: Self,
-        replace: ReplaceOpt,
-    ) {
-        match replace {
-            ReplaceOpt::IgnoreDuplicate => {
-                if self.is_none() {
-                    *self = other;
-                }
-            }
-            ReplaceOpt::Override => {
-                if other.is_some() {
-                    *self = other;
-                }
-            }
-            ReplaceOpt::ErrorOnDuplicate => {
-                if other.is_some() {
-                    if self.is_some() {
-                        if cfg!(test) {
-                            panic!("overriding existing option")
-                        } else {
-                            eprintln!("overriding existing option");
-                            exit!(2);
-                        }
-                    } else {
-                        *self = other;
-                    }
-                }
-            }
-        }
-    }
-}
-
-define_config! {
-    /// TOML representation of various global build decisions.
-    #[derive(Default)]
-    struct Build {
-        build: Option<String> = "build",
-        description: Option<String> = "description",
-        host: Option<Vec<String>> = "host",
-        target: Option<Vec<String>> = "target",
-        build_dir: Option<String> = "build-dir",
-        cargo: Option<PathBuf> = "cargo",
-        rustc: Option<PathBuf> = "rustc",
-        rustfmt: Option<PathBuf> = "rustfmt",
-        cargo_clippy: Option<PathBuf> = "cargo-clippy",
-        docs: Option<bool> = "docs",
-        compiler_docs: Option<bool> = "compiler-docs",
-        library_docs_private_items: Option<bool> = "library-docs-private-items",
-        docs_minification: Option<bool> = "docs-minification",
-        submodules: Option<bool> = "submodules",
-        gdb: Option<String> = "gdb",
-        lldb: Option<String> = "lldb",
-        nodejs: Option<String> = "nodejs",
-        npm: Option<String> = "npm",
-        python: Option<String> = "python",
-        reuse: Option<String> = "reuse",
-        locked_deps: Option<bool> = "locked-deps",
-        vendor: Option<bool> = "vendor",
-        full_bootstrap: Option<bool> = "full-bootstrap",
-        bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path",
-        extended: Option<bool> = "extended",
-        tools: Option<HashSet<String>> = "tools",
-        verbose: Option<usize> = "verbose",
-        sanitizers: Option<bool> = "sanitizers",
-        profiler: Option<bool> = "profiler",
-        cargo_native_static: Option<bool> = "cargo-native-static",
-        low_priority: Option<bool> = "low-priority",
-        configure_args: Option<Vec<String>> = "configure-args",
-        local_rebuild: Option<bool> = "local-rebuild",
-        print_step_timings: Option<bool> = "print-step-timings",
-        print_step_rusage: Option<bool> = "print-step-rusage",
-        check_stage: Option<u32> = "check-stage",
-        doc_stage: Option<u32> = "doc-stage",
-        build_stage: Option<u32> = "build-stage",
-        test_stage: Option<u32> = "test-stage",
-        install_stage: Option<u32> = "install-stage",
-        dist_stage: Option<u32> = "dist-stage",
-        bench_stage: Option<u32> = "bench-stage",
-        patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
-        // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally
-        metrics: Option<bool> = "metrics",
-        android_ndk: Option<PathBuf> = "android-ndk",
-        optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
-        jobs: Option<u32> = "jobs",
-        compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
-        compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
-        ccache: Option<StringOrBool> = "ccache",
-        exclude: Option<Vec<PathBuf>> = "exclude",
-    }
-}
-
-define_config! {
-    /// TOML representation of various global install decisions.
-    struct Install {
-        prefix: Option<String> = "prefix",
-        sysconfdir: Option<String> = "sysconfdir",
-        docdir: Option<String> = "docdir",
-        bindir: Option<String> = "bindir",
-        libdir: Option<String> = "libdir",
-        mandir: Option<String> = "mandir",
-        datadir: Option<String> = "datadir",
-    }
-}
-
-define_config! {
-    /// TOML representation of how the LLVM build is configured.
-    struct Llvm {
-        optimize: Option<bool> = "optimize",
-        thin_lto: Option<bool> = "thin-lto",
-        release_debuginfo: Option<bool> = "release-debuginfo",
-        assertions: Option<bool> = "assertions",
-        tests: Option<bool> = "tests",
-        enzyme: Option<bool> = "enzyme",
-        plugins: Option<bool> = "plugins",
-        // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache
-        ccache: Option<StringOrBool> = "ccache",
-        static_libstdcpp: Option<bool> = "static-libstdcpp",
-        libzstd: Option<bool> = "libzstd",
-        ninja: Option<bool> = "ninja",
-        targets: Option<String> = "targets",
-        experimental_targets: Option<String> = "experimental-targets",
-        link_jobs: Option<u32> = "link-jobs",
-        link_shared: Option<bool> = "link-shared",
-        version_suffix: Option<String> = "version-suffix",
-        clang_cl: Option<String> = "clang-cl",
-        cflags: Option<String> = "cflags",
-        cxxflags: Option<String> = "cxxflags",
-        ldflags: Option<String> = "ldflags",
-        use_libcxx: Option<bool> = "use-libcxx",
-        use_linker: Option<String> = "use-linker",
-        allow_old_toolchain: Option<bool> = "allow-old-toolchain",
-        offload: Option<bool> = "offload",
-        polly: Option<bool> = "polly",
-        clang: Option<bool> = "clang",
-        enable_warnings: Option<bool> = "enable-warnings",
-        download_ci_llvm: Option<StringOrBool> = "download-ci-llvm",
-        build_config: Option<HashMap<String, String>> = "build-config",
-    }
-}
-
-define_config! {
-    /// TOML representation of how the GCC build is configured.
-    struct Gcc {
-        download_ci_gcc: Option<bool> = "download-ci-gcc",
-    }
-}
-
-define_config! {
-    struct Dist {
-        sign_folder: Option<String> = "sign-folder",
-        upload_addr: Option<String> = "upload-addr",
-        src_tarball: Option<bool> = "src-tarball",
-        compression_formats: Option<Vec<String>> = "compression-formats",
-        compression_profile: Option<String> = "compression-profile",
-        include_mingw_linker: Option<bool> = "include-mingw-linker",
-        vendor: Option<bool> = "vendor",
-    }
-}
-
-#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
-#[serde(untagged)]
-pub enum StringOrBool {
-    String(String),
-    Bool(bool),
-}
-
-impl Default for StringOrBool {
-    fn default() -> StringOrBool {
-        StringOrBool::Bool(false)
-    }
-}
-
-impl StringOrBool {
-    fn is_string_or_true(&self) -> bool {
-        matches!(self, Self::String(_) | Self::Bool(true))
-    }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum RustOptimize {
-    String(String),
-    Int(u8),
-    Bool(bool),
-}
-
-impl Default for RustOptimize {
-    fn default() -> RustOptimize {
-        RustOptimize::Bool(false)
-    }
-}
-
-impl<'de> Deserialize<'de> for RustOptimize {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        deserializer.deserialize_any(OptimizeVisitor)
-    }
-}
-
-struct OptimizeVisitor;
-
-impl serde::de::Visitor<'_> for OptimizeVisitor {
-    type Value = RustOptimize;
-
-    fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#)
-    }
-
-    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        if matches!(value, "s" | "z") {
-            Ok(RustOptimize::String(value.to_string()))
-        } else {
-            Err(serde::de::Error::custom(format_optimize_error_msg(value)))
-        }
-    }
-
-    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        if matches!(value, 0..=3) {
-            Ok(RustOptimize::Int(value as u8))
-        } else {
-            Err(serde::de::Error::custom(format_optimize_error_msg(value)))
-        }
-    }
-
-    fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
-    where
-        E: serde::de::Error,
-    {
-        Ok(RustOptimize::Bool(value))
-    }
-}
-
-fn format_optimize_error_msg(v: impl std::fmt::Display) -> String {
-    format!(
-        r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"#
-    )
-}
-
-impl RustOptimize {
-    pub(crate) fn is_release(&self) -> bool {
-        match &self {
-            RustOptimize::Bool(true) | RustOptimize::String(_) => true,
-            RustOptimize::Int(i) => *i > 0,
-            RustOptimize::Bool(false) => false,
-        }
-    }
-
-    pub(crate) fn get_opt_level(&self) -> Option<String> {
-        match &self {
-            RustOptimize::String(s) => Some(s.clone()),
-            RustOptimize::Int(i) => Some(i.to_string()),
-            RustOptimize::Bool(_) => None,
-        }
-    }
-}
-
-#[derive(Deserialize)]
-#[serde(untagged)]
-enum StringOrInt {
-    String(String),
-    Int(i64),
-}
-
-impl<'de> Deserialize<'de> for LldMode {
-    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        struct LldModeVisitor;
-
-        impl serde::de::Visitor<'_> for LldModeVisitor {
-            type Value = LldMode;
-
-            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-                formatter.write_str("one of true, 'self-contained' or 'external'")
-            }
-
-            fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
-            where
-                E: serde::de::Error,
-            {
-                Ok(if v { LldMode::External } else { LldMode::Unused })
-            }
-
-            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
-            where
-                E: serde::de::Error,
-            {
-                match v {
-                    "external" => Ok(LldMode::External),
-                    "self-contained" => Ok(LldMode::SelfContained),
-                    _ => Err(E::custom(format!("unknown mode {v}"))),
-                }
-            }
-        }
-
-        deserializer.deserialize_any(LldModeVisitor)
-    }
-}
-
-define_config! {
-    /// TOML representation of how the Rust build is configured.
-    struct Rust {
-        optimize: Option<RustOptimize> = "optimize",
-        debug: Option<bool> = "debug",
-        codegen_units: Option<u32> = "codegen-units",
-        codegen_units_std: Option<u32> = "codegen-units-std",
-        rustc_debug_assertions: Option<bool> = "debug-assertions",
-        randomize_layout: Option<bool> = "randomize-layout",
-        std_debug_assertions: Option<bool> = "debug-assertions-std",
-        tools_debug_assertions: Option<bool> = "debug-assertions-tools",
-        overflow_checks: Option<bool> = "overflow-checks",
-        overflow_checks_std: Option<bool> = "overflow-checks-std",
-        debug_logging: Option<bool> = "debug-logging",
-        debuginfo_level: Option<DebuginfoLevel> = "debuginfo-level",
-        debuginfo_level_rustc: Option<DebuginfoLevel> = "debuginfo-level-rustc",
-        debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std",
-        debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools",
-        debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests",
-        backtrace: Option<bool> = "backtrace",
-        incremental: Option<bool> = "incremental",
-        default_linker: Option<String> = "default-linker",
-        channel: Option<String> = "channel",
-        // FIXME: Remove this field at Q2 2025, it has been replaced by build.description
-        description: Option<String> = "description",
-        musl_root: Option<String> = "musl-root",
-        rpath: Option<bool> = "rpath",
-        strip: Option<bool> = "strip",
-        frame_pointers: Option<bool> = "frame-pointers",
-        stack_protector: Option<String> = "stack-protector",
-        verbose_tests: Option<bool> = "verbose-tests",
-        optimize_tests: Option<bool> = "optimize-tests",
-        codegen_tests: Option<bool> = "codegen-tests",
-        omit_git_hash: Option<bool> = "omit-git-hash",
-        dist_src: Option<bool> = "dist-src",
-        save_toolstates: Option<String> = "save-toolstates",
-        codegen_backends: Option<Vec<String>> = "codegen-backends",
-        llvm_bitcode_linker: Option<bool> = "llvm-bitcode-linker",
-        lld: Option<bool> = "lld",
-        lld_mode: Option<LldMode> = "use-lld",
-        llvm_tools: Option<bool> = "llvm-tools",
-        deny_warnings: Option<bool> = "deny-warnings",
-        backtrace_on_ice: Option<bool> = "backtrace-on-ice",
-        verify_llvm_ir: Option<bool> = "verify-llvm-ir",
-        thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit",
-        remap_debuginfo: Option<bool> = "remap-debuginfo",
-        jemalloc: Option<bool> = "jemalloc",
-        test_compare_mode: Option<bool> = "test-compare-mode",
-        llvm_libunwind: Option<String> = "llvm-libunwind",
-        control_flow_guard: Option<bool> = "control-flow-guard",
-        ehcont_guard: Option<bool> = "ehcont-guard",
-        new_symbol_mangling: Option<bool> = "new-symbol-mangling",
-        profile_generate: Option<String> = "profile-generate",
-        profile_use: Option<String> = "profile-use",
-        // ignored; this is set from an env var set by bootstrap.py
-        download_rustc: Option<StringOrBool> = "download-rustc",
-        lto: Option<String> = "lto",
-        validate_mir_opts: Option<u32> = "validate-mir-opts",
-        std_features: Option<BTreeSet<String>> = "std-features",
-    }
-}
-
-define_config! {
-    /// TOML representation of how each build target is configured.
-    struct TomlTarget {
-        cc: Option<String> = "cc",
-        cxx: Option<String> = "cxx",
-        ar: Option<String> = "ar",
-        ranlib: Option<String> = "ranlib",
-        default_linker: Option<PathBuf> = "default-linker",
-        linker: Option<String> = "linker",
-        split_debuginfo: Option<String> = "split-debuginfo",
-        llvm_config: Option<String> = "llvm-config",
-        llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches",
-        llvm_filecheck: Option<String> = "llvm-filecheck",
-        llvm_libunwind: Option<String> = "llvm-libunwind",
-        sanitizers: Option<bool> = "sanitizers",
-        profiler: Option<StringOrBool> = "profiler",
-        rpath: Option<bool> = "rpath",
-        crt_static: Option<bool> = "crt-static",
-        musl_root: Option<String> = "musl-root",
-        musl_libdir: Option<String> = "musl-libdir",
-        wasi_root: Option<String> = "wasi-root",
-        qemu_rootfs: Option<String> = "qemu-rootfs",
-        no_std: Option<bool> = "no-std",
-        codegen_backends: Option<Vec<String>> = "codegen-backends",
-        runner: Option<String> = "runner",
-        optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
-        jemalloc: Option<bool> = "jemalloc",
-    }
-}
-
 impl Config {
     #[cfg_attr(
         feature = "tracing",
@@ -1410,47 +362,6 @@ impl Config {
         }
     }
 
-    pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result<TomlConfig, toml::de::Error> {
-        if self.dry_run() {
-            return Ok(TomlConfig::default());
-        }
-
-        let builder_config_path =
-            self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME);
-        Self::get_toml(&builder_config_path)
-    }
-
-    pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
-        #[cfg(test)]
-        return Ok(TomlConfig::default());
-
-        #[cfg(not(test))]
-        Self::get_toml_inner(file)
-    }
-
-    fn get_toml_inner(file: &Path) -> Result<TomlConfig, toml::de::Error> {
-        let contents =
-            t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
-        // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
-        // TomlConfig and sub types to be monomorphized 5x by toml.
-        toml::from_str(&contents)
-            .and_then(|table: toml::Value| TomlConfig::deserialize(table))
-            .inspect_err(|_| {
-                if let Ok(ChangeIdWrapper { inner: Some(ChangeId::Id(id)) }) =
-                    toml::from_str::<toml::Value>(&contents)
-                        .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table))
-                {
-                    let changes = crate::find_recent_config_change_ids(id);
-                    if !changes.is_empty() {
-                        println!(
-                            "WARNING: There have been changes to x.py since you last updated:\n{}",
-                            crate::human_readable_changes(changes)
-                        );
-                    }
-                }
-            })
-    }
-
     #[cfg_attr(
         feature = "tracing",
         instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::parse", skip_all)
@@ -1912,42 +823,11 @@ impl Config {
         // Verbose flag is a good default for `rust.verbose-tests`.
         config.verbose_tests = config.is_verbose();
 
-        if let Some(install) = toml.install {
-            let Install { prefix, sysconfdir, docdir, bindir, libdir, mandir, datadir } = install;
-            config.prefix = prefix.map(PathBuf::from);
-            config.sysconfdir = sysconfdir.map(PathBuf::from);
-            config.datadir = datadir.map(PathBuf::from);
-            config.docdir = docdir.map(PathBuf::from);
-            set(&mut config.bindir, bindir.map(PathBuf::from));
-            config.libdir = libdir.map(PathBuf::from);
-            config.mandir = mandir.map(PathBuf::from);
-        }
+        config.apply_install_config(toml.install);
 
         config.llvm_assertions =
             toml.llvm.as_ref().is_some_and(|llvm| llvm.assertions.unwrap_or(false));
 
-        // Store off these values as options because if they're not provided
-        // we'll infer default values for them later
-        let mut llvm_tests = None;
-        let mut llvm_enzyme = None;
-        let mut llvm_offload = None;
-        let mut llvm_plugins = None;
-        let mut debug = None;
-        let mut rustc_debug_assertions = None;
-        let mut std_debug_assertions = None;
-        let mut tools_debug_assertions = None;
-        let mut overflow_checks = None;
-        let mut overflow_checks_std = None;
-        let mut debug_logging = None;
-        let mut debuginfo_level = None;
-        let mut debuginfo_level_rustc = None;
-        let mut debuginfo_level_std = None;
-        let mut debuginfo_level_tools = None;
-        let mut debuginfo_level_tests = None;
-        let mut optimize = None;
-        let mut lld_enabled = None;
-        let mut std_features = None;
-
         let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel")));
         let ci_channel = file_content.trim_end();
 
@@ -1991,190 +871,10 @@ impl Config {
             config.channel = ci_channel.into();
         }
 
-        if let Some(rust) = toml.rust {
-            let Rust {
-                optimize: optimize_toml,
-                debug: debug_toml,
-                codegen_units,
-                codegen_units_std,
-                rustc_debug_assertions: rustc_debug_assertions_toml,
-                std_debug_assertions: std_debug_assertions_toml,
-                tools_debug_assertions: tools_debug_assertions_toml,
-                overflow_checks: overflow_checks_toml,
-                overflow_checks_std: overflow_checks_std_toml,
-                debug_logging: debug_logging_toml,
-                debuginfo_level: debuginfo_level_toml,
-                debuginfo_level_rustc: debuginfo_level_rustc_toml,
-                debuginfo_level_std: debuginfo_level_std_toml,
-                debuginfo_level_tools: debuginfo_level_tools_toml,
-                debuginfo_level_tests: debuginfo_level_tests_toml,
-                backtrace,
-                incremental,
-                randomize_layout,
-                default_linker,
-                channel: _, // already handled above
-                description: rust_description,
-                musl_root,
-                rpath,
-                verbose_tests,
-                optimize_tests,
-                codegen_tests,
-                omit_git_hash: _, // already handled above
-                dist_src,
-                save_toolstates,
-                codegen_backends,
-                lld: lld_enabled_toml,
-                llvm_tools,
-                llvm_bitcode_linker,
-                deny_warnings,
-                backtrace_on_ice,
-                verify_llvm_ir,
-                thin_lto_import_instr_limit,
-                remap_debuginfo,
-                jemalloc,
-                test_compare_mode,
-                llvm_libunwind,
-                control_flow_guard,
-                ehcont_guard,
-                new_symbol_mangling,
-                profile_generate,
-                profile_use,
-                download_rustc,
-                lto,
-                validate_mir_opts,
-                frame_pointers,
-                stack_protector,
-                strip,
-                lld_mode,
-                std_features: std_features_toml,
-            } = rust;
-
-            // FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions
-            // enabled. We should not download a CI alt rustc if we need rustc to have debug
-            // assertions (e.g. for crashes test suite). This can be changed once something like
-            // [Enable debug assertions on alt
-            // builds](https://github.com/rust-lang/rust/pull/131077) lands.
-            //
-            // Note that `rust.debug = true` currently implies `rust.debug-assertions = true`!
-            //
-            // This relies also on the fact that the global default for `download-rustc` will be
-            // `false` if it's not explicitly set.
-            let debug_assertions_requested = matches!(rustc_debug_assertions_toml, Some(true))
-                || (matches!(debug_toml, Some(true))
-                    && !matches!(rustc_debug_assertions_toml, Some(false)));
-
-            if debug_assertions_requested
-                && let Some(ref opt) = download_rustc
-                && opt.is_string_or_true()
-            {
-                eprintln!(
-                    "WARN: currently no CI rustc builds have rustc debug assertions \
-                            enabled. Please either set `rust.debug-assertions` to `false` if you \
-                            want to use download CI rustc or set `rust.download-rustc` to `false`."
-                );
-            }
+        config.rust_profile_use = flags.rust_profile_use;
+        config.rust_profile_generate = flags.rust_profile_generate;
 
-            config.download_rustc_commit = config.download_ci_rustc_commit(
-                download_rustc,
-                debug_assertions_requested,
-                config.llvm_assertions,
-            );
-
-            debug = debug_toml;
-            rustc_debug_assertions = rustc_debug_assertions_toml;
-            std_debug_assertions = std_debug_assertions_toml;
-            tools_debug_assertions = tools_debug_assertions_toml;
-            overflow_checks = overflow_checks_toml;
-            overflow_checks_std = overflow_checks_std_toml;
-            debug_logging = debug_logging_toml;
-            debuginfo_level = debuginfo_level_toml;
-            debuginfo_level_rustc = debuginfo_level_rustc_toml;
-            debuginfo_level_std = debuginfo_level_std_toml;
-            debuginfo_level_tools = debuginfo_level_tools_toml;
-            debuginfo_level_tests = debuginfo_level_tests_toml;
-            lld_enabled = lld_enabled_toml;
-            std_features = std_features_toml;
-
-            optimize = optimize_toml;
-            config.rust_new_symbol_mangling = new_symbol_mangling;
-            set(&mut config.rust_optimize_tests, optimize_tests);
-            set(&mut config.codegen_tests, codegen_tests);
-            set(&mut config.rust_rpath, rpath);
-            set(&mut config.rust_strip, strip);
-            set(&mut config.rust_frame_pointers, frame_pointers);
-            config.rust_stack_protector = stack_protector;
-            set(&mut config.jemalloc, jemalloc);
-            set(&mut config.test_compare_mode, test_compare_mode);
-            set(&mut config.backtrace, backtrace);
-            if rust_description.is_some() {
-                eprintln!(
-                    "Warning: rust.description is deprecated. Use build.description instead."
-                );
-            }
-            description = description.or(rust_description);
-            set(&mut config.rust_dist_src, dist_src);
-            set(&mut config.verbose_tests, verbose_tests);
-            // in the case "false" is set explicitly, do not overwrite the command line args
-            if let Some(true) = incremental {
-                config.incremental = true;
-            }
-            set(&mut config.lld_mode, lld_mode);
-            set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
-
-            config.rust_randomize_layout = randomize_layout.unwrap_or_default();
-            config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
-
-            config.llvm_enzyme =
-                llvm_enzyme.unwrap_or(config.channel == "dev" || config.channel == "nightly");
-            config.rustc_default_linker = default_linker;
-            config.musl_root = musl_root.map(PathBuf::from);
-            config.save_toolstates = save_toolstates.map(PathBuf::from);
-            set(
-                &mut config.deny_warnings,
-                match flags.warnings {
-                    Warnings::Deny => Some(true),
-                    Warnings::Warn => Some(false),
-                    Warnings::Default => deny_warnings,
-                },
-            );
-            set(&mut config.backtrace_on_ice, backtrace_on_ice);
-            set(&mut config.rust_verify_llvm_ir, verify_llvm_ir);
-            config.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit;
-            set(&mut config.rust_remap_debuginfo, remap_debuginfo);
-            set(&mut config.control_flow_guard, control_flow_guard);
-            set(&mut config.ehcont_guard, ehcont_guard);
-            config.llvm_libunwind_default =
-                llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
-
-            if let Some(ref backends) = codegen_backends {
-                let available_backends = ["llvm", "cranelift", "gcc"];
-
-                config.rust_codegen_backends = backends.iter().map(|s| {
-                    if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
-                        if available_backends.contains(&backend) {
-                            panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'.");
-                        } else {
-                            println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \
-                                Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
-                                In this case, it would be referred to as '{backend}'.");
-                        }
-                    }
-
-                    s.clone()
-                }).collect();
-            }
-
-            config.rust_codegen_units = codegen_units.map(threads_from_config);
-            config.rust_codegen_units_std = codegen_units_std.map(threads_from_config);
-            config.rust_profile_use = flags.rust_profile_use.or(profile_use);
-            config.rust_profile_generate = flags.rust_profile_generate.or(profile_generate);
-            config.rust_lto =
-                lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default();
-            config.rust_validate_mir_opts = validate_mir_opts;
-        } else {
-            config.rust_profile_use = flags.rust_profile_use;
-            config.rust_profile_generate = flags.rust_profile_generate;
-        }
+        config.apply_rust_config(toml.rust, flags.warnings, &mut description);
 
         config.reproducible_artifacts = flags.reproducible_artifact;
         config.description = description;
@@ -2195,206 +895,11 @@ impl Config {
             config.channel = channel;
         }
 
-        if let Some(llvm) = toml.llvm {
-            let Llvm {
-                optimize: optimize_toml,
-                thin_lto,
-                release_debuginfo,
-                assertions: _,
-                tests,
-                enzyme,
-                plugins,
-                ccache: llvm_ccache,
-                static_libstdcpp,
-                libzstd,
-                ninja,
-                targets,
-                experimental_targets,
-                link_jobs,
-                link_shared,
-                version_suffix,
-                clang_cl,
-                cflags,
-                cxxflags,
-                ldflags,
-                use_libcxx,
-                use_linker,
-                allow_old_toolchain,
-                offload,
-                polly,
-                clang,
-                enable_warnings,
-                download_ci_llvm,
-                build_config,
-            } = llvm;
-            if llvm_ccache.is_some() {
-                eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead.");
-            }
-
-            ccache = ccache.or(llvm_ccache);
-            set(&mut config.ninja_in_file, ninja);
-            llvm_tests = tests;
-            llvm_enzyme = enzyme;
-            llvm_offload = offload;
-            llvm_plugins = plugins;
-            set(&mut config.llvm_optimize, optimize_toml);
-            set(&mut config.llvm_thin_lto, thin_lto);
-            set(&mut config.llvm_release_debuginfo, release_debuginfo);
-            set(&mut config.llvm_static_stdcpp, static_libstdcpp);
-            set(&mut config.llvm_libzstd, libzstd);
-            if let Some(v) = link_shared {
-                config.llvm_link_shared.set(Some(v));
-            }
-            config.llvm_targets.clone_from(&targets);
-            config.llvm_experimental_targets.clone_from(&experimental_targets);
-            config.llvm_link_jobs = link_jobs;
-            config.llvm_version_suffix.clone_from(&version_suffix);
-            config.llvm_clang_cl.clone_from(&clang_cl);
-
-            config.llvm_cflags.clone_from(&cflags);
-            config.llvm_cxxflags.clone_from(&cxxflags);
-            config.llvm_ldflags.clone_from(&ldflags);
-            set(&mut config.llvm_use_libcxx, use_libcxx);
-            config.llvm_use_linker.clone_from(&use_linker);
-            config.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false);
-            config.llvm_offload = offload.unwrap_or(false);
-            config.llvm_polly = polly.unwrap_or(false);
-            config.llvm_clang = clang.unwrap_or(false);
-            config.llvm_enable_warnings = enable_warnings.unwrap_or(false);
-            config.llvm_build_config = build_config.clone().unwrap_or(Default::default());
-
-            config.llvm_from_ci =
-                config.parse_download_ci_llvm(download_ci_llvm, config.llvm_assertions);
-
-            if config.llvm_from_ci {
-                let warn = |option: &str| {
-                    println!(
-                        "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build."
-                    );
-                    println!(
-                        "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false."
-                    );
-                };
-
-                if static_libstdcpp.is_some() {
-                    warn("static-libstdcpp");
-                }
-
-                if link_shared.is_some() {
-                    warn("link-shared");
-                }
-
-                // FIXME(#129153): instead of all the ad-hoc `download-ci-llvm` checks that follow,
-                // use the `builder-config` present in tarballs since #128822 to compare the local
-                // config to the ones used to build the LLVM artifacts on CI, and only notify users
-                // if they've chosen a different value.
-
-                if libzstd.is_some() {
-                    println!(
-                        "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \
-                        like almost all `llvm.*` options, will be ignored and set by the LLVM CI \
-                        artifacts builder config."
-                    );
-                    println!(
-                        "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false."
-                    );
-                }
-            }
-
-            if !config.llvm_from_ci && config.llvm_thin_lto && link_shared.is_none() {
-                // If we're building with ThinLTO on, by default we want to link
-                // to LLVM shared, to avoid re-doing ThinLTO (which happens in
-                // the link step) with each stage.
-                config.llvm_link_shared.set(Some(true));
-            }
-        } else {
-            config.llvm_from_ci = config.parse_download_ci_llvm(None, false);
-        }
-
-        if let Some(gcc) = toml.gcc {
-            config.gcc_ci_mode = match gcc.download_ci_gcc {
-                Some(value) => match value {
-                    true => GccCiMode::DownloadFromCi,
-                    false => GccCiMode::BuildLocally,
-                },
-                None => GccCiMode::default(),
-            };
-        }
+        config.apply_llvm_config(toml.llvm, &mut ccache);
 
-        if let Some(t) = toml.target {
-            for (triple, cfg) in t {
-                let mut target = Target::from_triple(&triple);
+        config.apply_gcc_config(toml.gcc);
 
-                if let Some(ref s) = cfg.llvm_config {
-                    if config.download_rustc_commit.is_some() && triple == *config.build.triple {
-                        panic!(
-                            "setting llvm_config for the host is incompatible with download-rustc"
-                        );
-                    }
-                    target.llvm_config = Some(config.src.join(s));
-                }
-                if let Some(patches) = cfg.llvm_has_rust_patches {
-                    assert!(
-                        config.submodules == Some(false) || cfg.llvm_config.is_some(),
-                        "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided"
-                    );
-                    target.llvm_has_rust_patches = Some(patches);
-                }
-                if let Some(ref s) = cfg.llvm_filecheck {
-                    target.llvm_filecheck = Some(config.src.join(s));
-                }
-                target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| {
-                    v.parse().unwrap_or_else(|_| {
-                        panic!("failed to parse target.{triple}.llvm-libunwind")
-                    })
-                });
-                if let Some(s) = cfg.no_std {
-                    target.no_std = s;
-                }
-                target.cc = cfg.cc.map(PathBuf::from);
-                target.cxx = cfg.cxx.map(PathBuf::from);
-                target.ar = cfg.ar.map(PathBuf::from);
-                target.ranlib = cfg.ranlib.map(PathBuf::from);
-                target.linker = cfg.linker.map(PathBuf::from);
-                target.crt_static = cfg.crt_static;
-                target.musl_root = cfg.musl_root.map(PathBuf::from);
-                target.musl_libdir = cfg.musl_libdir.map(PathBuf::from);
-                target.wasi_root = cfg.wasi_root.map(PathBuf::from);
-                target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from);
-                target.runner = cfg.runner;
-                target.sanitizers = cfg.sanitizers;
-                target.profiler = cfg.profiler;
-                target.rpath = cfg.rpath;
-                target.optimized_compiler_builtins = cfg.optimized_compiler_builtins;
-                target.jemalloc = cfg.jemalloc;
-
-                if let Some(ref backends) = cfg.codegen_backends {
-                    let available_backends = ["llvm", "cranelift", "gcc"];
-
-                    target.codegen_backends = Some(backends.iter().map(|s| {
-                        if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
-                            if available_backends.contains(&backend) {
-                                panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'.");
-                            } else {
-                                println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
-                                    Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
-                                    In this case, it would be referred to as '{backend}'.");
-                            }
-                        }
-
-                        s.clone()
-                    }).collect());
-                }
-
-                target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| {
-                    v.parse().unwrap_or_else(|_| {
-                        panic!("invalid value for target.{triple}.split-debuginfo")
-                    })
-                });
-
-                config.target_config.insert(TargetSelection::from_user(&triple), target);
-            }
-        }
+        config.apply_target_config(toml.target);
 
         match ccache {
             Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()),
@@ -2418,69 +923,11 @@ impl Config {
             build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build)));
         }
 
-        if let Some(dist) = toml.dist {
-            let Dist {
-                sign_folder,
-                upload_addr,
-                src_tarball,
-                compression_formats,
-                compression_profile,
-                include_mingw_linker,
-                vendor,
-            } = dist;
-            config.dist_sign_folder = sign_folder.map(PathBuf::from);
-            config.dist_upload_addr = upload_addr;
-            config.dist_compression_formats = compression_formats;
-            set(&mut config.dist_compression_profile, compression_profile);
-            set(&mut config.rust_dist_src, src_tarball);
-            set(&mut config.dist_include_mingw_linker, include_mingw_linker);
-            config.dist_vendor = vendor.unwrap_or_else(|| {
-                // If we're building from git or tarball sources, enable it by default.
-                config.rust_info.is_managed_git_subrepository()
-                    || config.rust_info.is_from_tarball()
-            });
-        }
+        config.apply_dist_config(toml.dist);
 
         config.initial_rustfmt =
             if let Some(r) = rustfmt { Some(r) } else { config.maybe_download_rustfmt() };
 
-        // Now that we've reached the end of our configuration, infer the
-        // default values for all options that we haven't otherwise stored yet.
-
-        config.llvm_tests = llvm_tests.unwrap_or(false);
-        config.llvm_enzyme = llvm_enzyme.unwrap_or(false);
-        config.llvm_offload = llvm_offload.unwrap_or(false);
-        config.llvm_plugins = llvm_plugins.unwrap_or(false);
-        config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
-
-        // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will
-        // build our internal lld and use it as the default linker, by setting the `rust.lld` config
-        // to true by default:
-        // - on the `x86_64-unknown-linux-gnu` target
-        // - on the `dev` and `nightly` channels
-        // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
-        //   we're also able to build the corresponding lld
-        // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
-        //   lld
-        // - otherwise, we'd be using an external llvm, and lld would not necessarily available and
-        //   thus, disabled
-        // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
-        //   when the config sets `rust.lld = false`
-        if config.build.triple == "x86_64-unknown-linux-gnu"
-            && config.hosts == [config.build]
-            && (config.channel == "dev" || config.channel == "nightly")
-        {
-            let no_llvm_config = config
-                .target_config
-                .get(&config.build)
-                .is_some_and(|target_config| target_config.llvm_config.is_none());
-            let enable_lld = config.llvm_from_ci || no_llvm_config;
-            // Prefer the config setting in case an explicit opt-out is needed.
-            config.lld_enabled = lld_enabled.unwrap_or(enable_lld);
-        } else {
-            set(&mut config.lld_enabled, lld_enabled);
-        }
-
         if matches!(config.lld_mode, LldMode::SelfContained)
             && !config.lld_enabled
             && flags.stage.unwrap_or(0) > 0
@@ -2496,31 +943,6 @@ impl Config {
             );
         }
 
-        let default_std_features = BTreeSet::from([String::from("panic-unwind")]);
-        config.rust_std_features = std_features.unwrap_or(default_std_features);
-
-        let default = debug == Some(true);
-        config.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default);
-        config.std_debug_assertions = std_debug_assertions.unwrap_or(config.rustc_debug_assertions);
-        config.tools_debug_assertions =
-            tools_debug_assertions.unwrap_or(config.rustc_debug_assertions);
-        config.rust_overflow_checks = overflow_checks.unwrap_or(default);
-        config.rust_overflow_checks_std =
-            overflow_checks_std.unwrap_or(config.rust_overflow_checks);
-
-        config.rust_debug_logging = debug_logging.unwrap_or(config.rustc_debug_assertions);
-
-        let with_defaults = |debuginfo_level_specific: Option<_>| {
-            debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
-                DebuginfoLevel::Limited
-            } else {
-                DebuginfoLevel::None
-            })
-        };
-        config.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc);
-        config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std);
-        config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
-        config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None);
         config.optimized_compiler_builtins =
             optimized_compiler_builtins.unwrap_or(config.channel != "dev");
         config.compiletest_diff_tool = compiletest_diff_tool;
@@ -2845,75 +1267,17 @@ impl Config {
         }
     }
 
-    pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
-        self.target_config.get(&target).and_then(|t| t.sanitizers).unwrap_or(self.sanitizers)
-    }
-
-    pub fn needs_sanitizer_runtime_built(&self, target: TargetSelection) -> bool {
-        // MSVC uses the Microsoft-provided sanitizer runtime, but all other runtimes we build.
-        !target.is_msvc() && self.sanitizers_enabled(target)
-    }
-
     pub fn any_sanitizers_to_build(&self) -> bool {
         self.target_config
             .iter()
             .any(|(ts, t)| !ts.is_msvc() && t.sanitizers.unwrap_or(self.sanitizers))
     }
 
-    pub fn profiler_path(&self, target: TargetSelection) -> Option<&str> {
-        match self.target_config.get(&target)?.profiler.as_ref()? {
-            StringOrBool::String(s) => Some(s),
-            StringOrBool::Bool(_) => None,
-        }
-    }
-
-    pub fn profiler_enabled(&self, target: TargetSelection) -> bool {
-        self.target_config
-            .get(&target)
-            .and_then(|t| t.profiler.as_ref())
-            .map(StringOrBool::is_string_or_true)
-            .unwrap_or(self.profiler)
-    }
-
     pub fn any_profiler_enabled(&self) -> bool {
         self.target_config.values().any(|t| matches!(&t.profiler, Some(p) if p.is_string_or_true()))
             || self.profiler
     }
 
-    pub fn rpath_enabled(&self, target: TargetSelection) -> bool {
-        self.target_config.get(&target).and_then(|t| t.rpath).unwrap_or(self.rust_rpath)
-    }
-
-    pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool {
-        self.target_config
-            .get(&target)
-            .and_then(|t| t.optimized_compiler_builtins)
-            .unwrap_or(self.optimized_compiler_builtins)
-    }
-
-    pub fn llvm_enabled(&self, target: TargetSelection) -> bool {
-        self.codegen_backends(target).contains(&"llvm".to_owned())
-    }
-
-    pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind {
-        self.target_config
-            .get(&target)
-            .and_then(|t| t.llvm_libunwind)
-            .or(self.llvm_libunwind_default)
-            .unwrap_or(if target.contains("fuchsia") {
-                LlvmLibunwind::InTree
-            } else {
-                LlvmLibunwind::No
-            })
-    }
-
-    pub fn split_debuginfo(&self, target: TargetSelection) -> SplitDebuginfo {
-        self.target_config
-            .get(&target)
-            .and_then(|t| t.split_debuginfo)
-            .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target))
-    }
-
     /// Returns whether or not submodules should be managed by bootstrap.
     pub fn submodules(&self) -> bool {
         // If not specified in config, the default is to only manage
@@ -2921,21 +1285,6 @@ impl Config {
         self.submodules.unwrap_or(self.rust_info.is_managed_git_subrepository())
     }
 
-    pub fn codegen_backends(&self, target: TargetSelection) -> &[String] {
-        self.target_config
-            .get(&target)
-            .and_then(|cfg| cfg.codegen_backends.as_deref())
-            .unwrap_or(&self.rust_codegen_backends)
-    }
-
-    pub fn jemalloc(&self, target: TargetSelection) -> bool {
-        self.target_config.get(&target).and_then(|cfg| cfg.jemalloc).unwrap_or(self.jemalloc)
-    }
-
-    pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<String> {
-        self.codegen_backends(target).first().cloned()
-    }
-
     pub fn git_config(&self) -> GitConfig<'_> {
         GitConfig {
             nightly_branch: &self.stage0_metadata.config.nightly_branch,
@@ -3119,7 +1468,7 @@ impl Config {
     }
 
     /// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
-    fn download_ci_rustc_commit(
+    pub fn download_ci_rustc_commit(
         &self,
         download_rustc: Option<StringOrBool>,
         debug_assertions_requested: bool,
@@ -3199,7 +1548,7 @@ impl Config {
         Some(commit)
     }
 
-    fn parse_download_ci_llvm(
+    pub fn parse_download_ci_llvm(
         &self,
         download_ci_llvm: Option<StringOrBool>,
         asserts: bool,
@@ -3282,6 +1631,83 @@ impl Config {
             .clone()
     }
 
+    pub fn ci_env(&self) -> CiEnv {
+        if self.is_running_on_ci { CiEnv::GitHubActions } else { CiEnv::None }
+    }
+
+    pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
+        self.target_config.get(&target).and_then(|t| t.sanitizers).unwrap_or(self.sanitizers)
+    }
+
+    pub fn needs_sanitizer_runtime_built(&self, target: TargetSelection) -> bool {
+        // MSVC uses the Microsoft-provided sanitizer runtime, but all other runtimes we build.
+        !target.is_msvc() && self.sanitizers_enabled(target)
+    }
+
+    pub fn profiler_path(&self, target: TargetSelection) -> Option<&str> {
+        match self.target_config.get(&target)?.profiler.as_ref()? {
+            StringOrBool::String(s) => Some(s),
+            StringOrBool::Bool(_) => None,
+        }
+    }
+
+    pub fn profiler_enabled(&self, target: TargetSelection) -> bool {
+        self.target_config
+            .get(&target)
+            .and_then(|t| t.profiler.as_ref())
+            .map(StringOrBool::is_string_or_true)
+            .unwrap_or(self.profiler)
+    }
+
+    pub fn codegen_backends(&self, target: TargetSelection) -> &[String] {
+        self.target_config
+            .get(&target)
+            .and_then(|cfg| cfg.codegen_backends.as_deref())
+            .unwrap_or(&self.rust_codegen_backends)
+    }
+
+    pub fn jemalloc(&self, target: TargetSelection) -> bool {
+        self.target_config.get(&target).and_then(|cfg| cfg.jemalloc).unwrap_or(self.jemalloc)
+    }
+
+    pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<String> {
+        self.codegen_backends(target).first().cloned()
+    }
+
+    pub fn rpath_enabled(&self, target: TargetSelection) -> bool {
+        self.target_config.get(&target).and_then(|t| t.rpath).unwrap_or(self.rust_rpath)
+    }
+
+    pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool {
+        self.target_config
+            .get(&target)
+            .and_then(|t| t.optimized_compiler_builtins)
+            .unwrap_or(self.optimized_compiler_builtins)
+    }
+
+    pub fn llvm_enabled(&self, target: TargetSelection) -> bool {
+        self.codegen_backends(target).contains(&"llvm".to_owned())
+    }
+
+    pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind {
+        self.target_config
+            .get(&target)
+            .and_then(|t| t.llvm_libunwind)
+            .or(self.llvm_libunwind_default)
+            .unwrap_or(if target.contains("fuchsia") {
+                LlvmLibunwind::InTree
+            } else {
+                LlvmLibunwind::No
+            })
+    }
+
+    pub fn split_debuginfo(&self, target: TargetSelection) -> SplitDebuginfo {
+        self.target_config
+            .get(&target)
+            .and_then(|t| t.split_debuginfo)
+            .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target))
+    }
+
     /// Checks if the given target is the same as the host target.
     pub fn is_host_target(&self, target: TargetSelection) -> bool {
         self.build == target
@@ -3317,290 +1743,4 @@ impl Config {
             _ => !self.is_system_llvm(target),
         }
     }
-
-    pub fn ci_env(&self) -> CiEnv {
-        if self.is_running_on_ci { CiEnv::GitHubActions } else { CiEnv::None }
-    }
-}
-
-/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options.
-/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing.
-#[cfg(not(test))]
-pub(crate) fn check_incompatible_options_for_ci_llvm(
-    current_config_toml: TomlConfig,
-    ci_config_toml: TomlConfig,
-) -> Result<(), String> {
-    macro_rules! err {
-        ($current:expr, $expected:expr) => {
-            if let Some(current) = &$current {
-                if Some(current) != $expected.as_ref() {
-                    return Err(format!(
-                        "ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \
-                        Current value: {:?}, Expected value(s): {}{:?}",
-                        stringify!($expected).replace("_", "-"),
-                        $current,
-                        if $expected.is_some() { "None/" } else { "" },
-                        $expected,
-                    ));
-                };
-            };
-        };
-    }
-
-    macro_rules! warn {
-        ($current:expr, $expected:expr) => {
-            if let Some(current) = &$current {
-                if Some(current) != $expected.as_ref() {
-                    println!(
-                        "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \
-                        Current value: {:?}, Expected value(s): {}{:?}",
-                        stringify!($expected).replace("_", "-"),
-                        $current,
-                        if $expected.is_some() { "None/" } else { "" },
-                        $expected,
-                    );
-                };
-            };
-        };
-    }
-
-    let (Some(current_llvm_config), Some(ci_llvm_config)) =
-        (current_config_toml.llvm, ci_config_toml.llvm)
-    else {
-        return Ok(());
-    };
-
-    let Llvm {
-        optimize,
-        thin_lto,
-        release_debuginfo,
-        assertions: _,
-        tests: _,
-        plugins,
-        ccache: _,
-        static_libstdcpp: _,
-        libzstd,
-        ninja: _,
-        targets,
-        experimental_targets,
-        link_jobs: _,
-        link_shared: _,
-        version_suffix,
-        clang_cl,
-        cflags,
-        cxxflags,
-        ldflags,
-        use_libcxx,
-        use_linker,
-        allow_old_toolchain,
-        offload,
-        polly,
-        clang,
-        enable_warnings,
-        download_ci_llvm: _,
-        build_config,
-        enzyme,
-    } = ci_llvm_config;
-
-    err!(current_llvm_config.optimize, optimize);
-    err!(current_llvm_config.thin_lto, thin_lto);
-    err!(current_llvm_config.release_debuginfo, release_debuginfo);
-    err!(current_llvm_config.libzstd, libzstd);
-    err!(current_llvm_config.targets, targets);
-    err!(current_llvm_config.experimental_targets, experimental_targets);
-    err!(current_llvm_config.clang_cl, clang_cl);
-    err!(current_llvm_config.version_suffix, version_suffix);
-    err!(current_llvm_config.cflags, cflags);
-    err!(current_llvm_config.cxxflags, cxxflags);
-    err!(current_llvm_config.ldflags, ldflags);
-    err!(current_llvm_config.use_libcxx, use_libcxx);
-    err!(current_llvm_config.use_linker, use_linker);
-    err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain);
-    err!(current_llvm_config.offload, offload);
-    err!(current_llvm_config.polly, polly);
-    err!(current_llvm_config.clang, clang);
-    err!(current_llvm_config.build_config, build_config);
-    err!(current_llvm_config.plugins, plugins);
-    err!(current_llvm_config.enzyme, enzyme);
-
-    warn!(current_llvm_config.enable_warnings, enable_warnings);
-
-    Ok(())
-}
-
-/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options.
-/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing.
-fn check_incompatible_options_for_ci_rustc(
-    host: TargetSelection,
-    current_config_toml: TomlConfig,
-    ci_config_toml: TomlConfig,
-) -> Result<(), String> {
-    macro_rules! err {
-        ($current:expr, $expected:expr, $config_section:expr) => {
-            if let Some(current) = &$current {
-                if Some(current) != $expected.as_ref() {
-                    return Err(format!(
-                        "ERROR: Setting `{}` is incompatible with `rust.download-rustc`. \
-                        Current value: {:?}, Expected value(s): {}{:?}",
-                        format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
-                        $current,
-                        if $expected.is_some() { "None/" } else { "" },
-                        $expected,
-                    ));
-                };
-            };
-        };
-    }
-
-    macro_rules! warn {
-        ($current:expr, $expected:expr, $config_section:expr) => {
-            if let Some(current) = &$current {
-                if Some(current) != $expected.as_ref() {
-                    println!(
-                        "WARNING: `{}` has no effect with `rust.download-rustc`. \
-                        Current value: {:?}, Expected value(s): {}{:?}",
-                        format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
-                        $current,
-                        if $expected.is_some() { "None/" } else { "" },
-                        $expected,
-                    );
-                };
-            };
-        };
-    }
-
-    let current_profiler = current_config_toml.build.as_ref().and_then(|b| b.profiler);
-    let profiler = ci_config_toml.build.as_ref().and_then(|b| b.profiler);
-    err!(current_profiler, profiler, "build");
-
-    let current_optimized_compiler_builtins =
-        current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins);
-    let optimized_compiler_builtins =
-        ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins);
-    err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build");
-
-    // We always build the in-tree compiler on cross targets, so we only care
-    // about the host target here.
-    let host_str = host.to_string();
-    if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str))
-        && current_cfg.profiler.is_some()
-    {
-        let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str));
-        let ci_cfg = ci_target_toml.ok_or(format!(
-            "Target specific config for '{host_str}' is not present for CI-rustc"
-        ))?;
-
-        let profiler = &ci_cfg.profiler;
-        err!(current_cfg.profiler, profiler, "build");
-
-        let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins;
-        err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build");
-    }
-
-    let (Some(current_rust_config), Some(ci_rust_config)) =
-        (current_config_toml.rust, ci_config_toml.rust)
-    else {
-        return Ok(());
-    };
-
-    let Rust {
-        // Following options are the CI rustc incompatible ones.
-        optimize,
-        randomize_layout,
-        debug_logging,
-        debuginfo_level_rustc,
-        llvm_tools,
-        llvm_bitcode_linker,
-        lto,
-        stack_protector,
-        strip,
-        lld_mode,
-        jemalloc,
-        rpath,
-        channel,
-        description,
-        incremental,
-        default_linker,
-        std_features,
-
-        // Rest of the options can simply be ignored.
-        debug: _,
-        codegen_units: _,
-        codegen_units_std: _,
-        rustc_debug_assertions: _,
-        std_debug_assertions: _,
-        tools_debug_assertions: _,
-        overflow_checks: _,
-        overflow_checks_std: _,
-        debuginfo_level: _,
-        debuginfo_level_std: _,
-        debuginfo_level_tools: _,
-        debuginfo_level_tests: _,
-        backtrace: _,
-        musl_root: _,
-        verbose_tests: _,
-        optimize_tests: _,
-        codegen_tests: _,
-        omit_git_hash: _,
-        dist_src: _,
-        save_toolstates: _,
-        codegen_backends: _,
-        lld: _,
-        deny_warnings: _,
-        backtrace_on_ice: _,
-        verify_llvm_ir: _,
-        thin_lto_import_instr_limit: _,
-        remap_debuginfo: _,
-        test_compare_mode: _,
-        llvm_libunwind: _,
-        control_flow_guard: _,
-        ehcont_guard: _,
-        new_symbol_mangling: _,
-        profile_generate: _,
-        profile_use: _,
-        download_rustc: _,
-        validate_mir_opts: _,
-        frame_pointers: _,
-    } = ci_rust_config;
-
-    // There are two kinds of checks for CI rustc incompatible options:
-    //    1. Checking an option that may change the compiler behaviour/output.
-    //    2. Checking an option that have no effect on the compiler behaviour/output.
-    //
-    // If the option belongs to the first category, we call `err` macro for a hard error;
-    // otherwise, we just print a warning with `warn` macro.
-
-    err!(current_rust_config.optimize, optimize, "rust");
-    err!(current_rust_config.randomize_layout, randomize_layout, "rust");
-    err!(current_rust_config.debug_logging, debug_logging, "rust");
-    err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust");
-    err!(current_rust_config.rpath, rpath, "rust");
-    err!(current_rust_config.strip, strip, "rust");
-    err!(current_rust_config.lld_mode, lld_mode, "rust");
-    err!(current_rust_config.llvm_tools, llvm_tools, "rust");
-    err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust");
-    err!(current_rust_config.jemalloc, jemalloc, "rust");
-    err!(current_rust_config.default_linker, default_linker, "rust");
-    err!(current_rust_config.stack_protector, stack_protector, "rust");
-    err!(current_rust_config.lto, lto, "rust");
-    err!(current_rust_config.std_features, std_features, "rust");
-
-    warn!(current_rust_config.channel, channel, "rust");
-    warn!(current_rust_config.description, description, "rust");
-    warn!(current_rust_config.incremental, incremental, "rust");
-
-    Ok(())
-}
-
-fn set<T>(field: &mut T, val: Option<T>) {
-    if let Some(v) = val {
-        *field = v;
-    }
-}
-
-fn threads_from_config(v: u32) -> u32 {
-    match v {
-        0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32,
-        n => n,
-    }
 }
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 45a0836ee67..30617f58d43 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -12,7 +12,8 @@ use tracing::instrument;
 use crate::core::build_steps::perf::PerfArgs;
 use crate::core::build_steps::setup::Profile;
 use crate::core::builder::{Builder, Kind};
-use crate::core::config::{Config, TargetSelectionList, target_selection_list};
+use crate::core::config::Config;
+use crate::core::config::target_selection::{TargetSelectionList, target_selection_list};
 use crate::{Build, DocTests};
 
 #[derive(Copy, Clone, Default, Debug, ValueEnum)]
diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs
index 179e15e778b..f39e7b02ccc 100644
--- a/src/bootstrap/src/core/config/mod.rs
+++ b/src/bootstrap/src/core/config/mod.rs
@@ -1,7 +1,418 @@
+//! Entry point for the `config` module.
+//!
+//! This module defines two macros:
+//!
+//! - `define_config!`: A declarative macro used instead of `#[derive(Deserialize)]` to reduce
+//!   compile time and binary size, especially for the bootstrap binary.
+//!
+//! - `check_ci_llvm!`: A compile-time assertion macro that ensures certain settings are
+//!   not enabled when `download-ci-llvm` is active.
+//!
+//! A declarative macro is used here in place of a procedural derive macro to minimize
+//! the compile time of the bootstrap process.
+//!
+//! Additionally, this module defines common types, enums, and helper functions used across
+//! various TOML configuration sections in `bootstrap.toml`.
+//!
+//! It provides shared definitions for:
+//! - Data types deserialized from TOML.
+//! - Utility enums for specific configuration options.
+//! - Helper functions for managing configuration values.
+
 #[expect(clippy::module_inception)]
 mod config;
 pub mod flags;
+pub mod target_selection;
 #[cfg(test)]
 mod tests;
+pub mod toml;
+
+use std::collections::HashSet;
+use std::path::PathBuf;
 
+use build_helper::exit;
 pub use config::*;
+use serde::{Deserialize, Deserializer};
+use serde_derive::Deserialize;
+pub use target_selection::TargetSelection;
+pub use toml::BUILDER_CONFIG_FILENAME;
+pub use toml::change_id::ChangeId;
+pub use toml::rust::LldMode;
+pub use toml::target::Target;
+#[cfg(feature = "tracing")]
+use tracing::{instrument, span};
+
+use crate::Display;
+use crate::str::FromStr;
+
+// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap.
+#[macro_export]
+macro_rules! define_config {
+    ($(#[$attr:meta])* struct $name:ident {
+        $($field:ident: Option<$field_ty:ty> = $field_key:literal,)*
+    }) => {
+        $(#[$attr])*
+        pub struct $name {
+            $(pub $field: Option<$field_ty>,)*
+        }
+
+        impl Merge for $name {
+            fn merge(
+                &mut self,
+                _parent_config_path: Option<PathBuf>,
+                _included_extensions: &mut HashSet<PathBuf>,
+                other: Self,
+                replace: ReplaceOpt
+            ) {
+                $(
+                    match replace {
+                        ReplaceOpt::IgnoreDuplicate => {
+                            if self.$field.is_none() {
+                                self.$field = other.$field;
+                            }
+                        },
+                        ReplaceOpt::Override => {
+                            if other.$field.is_some() {
+                                self.$field = other.$field;
+                            }
+                        }
+                        ReplaceOpt::ErrorOnDuplicate => {
+                            if other.$field.is_some() {
+                                if self.$field.is_some() {
+                                    if cfg!(test) {
+                                        panic!("overriding existing option")
+                                    } else {
+                                        eprintln!("overriding existing option: `{}`", stringify!($field));
+                                        exit!(2);
+                                    }
+                                } else {
+                                    self.$field = other.$field;
+                                }
+                            }
+                        }
+                    }
+                )*
+            }
+        }
+
+        // The following is a trimmed version of what serde_derive generates. All parts not relevant
+        // for toml deserialization have been removed. This reduces the binary size and improves
+        // compile time of bootstrap.
+        impl<'de> Deserialize<'de> for $name {
+            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+            where
+                D: Deserializer<'de>,
+            {
+                struct Field;
+                impl<'de> serde::de::Visitor<'de> for Field {
+                    type Value = $name;
+                    fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                        f.write_str(concat!("struct ", stringify!($name)))
+                    }
+
+                    #[inline]
+                    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
+                    where
+                        A: serde::de::MapAccess<'de>,
+                    {
+                        $(let mut $field: Option<$field_ty> = None;)*
+                        while let Some(key) =
+                            match serde::de::MapAccess::next_key::<String>(&mut map) {
+                                Ok(val) => val,
+                                Err(err) => {
+                                    return Err(err);
+                                }
+                            }
+                        {
+                            match &*key {
+                                $($field_key => {
+                                    if $field.is_some() {
+                                        return Err(<A::Error as serde::de::Error>::duplicate_field(
+                                            $field_key,
+                                        ));
+                                    }
+                                    $field = match serde::de::MapAccess::next_value::<$field_ty>(
+                                        &mut map,
+                                    ) {
+                                        Ok(val) => Some(val),
+                                        Err(err) => {
+                                            return Err(err);
+                                        }
+                                    };
+                                })*
+                                key => {
+                                    return Err(serde::de::Error::unknown_field(key, FIELDS));
+                                }
+                            }
+                        }
+                        Ok($name { $($field),* })
+                    }
+                }
+                const FIELDS: &'static [&'static str] = &[
+                    $($field_key,)*
+                ];
+                Deserializer::deserialize_struct(
+                    deserializer,
+                    stringify!($name),
+                    FIELDS,
+                    Field,
+                )
+            }
+        }
+    }
+}
+
+#[macro_export]
+macro_rules! check_ci_llvm {
+    ($name:expr) => {
+        assert!(
+            $name.is_none(),
+            "setting {} is incompatible with download-ci-llvm.",
+            stringify!($name).replace("_", "-")
+        );
+    };
+}
+
+pub(crate) trait Merge {
+    fn merge(
+        &mut self,
+        parent_config_path: Option<PathBuf>,
+        included_extensions: &mut HashSet<PathBuf>,
+        other: Self,
+        replace: ReplaceOpt,
+    );
+}
+
+impl<T> Merge for Option<T> {
+    fn merge(
+        &mut self,
+        _parent_config_path: Option<PathBuf>,
+        _included_extensions: &mut HashSet<PathBuf>,
+        other: Self,
+        replace: ReplaceOpt,
+    ) {
+        match replace {
+            ReplaceOpt::IgnoreDuplicate => {
+                if self.is_none() {
+                    *self = other;
+                }
+            }
+            ReplaceOpt::Override => {
+                if other.is_some() {
+                    *self = other;
+                }
+            }
+            ReplaceOpt::ErrorOnDuplicate => {
+                if other.is_some() {
+                    if self.is_some() {
+                        if cfg!(test) {
+                            panic!("overriding existing option")
+                        } else {
+                            eprintln!("overriding existing option");
+                            exit!(2);
+                        }
+                    } else {
+                        *self = other;
+                    }
+                }
+            }
+        }
+    }
+}
+
+#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
+pub enum DebuginfoLevel {
+    #[default]
+    None,
+    LineDirectivesOnly,
+    LineTablesOnly,
+    Limited,
+    Full,
+}
+
+// NOTE: can't derive(Deserialize) because the intermediate trip through toml::Value only
+// deserializes i64, and derive() only generates visit_u64
+impl<'de> Deserialize<'de> for DebuginfoLevel {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        use serde::de::Error;
+
+        Ok(match Deserialize::deserialize(deserializer)? {
+            StringOrInt::String(s) if s == "none" => DebuginfoLevel::None,
+            StringOrInt::Int(0) => DebuginfoLevel::None,
+            StringOrInt::String(s) if s == "line-directives-only" => {
+                DebuginfoLevel::LineDirectivesOnly
+            }
+            StringOrInt::String(s) if s == "line-tables-only" => DebuginfoLevel::LineTablesOnly,
+            StringOrInt::String(s) if s == "limited" => DebuginfoLevel::Limited,
+            StringOrInt::Int(1) => DebuginfoLevel::Limited,
+            StringOrInt::String(s) if s == "full" => DebuginfoLevel::Full,
+            StringOrInt::Int(2) => DebuginfoLevel::Full,
+            StringOrInt::Int(n) => {
+                let other = serde::de::Unexpected::Signed(n);
+                return Err(D::Error::invalid_value(other, &"expected 0, 1, or 2"));
+            }
+            StringOrInt::String(s) => {
+                let other = serde::de::Unexpected::Str(&s);
+                return Err(D::Error::invalid_value(
+                    other,
+                    &"expected none, line-tables-only, limited, or full",
+                ));
+            }
+        })
+    }
+}
+
+/// Suitable for passing to `-C debuginfo`
+impl Display for DebuginfoLevel {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        use DebuginfoLevel::*;
+        f.write_str(match self {
+            None => "0",
+            LineDirectivesOnly => "line-directives-only",
+            LineTablesOnly => "line-tables-only",
+            Limited => "1",
+            Full => "2",
+        })
+    }
+}
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
+#[serde(untagged)]
+pub enum StringOrBool {
+    String(String),
+    Bool(bool),
+}
+
+impl Default for StringOrBool {
+    fn default() -> StringOrBool {
+        StringOrBool::Bool(false)
+    }
+}
+
+impl StringOrBool {
+    pub fn is_string_or_true(&self) -> bool {
+        matches!(self, Self::String(_) | Self::Bool(true))
+    }
+}
+
+#[derive(Deserialize)]
+#[serde(untagged)]
+pub enum StringOrInt {
+    String(String),
+    Int(i64),
+}
+
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
+pub enum LlvmLibunwind {
+    #[default]
+    No,
+    InTree,
+    System,
+}
+
+impl FromStr for LlvmLibunwind {
+    type Err = String;
+
+    fn from_str(value: &str) -> Result<Self, Self::Err> {
+        match value {
+            "no" => Ok(Self::No),
+            "in-tree" => Ok(Self::InTree),
+            "system" => Ok(Self::System),
+            invalid => Err(format!("Invalid value '{invalid}' for rust.llvm-libunwind config.")),
+        }
+    }
+}
+
+#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum SplitDebuginfo {
+    Packed,
+    Unpacked,
+    #[default]
+    Off,
+}
+
+impl std::str::FromStr for SplitDebuginfo {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "packed" => Ok(SplitDebuginfo::Packed),
+            "unpacked" => Ok(SplitDebuginfo::Unpacked),
+            "off" => Ok(SplitDebuginfo::Off),
+            _ => Err(()),
+        }
+    }
+}
+
+/// Describes how to handle conflicts in merging two `TomlConfig`
+#[derive(Copy, Clone, Debug)]
+pub enum ReplaceOpt {
+    /// Silently ignore a duplicated value
+    IgnoreDuplicate,
+    /// Override the current value, even if it's `Some`
+    Override,
+    /// Exit with an error on duplicate values
+    ErrorOnDuplicate,
+}
+
+#[derive(Clone, Default)]
+pub enum DryRun {
+    /// This isn't a dry run.
+    #[default]
+    Disabled,
+    /// This is a dry run enabled by bootstrap itself, so it can verify that no work is done.
+    SelfCheck,
+    /// This is a dry run enabled by the `--dry-run` flag.
+    UserSelected,
+}
+
+/// LTO mode used for compiling rustc itself.
+#[derive(Default, Clone, PartialEq, Debug)]
+pub enum RustcLto {
+    Off,
+    #[default]
+    ThinLocal,
+    Thin,
+    Fat,
+}
+
+impl std::str::FromStr for RustcLto {
+    type Err = String;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "thin-local" => Ok(RustcLto::ThinLocal),
+            "thin" => Ok(RustcLto::Thin),
+            "fat" => Ok(RustcLto::Fat),
+            "off" => Ok(RustcLto::Off),
+            _ => Err(format!("Invalid value for rustc LTO: {s}")),
+        }
+    }
+}
+
+/// Determines how will GCC be provided.
+#[derive(Default, Clone)]
+pub enum GccCiMode {
+    /// Build GCC from the local `src/gcc` submodule.
+    #[default]
+    BuildLocally,
+    /// Try to download GCC from CI.
+    /// If it is not available on CI, it will be built locally instead.
+    DownloadFromCi,
+}
+
+pub fn set<T>(field: &mut T, val: Option<T>) {
+    if let Some(v) = val {
+        *field = v;
+    }
+}
+
+pub fn threads_from_config(v: u32) -> u32 {
+    match v {
+        0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32,
+        n => n,
+    }
+}
diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs
new file mode 100644
index 00000000000..ebd3fe7a8c6
--- /dev/null
+++ b/src/bootstrap/src/core/config/target_selection.rs
@@ -0,0 +1,147 @@
+use std::fmt;
+
+use crate::core::config::SplitDebuginfo;
+use crate::utils::cache::{INTERNER, Interned};
+use crate::{Path, env};
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy.
+// Making !Copy is highly nontrivial!
+pub struct TargetSelection {
+    pub triple: Interned<String>,
+    pub file: Option<Interned<String>>,
+    pub synthetic: bool,
+}
+
+/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
+#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct TargetSelectionList(pub Vec<TargetSelection>);
+
+pub fn target_selection_list(s: &str) -> Result<TargetSelectionList, String> {
+    Ok(TargetSelectionList(
+        s.split(',').filter(|s| !s.is_empty()).map(TargetSelection::from_user).collect(),
+    ))
+}
+
+impl TargetSelection {
+    pub fn from_user(selection: &str) -> Self {
+        let path = Path::new(selection);
+
+        let (triple, file) = if path.exists() {
+            let triple = path
+                .file_stem()
+                .expect("Target specification file has no file stem")
+                .to_str()
+                .expect("Target specification file stem is not UTF-8");
+
+            (triple, Some(selection))
+        } else {
+            (selection, None)
+        };
+
+        let triple = INTERNER.intern_str(triple);
+        let file = file.map(|f| INTERNER.intern_str(f));
+
+        Self { triple, file, synthetic: false }
+    }
+
+    pub fn create_synthetic(triple: &str, file: &str) -> Self {
+        Self {
+            triple: INTERNER.intern_str(triple),
+            file: Some(INTERNER.intern_str(file)),
+            synthetic: true,
+        }
+    }
+
+    pub fn rustc_target_arg(&self) -> &str {
+        self.file.as_ref().unwrap_or(&self.triple)
+    }
+
+    pub fn contains(&self, needle: &str) -> bool {
+        self.triple.contains(needle)
+    }
+
+    pub fn starts_with(&self, needle: &str) -> bool {
+        self.triple.starts_with(needle)
+    }
+
+    pub fn ends_with(&self, needle: &str) -> bool {
+        self.triple.ends_with(needle)
+    }
+
+    // See src/bootstrap/synthetic_targets.rs
+    pub fn is_synthetic(&self) -> bool {
+        self.synthetic
+    }
+
+    pub fn is_msvc(&self) -> bool {
+        self.contains("msvc")
+    }
+
+    pub fn is_windows(&self) -> bool {
+        self.contains("windows")
+    }
+
+    pub fn is_windows_gnu(&self) -> bool {
+        self.ends_with("windows-gnu")
+    }
+
+    pub fn is_cygwin(&self) -> bool {
+        self.is_windows() &&
+        // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html
+        env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin"))
+    }
+
+    pub fn needs_crt_begin_end(&self) -> bool {
+        self.contains("musl") && !self.contains("unikraft")
+    }
+
+    /// Path to the file defining the custom target, if any.
+    pub fn filepath(&self) -> Option<&Path> {
+        self.file.as_ref().map(Path::new)
+    }
+}
+
+impl fmt::Display for TargetSelection {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.triple)?;
+        if let Some(file) = self.file {
+            write!(f, "({file})")?;
+        }
+        Ok(())
+    }
+}
+
+impl fmt::Debug for TargetSelection {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{self}")
+    }
+}
+
+impl PartialEq<&str> for TargetSelection {
+    fn eq(&self, other: &&str) -> bool {
+        self.triple == *other
+    }
+}
+
+// Targets are often used as directory names throughout bootstrap.
+// This impl makes it more ergonomics to use them as such.
+impl AsRef<Path> for TargetSelection {
+    fn as_ref(&self) -> &Path {
+        self.triple.as_ref()
+    }
+}
+
+impl SplitDebuginfo {
+    /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for
+    /// `rust.split-debuginfo` in `bootstrap.example.toml`.
+    pub fn default_for_platform(target: TargetSelection) -> Self {
+        if target.contains("apple") {
+            SplitDebuginfo::Unpacked
+        } else if target.is_windows() {
+            SplitDebuginfo::Packed
+        } else {
+            SplitDebuginfo::Off
+        }
+    }
+}
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index 96ac8a6d52f..50eba12aba7 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -10,12 +10,14 @@ use clap::CommandFactory;
 use serde::Deserialize;
 
 use super::flags::Flags;
-use super::{ChangeIdWrapper, Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS};
+use super::toml::change_id::ChangeIdWrapper;
+use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS};
 use crate::ChangeId;
 use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order};
 use crate::core::build_steps::llvm;
 use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS;
-use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig};
+use crate::core::config::toml::TomlConfig;
+use crate::core::config::{LldMode, Target, TargetSelection};
 use crate::utils::tests::git::git_test;
 
 pub(crate) fn parse(config: &str) -> Config {
diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs
new file mode 100644
index 00000000000..85ded3c87d9
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/build.rs
@@ -0,0 +1,72 @@
+//! This module defines the `Build` struct, which represents the `[build]` table
+//! in the `bootstrap.toml` configuration file.
+//!
+//! The `[build]` table contains global options that influence the overall build process,
+//! such as default host and target triples, paths to tools, build directories, and
+//! various feature flags. These options apply across different stages and components
+//! unless specifically overridden by other configuration sections or command-line flags.
+
+use serde::{Deserialize, Deserializer};
+
+use crate::core::config::toml::ReplaceOpt;
+use crate::core::config::{Merge, StringOrBool};
+use crate::{HashSet, PathBuf, define_config, exit};
+
+define_config! {
+    /// TOML representation of various global build decisions.
+    #[derive(Default)]
+    struct Build {
+        build: Option<String> = "build",
+        description: Option<String> = "description",
+        host: Option<Vec<String>> = "host",
+        target: Option<Vec<String>> = "target",
+        build_dir: Option<String> = "build-dir",
+        cargo: Option<PathBuf> = "cargo",
+        rustc: Option<PathBuf> = "rustc",
+        rustfmt: Option<PathBuf> = "rustfmt",
+        cargo_clippy: Option<PathBuf> = "cargo-clippy",
+        docs: Option<bool> = "docs",
+        compiler_docs: Option<bool> = "compiler-docs",
+        library_docs_private_items: Option<bool> = "library-docs-private-items",
+        docs_minification: Option<bool> = "docs-minification",
+        submodules: Option<bool> = "submodules",
+        gdb: Option<String> = "gdb",
+        lldb: Option<String> = "lldb",
+        nodejs: Option<String> = "nodejs",
+        npm: Option<String> = "npm",
+        python: Option<String> = "python",
+        reuse: Option<String> = "reuse",
+        locked_deps: Option<bool> = "locked-deps",
+        vendor: Option<bool> = "vendor",
+        full_bootstrap: Option<bool> = "full-bootstrap",
+        bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path",
+        extended: Option<bool> = "extended",
+        tools: Option<HashSet<String>> = "tools",
+        verbose: Option<usize> = "verbose",
+        sanitizers: Option<bool> = "sanitizers",
+        profiler: Option<bool> = "profiler",
+        cargo_native_static: Option<bool> = "cargo-native-static",
+        low_priority: Option<bool> = "low-priority",
+        configure_args: Option<Vec<String>> = "configure-args",
+        local_rebuild: Option<bool> = "local-rebuild",
+        print_step_timings: Option<bool> = "print-step-timings",
+        print_step_rusage: Option<bool> = "print-step-rusage",
+        check_stage: Option<u32> = "check-stage",
+        doc_stage: Option<u32> = "doc-stage",
+        build_stage: Option<u32> = "build-stage",
+        test_stage: Option<u32> = "test-stage",
+        install_stage: Option<u32> = "install-stage",
+        dist_stage: Option<u32> = "dist-stage",
+        bench_stage: Option<u32> = "bench-stage",
+        patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
+        // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally
+        metrics: Option<bool> = "metrics",
+        android_ndk: Option<PathBuf> = "android-ndk",
+        optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
+        jobs: Option<u32> = "jobs",
+        compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
+        compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
+        ccache: Option<StringOrBool> = "ccache",
+        exclude: Option<Vec<PathBuf>> = "exclude",
+    }
+}
diff --git a/src/bootstrap/src/core/config/toml/change_id.rs b/src/bootstrap/src/core/config/toml/change_id.rs
new file mode 100644
index 00000000000..41dd2531d43
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/change_id.rs
@@ -0,0 +1,34 @@
+use serde::{Deserialize, Deserializer};
+use serde_derive::Deserialize;
+
+/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`.
+#[derive(Clone, Debug, PartialEq)]
+pub enum ChangeId {
+    Ignore,
+    Id(usize),
+}
+
+/// Since we use `#[serde(deny_unknown_fields)]` on `TomlConfig`, we need a wrapper type
+/// for the "change-id" field to parse it even if other fields are invalid. This ensures
+/// that if deserialization fails due to other fields, we can still provide the changelogs
+/// to allow developers to potentially find the reason for the failure in the logs..
+#[derive(Deserialize, Default)]
+pub(crate) struct ChangeIdWrapper {
+    #[serde(alias = "change-id", default, deserialize_with = "deserialize_change_id")]
+    pub(crate) inner: Option<ChangeId>,
+}
+
+fn deserialize_change_id<'de, D: Deserializer<'de>>(
+    deserializer: D,
+) -> Result<Option<ChangeId>, D::Error> {
+    let value = toml::Value::deserialize(deserializer)?;
+    Ok(match value {
+        toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore),
+        toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)),
+        _ => {
+            return Err(serde::de::Error::custom(
+                "expected \"ignore\" or an integer for change-id",
+            ));
+        }
+    })
+}
diff --git a/src/bootstrap/src/core/config/toml/dist.rs b/src/bootstrap/src/core/config/toml/dist.rs
new file mode 100644
index 00000000000..b1429ef1861
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/dist.rs
@@ -0,0 +1,52 @@
+//! This module defines the `Dist` struct, which represents the `[dist]` table
+//! in the `bootstrap.toml` configuration file.
+//!
+//! The `[dist]` table contains options related to the distribution process,
+//! including signing, uploading artifacts, source tarballs, compression settings,
+//! and inclusion of specific tools.
+
+use serde::{Deserialize, Deserializer};
+
+use crate::core::config::toml::ReplaceOpt;
+use crate::core::config::{Merge, set};
+use crate::{Config, HashSet, PathBuf, define_config, exit};
+
+define_config! {
+    struct Dist {
+        sign_folder: Option<String> = "sign-folder",
+        upload_addr: Option<String> = "upload-addr",
+        src_tarball: Option<bool> = "src-tarball",
+        compression_formats: Option<Vec<String>> = "compression-formats",
+        compression_profile: Option<String> = "compression-profile",
+        include_mingw_linker: Option<bool> = "include-mingw-linker",
+        vendor: Option<bool> = "vendor",
+    }
+}
+
+impl Config {
+    /// Applies distribution-related configuration from the `Dist` struct
+    /// to the global `Config` structure.
+    pub fn apply_dist_config(&mut self, toml_dist: Option<Dist>) {
+        if let Some(dist) = toml_dist {
+            let Dist {
+                sign_folder,
+                upload_addr,
+                src_tarball,
+                compression_formats,
+                compression_profile,
+                include_mingw_linker,
+                vendor,
+            } = dist;
+            self.dist_sign_folder = sign_folder.map(PathBuf::from);
+            self.dist_upload_addr = upload_addr;
+            self.dist_compression_formats = compression_formats;
+            set(&mut self.dist_compression_profile, compression_profile);
+            set(&mut self.rust_dist_src, src_tarball);
+            set(&mut self.dist_include_mingw_linker, include_mingw_linker);
+            self.dist_vendor = vendor.unwrap_or_else(|| {
+                // If we're building from git or tarball sources, enable it by default.
+                self.rust_info.is_managed_git_subrepository() || self.rust_info.is_from_tarball()
+            });
+        }
+    }
+}
diff --git a/src/bootstrap/src/core/config/toml/gcc.rs b/src/bootstrap/src/core/config/toml/gcc.rs
new file mode 100644
index 00000000000..bb817c2aaef
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/gcc.rs
@@ -0,0 +1,34 @@
+//! This module defines the `Gcc` struct, which represents the `[gcc]` table
+//! in the `bootstrap.toml` configuration file.
+//!
+//! The `[gcc]` table contains options specifically related to building or
+//! acquiring the GCC compiler for use within the Rust build process.
+
+use serde::{Deserialize, Deserializer};
+
+use crate::core::config::toml::ReplaceOpt;
+use crate::core::config::{GccCiMode, Merge};
+use crate::{Config, HashSet, PathBuf, define_config, exit};
+
+define_config! {
+    /// TOML representation of how the GCC build is configured.
+    struct Gcc {
+        download_ci_gcc: Option<bool> = "download-ci-gcc",
+    }
+}
+
+impl Config {
+    /// Applies GCC-related configuration from the `TomlGcc` struct to the
+    /// global `Config` structure.
+    pub fn apply_gcc_config(&mut self, toml_gcc: Option<Gcc>) {
+        if let Some(gcc) = toml_gcc {
+            self.gcc_ci_mode = match gcc.download_ci_gcc {
+                Some(value) => match value {
+                    true => GccCiMode::DownloadFromCi,
+                    false => GccCiMode::BuildLocally,
+                },
+                None => GccCiMode::default(),
+            };
+        }
+    }
+}
diff --git a/src/bootstrap/src/core/config/toml/install.rs b/src/bootstrap/src/core/config/toml/install.rs
new file mode 100644
index 00000000000..6b9ab87a0b6
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/install.rs
@@ -0,0 +1,43 @@
+//! This module defines the `Install` struct, which represents the `[install]` table
+//! in the `bootstrap.toml` configuration file.
+//!
+//! The `[install]` table contains options that specify the installation paths
+//! for various components of the Rust toolchain. These paths determine where
+//! executables, libraries, documentation, and other files will be placed
+//! during the `install` stage of the build.
+
+use serde::{Deserialize, Deserializer};
+
+use crate::core::config::toml::ReplaceOpt;
+use crate::core::config::{Merge, set};
+use crate::{Config, HashSet, PathBuf, define_config, exit};
+
+define_config! {
+    /// TOML representation of various global install decisions.
+    struct Install {
+        prefix: Option<String> = "prefix",
+        sysconfdir: Option<String> = "sysconfdir",
+        docdir: Option<String> = "docdir",
+        bindir: Option<String> = "bindir",
+        libdir: Option<String> = "libdir",
+        mandir: Option<String> = "mandir",
+        datadir: Option<String> = "datadir",
+    }
+}
+
+impl Config {
+    /// Applies installation-related configuration from the `Install` struct
+    /// to the global `Config` structure.
+    pub fn apply_install_config(&mut self, toml_install: Option<Install>) {
+        if let Some(install) = toml_install {
+            let Install { prefix, sysconfdir, docdir, bindir, libdir, mandir, datadir } = install;
+            self.prefix = prefix.map(PathBuf::from);
+            self.sysconfdir = sysconfdir.map(PathBuf::from);
+            self.datadir = datadir.map(PathBuf::from);
+            self.docdir = docdir.map(PathBuf::from);
+            set(&mut self.bindir, bindir.map(PathBuf::from));
+            self.libdir = libdir.map(PathBuf::from);
+            self.mandir = mandir.map(PathBuf::from);
+        }
+    }
+}
diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs
new file mode 100644
index 00000000000..4774e202bd8
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/llvm.rs
@@ -0,0 +1,284 @@
+//! This module defines the `Llvm` struct, which represents the `[llvm]` table
+//! in the `bootstrap.toml` configuration file.
+
+use serde::{Deserialize, Deserializer};
+
+use crate::core::config::toml::{Merge, ReplaceOpt, TomlConfig};
+use crate::core::config::{StringOrBool, set};
+use crate::{Config, HashMap, HashSet, PathBuf, define_config, exit};
+
+define_config! {
+    /// TOML representation of how the LLVM build is configured.
+    struct Llvm {
+        optimize: Option<bool> = "optimize",
+        thin_lto: Option<bool> = "thin-lto",
+        release_debuginfo: Option<bool> = "release-debuginfo",
+        assertions: Option<bool> = "assertions",
+        tests: Option<bool> = "tests",
+        enzyme: Option<bool> = "enzyme",
+        plugins: Option<bool> = "plugins",
+        // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache
+        ccache: Option<StringOrBool> = "ccache",
+        static_libstdcpp: Option<bool> = "static-libstdcpp",
+        libzstd: Option<bool> = "libzstd",
+        ninja: Option<bool> = "ninja",
+        targets: Option<String> = "targets",
+        experimental_targets: Option<String> = "experimental-targets",
+        link_jobs: Option<u32> = "link-jobs",
+        link_shared: Option<bool> = "link-shared",
+        version_suffix: Option<String> = "version-suffix",
+        clang_cl: Option<String> = "clang-cl",
+        cflags: Option<String> = "cflags",
+        cxxflags: Option<String> = "cxxflags",
+        ldflags: Option<String> = "ldflags",
+        use_libcxx: Option<bool> = "use-libcxx",
+        use_linker: Option<String> = "use-linker",
+        allow_old_toolchain: Option<bool> = "allow-old-toolchain",
+        offload: Option<bool> = "offload",
+        polly: Option<bool> = "polly",
+        clang: Option<bool> = "clang",
+        enable_warnings: Option<bool> = "enable-warnings",
+        download_ci_llvm: Option<StringOrBool> = "download-ci-llvm",
+        build_config: Option<HashMap<String, String>> = "build-config",
+    }
+}
+
+/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options.
+/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing.
+#[cfg(not(test))]
+pub fn check_incompatible_options_for_ci_llvm(
+    current_config_toml: TomlConfig,
+    ci_config_toml: TomlConfig,
+) -> Result<(), String> {
+    macro_rules! err {
+        ($current:expr, $expected:expr) => {
+            if let Some(current) = &$current {
+                if Some(current) != $expected.as_ref() {
+                    return Err(format!(
+                        "ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \
+                        Current value: {:?}, Expected value(s): {}{:?}",
+                        stringify!($expected).replace("_", "-"),
+                        $current,
+                        if $expected.is_some() { "None/" } else { "" },
+                        $expected,
+                    ));
+                };
+            };
+        };
+    }
+
+    macro_rules! warn {
+        ($current:expr, $expected:expr) => {
+            if let Some(current) = &$current {
+                if Some(current) != $expected.as_ref() {
+                    println!(
+                        "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \
+                        Current value: {:?}, Expected value(s): {}{:?}",
+                        stringify!($expected).replace("_", "-"),
+                        $current,
+                        if $expected.is_some() { "None/" } else { "" },
+                        $expected,
+                    );
+                };
+            };
+        };
+    }
+
+    let (Some(current_llvm_config), Some(ci_llvm_config)) =
+        (current_config_toml.llvm, ci_config_toml.llvm)
+    else {
+        return Ok(());
+    };
+
+    let Llvm {
+        optimize,
+        thin_lto,
+        release_debuginfo,
+        assertions: _,
+        tests: _,
+        plugins,
+        ccache: _,
+        static_libstdcpp: _,
+        libzstd,
+        ninja: _,
+        targets,
+        experimental_targets,
+        link_jobs: _,
+        link_shared: _,
+        version_suffix,
+        clang_cl,
+        cflags,
+        cxxflags,
+        ldflags,
+        use_libcxx,
+        use_linker,
+        allow_old_toolchain,
+        offload,
+        polly,
+        clang,
+        enable_warnings,
+        download_ci_llvm: _,
+        build_config,
+        enzyme,
+    } = ci_llvm_config;
+
+    err!(current_llvm_config.optimize, optimize);
+    err!(current_llvm_config.thin_lto, thin_lto);
+    err!(current_llvm_config.release_debuginfo, release_debuginfo);
+    err!(current_llvm_config.libzstd, libzstd);
+    err!(current_llvm_config.targets, targets);
+    err!(current_llvm_config.experimental_targets, experimental_targets);
+    err!(current_llvm_config.clang_cl, clang_cl);
+    err!(current_llvm_config.version_suffix, version_suffix);
+    err!(current_llvm_config.cflags, cflags);
+    err!(current_llvm_config.cxxflags, cxxflags);
+    err!(current_llvm_config.ldflags, ldflags);
+    err!(current_llvm_config.use_libcxx, use_libcxx);
+    err!(current_llvm_config.use_linker, use_linker);
+    err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain);
+    err!(current_llvm_config.offload, offload);
+    err!(current_llvm_config.polly, polly);
+    err!(current_llvm_config.clang, clang);
+    err!(current_llvm_config.build_config, build_config);
+    err!(current_llvm_config.plugins, plugins);
+    err!(current_llvm_config.enzyme, enzyme);
+
+    warn!(current_llvm_config.enable_warnings, enable_warnings);
+
+    Ok(())
+}
+
+impl Config {
+    pub fn apply_llvm_config(
+        &mut self,
+        toml_llvm: Option<Llvm>,
+        ccache: &mut Option<StringOrBool>,
+    ) {
+        let mut llvm_tests = None;
+        let mut llvm_enzyme = None;
+        let mut llvm_offload = None;
+        let mut llvm_plugins = None;
+
+        if let Some(llvm) = toml_llvm {
+            let Llvm {
+                optimize: optimize_toml,
+                thin_lto,
+                release_debuginfo,
+                assertions: _,
+                tests,
+                enzyme,
+                plugins,
+                ccache: llvm_ccache,
+                static_libstdcpp,
+                libzstd,
+                ninja,
+                targets,
+                experimental_targets,
+                link_jobs,
+                link_shared,
+                version_suffix,
+                clang_cl,
+                cflags,
+                cxxflags,
+                ldflags,
+                use_libcxx,
+                use_linker,
+                allow_old_toolchain,
+                offload,
+                polly,
+                clang,
+                enable_warnings,
+                download_ci_llvm,
+                build_config,
+            } = llvm;
+            if llvm_ccache.is_some() {
+                eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead.");
+            }
+
+            if ccache.is_none() {
+                *ccache = llvm_ccache;
+            }
+            set(&mut self.ninja_in_file, ninja);
+            llvm_tests = tests;
+            llvm_enzyme = enzyme;
+            llvm_offload = offload;
+            llvm_plugins = plugins;
+            set(&mut self.llvm_optimize, optimize_toml);
+            set(&mut self.llvm_thin_lto, thin_lto);
+            set(&mut self.llvm_release_debuginfo, release_debuginfo);
+            set(&mut self.llvm_static_stdcpp, static_libstdcpp);
+            set(&mut self.llvm_libzstd, libzstd);
+            if let Some(v) = link_shared {
+                self.llvm_link_shared.set(Some(v));
+            }
+            self.llvm_targets.clone_from(&targets);
+            self.llvm_experimental_targets.clone_from(&experimental_targets);
+            self.llvm_link_jobs = link_jobs;
+            self.llvm_version_suffix.clone_from(&version_suffix);
+            self.llvm_clang_cl.clone_from(&clang_cl);
+
+            self.llvm_cflags.clone_from(&cflags);
+            self.llvm_cxxflags.clone_from(&cxxflags);
+            self.llvm_ldflags.clone_from(&ldflags);
+            set(&mut self.llvm_use_libcxx, use_libcxx);
+            self.llvm_use_linker.clone_from(&use_linker);
+            self.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false);
+            self.llvm_offload = offload.unwrap_or(false);
+            self.llvm_polly = polly.unwrap_or(false);
+            self.llvm_clang = clang.unwrap_or(false);
+            self.llvm_enable_warnings = enable_warnings.unwrap_or(false);
+            self.llvm_build_config = build_config.clone().unwrap_or(Default::default());
+
+            self.llvm_from_ci = self.parse_download_ci_llvm(download_ci_llvm, self.llvm_assertions);
+
+            if self.llvm_from_ci {
+                let warn = |option: &str| {
+                    println!(
+                        "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build."
+                    );
+                    println!(
+                        "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false."
+                    );
+                };
+
+                if static_libstdcpp.is_some() {
+                    warn("static-libstdcpp");
+                }
+
+                if link_shared.is_some() {
+                    warn("link-shared");
+                }
+
+                // FIXME(#129153): instead of all the ad-hoc `download-ci-llvm` checks that follow,
+                // use the `builder-config` present in tarballs since #128822 to compare the local
+                // config to the ones used to build the LLVM artifacts on CI, and only notify users
+                // if they've chosen a different value.
+
+                if libzstd.is_some() {
+                    println!(
+                        "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \
+                        like almost all `llvm.*` options, will be ignored and set by the LLVM CI \
+                        artifacts builder config."
+                    );
+                    println!(
+                        "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false."
+                    );
+                }
+            }
+
+            if !self.llvm_from_ci && self.llvm_thin_lto && link_shared.is_none() {
+                // If we're building with ThinLTO on, by default we want to link
+                // to LLVM shared, to avoid re-doing ThinLTO (which happens in
+                // the link step) with each stage.
+                self.llvm_link_shared.set(Some(true));
+            }
+        } else {
+            self.llvm_from_ci = self.parse_download_ci_llvm(None, false);
+        }
+
+        self.llvm_tests = llvm_tests.unwrap_or(false);
+        self.llvm_enzyme = llvm_enzyme.unwrap_or(false);
+        self.llvm_offload = llvm_offload.unwrap_or(false);
+        self.llvm_plugins = llvm_plugins.unwrap_or(false);
+    }
+}
diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs
new file mode 100644
index 00000000000..ac4e249e580
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/mod.rs
@@ -0,0 +1,184 @@
+//! This module defines the structures that directly mirror the `bootstrap.toml`
+//! file's format. These types are used for `serde` deserialization.
+//!
+//! Crucially, this module also houses the core logic for loading, parsing, and merging
+//! these raw TOML configurations from various sources (the main `bootstrap.toml`,
+//! included files, profile defaults, and command-line overrides). This processed
+//! TOML data then serves as an intermediate representation, which is further
+//! transformed and applied to the final [`Config`] struct.
+
+use serde::Deserialize;
+use serde_derive::Deserialize;
+pub mod build;
+pub mod change_id;
+pub mod dist;
+pub mod gcc;
+pub mod install;
+pub mod llvm;
+pub mod rust;
+pub mod target;
+
+use build::Build;
+use change_id::{ChangeId, ChangeIdWrapper};
+use dist::Dist;
+use gcc::Gcc;
+use install::Install;
+use llvm::Llvm;
+use rust::Rust;
+use target::TomlTarget;
+
+use crate::core::config::{Merge, ReplaceOpt};
+use crate::{Config, HashMap, HashSet, Path, PathBuf, exit, fs, t};
+
+/// Structure of the `bootstrap.toml` file that configuration is read from.
+///
+/// This structure uses `Decodable` to automatically decode a TOML configuration
+/// file into this format, and then this is traversed and written into the above
+/// `Config` structure.
+#[derive(Deserialize, Default)]
+#[serde(deny_unknown_fields, rename_all = "kebab-case")]
+pub(crate) struct TomlConfig {
+    #[serde(flatten)]
+    pub(crate) change_id: ChangeIdWrapper,
+    pub(super) build: Option<Build>,
+    pub(super) install: Option<Install>,
+    pub(super) llvm: Option<Llvm>,
+    pub(super) gcc: Option<Gcc>,
+    pub(super) rust: Option<Rust>,
+    pub(super) target: Option<HashMap<String, TomlTarget>>,
+    pub(super) dist: Option<Dist>,
+    pub(super) profile: Option<String>,
+    pub(super) include: Option<Vec<PathBuf>>,
+}
+
+impl Merge for TomlConfig {
+    fn merge(
+        &mut self,
+        parent_config_path: Option<PathBuf>,
+        included_extensions: &mut HashSet<PathBuf>,
+        TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self,
+        replace: ReplaceOpt,
+    ) {
+        fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) {
+            if let Some(new) = y {
+                if let Some(original) = x {
+                    original.merge(None, &mut Default::default(), new, replace);
+                } else {
+                    *x = Some(new);
+                }
+            }
+        }
+
+        self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace);
+        self.profile.merge(None, &mut Default::default(), profile, replace);
+
+        do_merge(&mut self.build, build, replace);
+        do_merge(&mut self.install, install, replace);
+        do_merge(&mut self.llvm, llvm, replace);
+        do_merge(&mut self.gcc, gcc, replace);
+        do_merge(&mut self.rust, rust, replace);
+        do_merge(&mut self.dist, dist, replace);
+
+        match (self.target.as_mut(), target) {
+            (_, None) => {}
+            (None, Some(target)) => self.target = Some(target),
+            (Some(original_target), Some(new_target)) => {
+                for (triple, new) in new_target {
+                    if let Some(original) = original_target.get_mut(&triple) {
+                        original.merge(None, &mut Default::default(), new, replace);
+                    } else {
+                        original_target.insert(triple, new);
+                    }
+                }
+            }
+        }
+
+        let parent_dir = parent_config_path
+            .as_ref()
+            .and_then(|p| p.parent().map(ToOwned::to_owned))
+            .unwrap_or_default();
+
+        // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to
+        // keep the upper-level configuration to take precedence.
+        for include_path in include.clone().unwrap_or_default().iter().rev() {
+            let include_path = parent_dir.join(include_path);
+            let include_path = include_path.canonicalize().unwrap_or_else(|e| {
+                eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display());
+                exit!(2);
+            });
+
+            let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| {
+                eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
+                exit!(2);
+            });
+
+            assert!(
+                included_extensions.insert(include_path.clone()),
+                "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.",
+                include_path.display()
+            );
+
+            self.merge(
+                Some(include_path.clone()),
+                included_extensions,
+                included_toml,
+                // Ensures that parent configuration always takes precedence
+                // over child configurations.
+                ReplaceOpt::IgnoreDuplicate,
+            );
+
+            included_extensions.remove(&include_path);
+        }
+    }
+}
+
+/// This file is embedded in the overlay directory of the tarball sources. It is
+/// useful in scenarios where developers want to see how the tarball sources were
+/// generated.
+///
+/// We also use this file to compare the host's bootstrap.toml against the CI rustc builder
+/// configuration to detect any incompatible options.
+pub const BUILDER_CONFIG_FILENAME: &str = "builder-config";
+
+impl Config {
+    pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result<TomlConfig, toml::de::Error> {
+        if self.dry_run() {
+            return Ok(TomlConfig::default());
+        }
+
+        let builder_config_path =
+            self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME);
+        Self::get_toml(&builder_config_path)
+    }
+
+    pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
+        #[cfg(test)]
+        return Ok(TomlConfig::default());
+
+        #[cfg(not(test))]
+        Self::get_toml_inner(file)
+    }
+
+    pub(crate) fn get_toml_inner(file: &Path) -> Result<TomlConfig, toml::de::Error> {
+        let contents =
+            t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
+        // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
+        // TomlConfig and sub types to be monomorphized 5x by toml.
+        toml::from_str(&contents)
+            .and_then(|table: toml::Value| TomlConfig::deserialize(table))
+            .inspect_err(|_| {
+                if let Ok(ChangeIdWrapper { inner: Some(ChangeId::Id(id)) }) =
+                    toml::from_str::<toml::Value>(&contents)
+                        .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table))
+                {
+                    let changes = crate::find_recent_config_change_ids(id);
+                    if !changes.is_empty() {
+                        println!(
+                            "WARNING: There have been changes to x.py since you last updated:\n{}",
+                            crate::human_readable_changes(changes)
+                        );
+                    }
+                }
+            })
+    }
+}
diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs
new file mode 100644
index 00000000000..81f95f356a5
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/rust.rs
@@ -0,0 +1,664 @@
+//! This module defines the `Rust` struct, which represents the `[rust]` table
+//! in the `bootstrap.toml` configuration file.
+
+use std::str::FromStr;
+
+use serde::{Deserialize, Deserializer};
+
+use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
+use crate::core::config::toml::TomlConfig;
+use crate::core::config::{
+    DebuginfoLevel, Merge, ReplaceOpt, RustcLto, StringOrBool, set, threads_from_config,
+};
+use crate::flags::Warnings;
+use crate::{BTreeSet, Config, HashSet, PathBuf, TargetSelection, define_config, exit};
+
+define_config! {
+    /// TOML representation of how the Rust build is configured.
+    struct Rust {
+        optimize: Option<RustOptimize> = "optimize",
+        debug: Option<bool> = "debug",
+        codegen_units: Option<u32> = "codegen-units",
+        codegen_units_std: Option<u32> = "codegen-units-std",
+        rustc_debug_assertions: Option<bool> = "debug-assertions",
+        randomize_layout: Option<bool> = "randomize-layout",
+        std_debug_assertions: Option<bool> = "debug-assertions-std",
+        tools_debug_assertions: Option<bool> = "debug-assertions-tools",
+        overflow_checks: Option<bool> = "overflow-checks",
+        overflow_checks_std: Option<bool> = "overflow-checks-std",
+        debug_logging: Option<bool> = "debug-logging",
+        debuginfo_level: Option<DebuginfoLevel> = "debuginfo-level",
+        debuginfo_level_rustc: Option<DebuginfoLevel> = "debuginfo-level-rustc",
+        debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std",
+        debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools",
+        debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests",
+        backtrace: Option<bool> = "backtrace",
+        incremental: Option<bool> = "incremental",
+        default_linker: Option<String> = "default-linker",
+        channel: Option<String> = "channel",
+        // FIXME: Remove this field at Q2 2025, it has been replaced by build.description
+        description: Option<String> = "description",
+        musl_root: Option<String> = "musl-root",
+        rpath: Option<bool> = "rpath",
+        strip: Option<bool> = "strip",
+        frame_pointers: Option<bool> = "frame-pointers",
+        stack_protector: Option<String> = "stack-protector",
+        verbose_tests: Option<bool> = "verbose-tests",
+        optimize_tests: Option<bool> = "optimize-tests",
+        codegen_tests: Option<bool> = "codegen-tests",
+        omit_git_hash: Option<bool> = "omit-git-hash",
+        dist_src: Option<bool> = "dist-src",
+        save_toolstates: Option<String> = "save-toolstates",
+        codegen_backends: Option<Vec<String>> = "codegen-backends",
+        llvm_bitcode_linker: Option<bool> = "llvm-bitcode-linker",
+        lld: Option<bool> = "lld",
+        lld_mode: Option<LldMode> = "use-lld",
+        llvm_tools: Option<bool> = "llvm-tools",
+        deny_warnings: Option<bool> = "deny-warnings",
+        backtrace_on_ice: Option<bool> = "backtrace-on-ice",
+        verify_llvm_ir: Option<bool> = "verify-llvm-ir",
+        thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit",
+        remap_debuginfo: Option<bool> = "remap-debuginfo",
+        jemalloc: Option<bool> = "jemalloc",
+        test_compare_mode: Option<bool> = "test-compare-mode",
+        llvm_libunwind: Option<String> = "llvm-libunwind",
+        control_flow_guard: Option<bool> = "control-flow-guard",
+        ehcont_guard: Option<bool> = "ehcont-guard",
+        new_symbol_mangling: Option<bool> = "new-symbol-mangling",
+        profile_generate: Option<String> = "profile-generate",
+        profile_use: Option<String> = "profile-use",
+        // ignored; this is set from an env var set by bootstrap.py
+        download_rustc: Option<StringOrBool> = "download-rustc",
+        lto: Option<String> = "lto",
+        validate_mir_opts: Option<u32> = "validate-mir-opts",
+        std_features: Option<BTreeSet<String>> = "std-features",
+    }
+}
+
+/// LLD in bootstrap works like this:
+/// - Self-contained lld: use `rust-lld` from the compiler's sysroot
+/// - External: use an external `lld` binary
+///
+/// It is configured depending on the target:
+/// 1) Everything except MSVC
+/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker`
+/// - External: `-Clinker-flavor=gnu-lld-cc`
+/// 2) MSVC
+/// - Self-contained: `-Clinker=<path to rust-lld>`
+/// - External: `-Clinker=lld`
+#[derive(Copy, Clone, Default, Debug, PartialEq)]
+pub enum LldMode {
+    /// Do not use LLD
+    #[default]
+    Unused,
+    /// Use `rust-lld` from the compiler's sysroot
+    SelfContained,
+    /// Use an externally provided `lld` binary.
+    /// Note that the linker name cannot be overridden, the binary has to be named `lld` and it has
+    /// to be in $PATH.
+    External,
+}
+
+impl LldMode {
+    pub fn is_used(&self) -> bool {
+        match self {
+            LldMode::SelfContained | LldMode::External => true,
+            LldMode::Unused => false,
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for LldMode {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct LldModeVisitor;
+
+        impl serde::de::Visitor<'_> for LldModeVisitor {
+            type Value = LldMode;
+
+            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                formatter.write_str("one of true, 'self-contained' or 'external'")
+            }
+
+            fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
+            where
+                E: serde::de::Error,
+            {
+                Ok(if v { LldMode::External } else { LldMode::Unused })
+            }
+
+            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+            where
+                E: serde::de::Error,
+            {
+                match v {
+                    "external" => Ok(LldMode::External),
+                    "self-contained" => Ok(LldMode::SelfContained),
+                    _ => Err(E::custom(format!("unknown mode {v}"))),
+                }
+            }
+        }
+
+        deserializer.deserialize_any(LldModeVisitor)
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum RustOptimize {
+    String(String),
+    Int(u8),
+    Bool(bool),
+}
+
+impl Default for RustOptimize {
+    fn default() -> RustOptimize {
+        RustOptimize::Bool(false)
+    }
+}
+
+impl<'de> Deserialize<'de> for RustOptimize {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        deserializer.deserialize_any(OptimizeVisitor)
+    }
+}
+
+struct OptimizeVisitor;
+
+impl serde::de::Visitor<'_> for OptimizeVisitor {
+    type Value = RustOptimize;
+
+    fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#)
+    }
+
+    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+    where
+        E: serde::de::Error,
+    {
+        if matches!(value, "s" | "z") {
+            Ok(RustOptimize::String(value.to_string()))
+        } else {
+            Err(serde::de::Error::custom(format_optimize_error_msg(value)))
+        }
+    }
+
+    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
+    where
+        E: serde::de::Error,
+    {
+        if matches!(value, 0..=3) {
+            Ok(RustOptimize::Int(value as u8))
+        } else {
+            Err(serde::de::Error::custom(format_optimize_error_msg(value)))
+        }
+    }
+
+    fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
+    where
+        E: serde::de::Error,
+    {
+        Ok(RustOptimize::Bool(value))
+    }
+}
+
+fn format_optimize_error_msg(v: impl std::fmt::Display) -> String {
+    format!(
+        r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"#
+    )
+}
+
+impl RustOptimize {
+    pub(crate) fn is_release(&self) -> bool {
+        match &self {
+            RustOptimize::Bool(true) | RustOptimize::String(_) => true,
+            RustOptimize::Int(i) => *i > 0,
+            RustOptimize::Bool(false) => false,
+        }
+    }
+
+    pub(crate) fn get_opt_level(&self) -> Option<String> {
+        match &self {
+            RustOptimize::String(s) => Some(s.clone()),
+            RustOptimize::Int(i) => Some(i.to_string()),
+            RustOptimize::Bool(_) => None,
+        }
+    }
+}
+
+/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options.
+/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing.
+pub fn check_incompatible_options_for_ci_rustc(
+    host: TargetSelection,
+    current_config_toml: TomlConfig,
+    ci_config_toml: TomlConfig,
+) -> Result<(), String> {
+    macro_rules! err {
+        ($current:expr, $expected:expr, $config_section:expr) => {
+            if let Some(current) = &$current {
+                if Some(current) != $expected.as_ref() {
+                    return Err(format!(
+                        "ERROR: Setting `{}` is incompatible with `rust.download-rustc`. \
+                        Current value: {:?}, Expected value(s): {}{:?}",
+                        format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
+                        $current,
+                        if $expected.is_some() { "None/" } else { "" },
+                        $expected,
+                    ));
+                };
+            };
+        };
+    }
+
+    macro_rules! warn {
+        ($current:expr, $expected:expr, $config_section:expr) => {
+            if let Some(current) = &$current {
+                if Some(current) != $expected.as_ref() {
+                    println!(
+                        "WARNING: `{}` has no effect with `rust.download-rustc`. \
+                        Current value: {:?}, Expected value(s): {}{:?}",
+                        format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
+                        $current,
+                        if $expected.is_some() { "None/" } else { "" },
+                        $expected,
+                    );
+                };
+            };
+        };
+    }
+
+    let current_profiler = current_config_toml.build.as_ref().and_then(|b| b.profiler);
+    let profiler = ci_config_toml.build.as_ref().and_then(|b| b.profiler);
+    err!(current_profiler, profiler, "build");
+
+    let current_optimized_compiler_builtins =
+        current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins);
+    let optimized_compiler_builtins =
+        ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins);
+    err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build");
+
+    // We always build the in-tree compiler on cross targets, so we only care
+    // about the host target here.
+    let host_str = host.to_string();
+    if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str))
+        && current_cfg.profiler.is_some()
+    {
+        let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str));
+        let ci_cfg = ci_target_toml.ok_or(format!(
+            "Target specific config for '{host_str}' is not present for CI-rustc"
+        ))?;
+
+        let profiler = &ci_cfg.profiler;
+        err!(current_cfg.profiler, profiler, "build");
+
+        let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins;
+        err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build");
+    }
+
+    let (Some(current_rust_config), Some(ci_rust_config)) =
+        (current_config_toml.rust, ci_config_toml.rust)
+    else {
+        return Ok(());
+    };
+
+    let Rust {
+        // Following options are the CI rustc incompatible ones.
+        optimize,
+        randomize_layout,
+        debug_logging,
+        debuginfo_level_rustc,
+        llvm_tools,
+        llvm_bitcode_linker,
+        lto,
+        stack_protector,
+        strip,
+        lld_mode,
+        jemalloc,
+        rpath,
+        channel,
+        description,
+        incremental,
+        default_linker,
+        std_features,
+
+        // Rest of the options can simply be ignored.
+        debug: _,
+        codegen_units: _,
+        codegen_units_std: _,
+        rustc_debug_assertions: _,
+        std_debug_assertions: _,
+        tools_debug_assertions: _,
+        overflow_checks: _,
+        overflow_checks_std: _,
+        debuginfo_level: _,
+        debuginfo_level_std: _,
+        debuginfo_level_tools: _,
+        debuginfo_level_tests: _,
+        backtrace: _,
+        musl_root: _,
+        verbose_tests: _,
+        optimize_tests: _,
+        codegen_tests: _,
+        omit_git_hash: _,
+        dist_src: _,
+        save_toolstates: _,
+        codegen_backends: _,
+        lld: _,
+        deny_warnings: _,
+        backtrace_on_ice: _,
+        verify_llvm_ir: _,
+        thin_lto_import_instr_limit: _,
+        remap_debuginfo: _,
+        test_compare_mode: _,
+        llvm_libunwind: _,
+        control_flow_guard: _,
+        ehcont_guard: _,
+        new_symbol_mangling: _,
+        profile_generate: _,
+        profile_use: _,
+        download_rustc: _,
+        validate_mir_opts: _,
+        frame_pointers: _,
+    } = ci_rust_config;
+
+    // There are two kinds of checks for CI rustc incompatible options:
+    //    1. Checking an option that may change the compiler behaviour/output.
+    //    2. Checking an option that have no effect on the compiler behaviour/output.
+    //
+    // If the option belongs to the first category, we call `err` macro for a hard error;
+    // otherwise, we just print a warning with `warn` macro.
+
+    err!(current_rust_config.optimize, optimize, "rust");
+    err!(current_rust_config.randomize_layout, randomize_layout, "rust");
+    err!(current_rust_config.debug_logging, debug_logging, "rust");
+    err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust");
+    err!(current_rust_config.rpath, rpath, "rust");
+    err!(current_rust_config.strip, strip, "rust");
+    err!(current_rust_config.lld_mode, lld_mode, "rust");
+    err!(current_rust_config.llvm_tools, llvm_tools, "rust");
+    err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust");
+    err!(current_rust_config.jemalloc, jemalloc, "rust");
+    err!(current_rust_config.default_linker, default_linker, "rust");
+    err!(current_rust_config.stack_protector, stack_protector, "rust");
+    err!(current_rust_config.lto, lto, "rust");
+    err!(current_rust_config.std_features, std_features, "rust");
+
+    warn!(current_rust_config.channel, channel, "rust");
+    warn!(current_rust_config.description, description, "rust");
+    warn!(current_rust_config.incremental, incremental, "rust");
+
+    Ok(())
+}
+
+impl Config {
+    pub fn apply_rust_config(
+        &mut self,
+        toml_rust: Option<Rust>,
+        warnings: Warnings,
+        description: &mut Option<String>,
+    ) {
+        let mut debug = None;
+        let mut rustc_debug_assertions = None;
+        let mut std_debug_assertions = None;
+        let mut tools_debug_assertions = None;
+        let mut overflow_checks = None;
+        let mut overflow_checks_std = None;
+        let mut debug_logging = None;
+        let mut debuginfo_level = None;
+        let mut debuginfo_level_rustc = None;
+        let mut debuginfo_level_std = None;
+        let mut debuginfo_level_tools = None;
+        let mut debuginfo_level_tests = None;
+        let mut optimize = None;
+        let mut lld_enabled = None;
+        let mut std_features = None;
+
+        if let Some(rust) = toml_rust {
+            let Rust {
+                optimize: optimize_toml,
+                debug: debug_toml,
+                codegen_units,
+                codegen_units_std,
+                rustc_debug_assertions: rustc_debug_assertions_toml,
+                std_debug_assertions: std_debug_assertions_toml,
+                tools_debug_assertions: tools_debug_assertions_toml,
+                overflow_checks: overflow_checks_toml,
+                overflow_checks_std: overflow_checks_std_toml,
+                debug_logging: debug_logging_toml,
+                debuginfo_level: debuginfo_level_toml,
+                debuginfo_level_rustc: debuginfo_level_rustc_toml,
+                debuginfo_level_std: debuginfo_level_std_toml,
+                debuginfo_level_tools: debuginfo_level_tools_toml,
+                debuginfo_level_tests: debuginfo_level_tests_toml,
+                backtrace,
+                incremental,
+                randomize_layout,
+                default_linker,
+                channel: _, // already handled above
+                description: rust_description,
+                musl_root,
+                rpath,
+                verbose_tests,
+                optimize_tests,
+                codegen_tests,
+                omit_git_hash: _, // already handled above
+                dist_src,
+                save_toolstates,
+                codegen_backends,
+                lld: lld_enabled_toml,
+                llvm_tools,
+                llvm_bitcode_linker,
+                deny_warnings,
+                backtrace_on_ice,
+                verify_llvm_ir,
+                thin_lto_import_instr_limit,
+                remap_debuginfo,
+                jemalloc,
+                test_compare_mode,
+                llvm_libunwind,
+                control_flow_guard,
+                ehcont_guard,
+                new_symbol_mangling,
+                profile_generate,
+                profile_use,
+                download_rustc,
+                lto,
+                validate_mir_opts,
+                frame_pointers,
+                stack_protector,
+                strip,
+                lld_mode,
+                std_features: std_features_toml,
+            } = rust;
+
+            // FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions
+            // enabled. We should not download a CI alt rustc if we need rustc to have debug
+            // assertions (e.g. for crashes test suite). This can be changed once something like
+            // [Enable debug assertions on alt
+            // builds](https://github.com/rust-lang/rust/pull/131077) lands.
+            //
+            // Note that `rust.debug = true` currently implies `rust.debug-assertions = true`!
+            //
+            // This relies also on the fact that the global default for `download-rustc` will be
+            // `false` if it's not explicitly set.
+            let debug_assertions_requested = matches!(rustc_debug_assertions_toml, Some(true))
+                || (matches!(debug_toml, Some(true))
+                    && !matches!(rustc_debug_assertions_toml, Some(false)));
+
+            if debug_assertions_requested
+                && let Some(ref opt) = download_rustc
+                && opt.is_string_or_true()
+            {
+                eprintln!(
+                    "WARN: currently no CI rustc builds have rustc debug assertions \
+                            enabled. Please either set `rust.debug-assertions` to `false` if you \
+                            want to use download CI rustc or set `rust.download-rustc` to `false`."
+                );
+            }
+
+            self.download_rustc_commit = self.download_ci_rustc_commit(
+                download_rustc,
+                debug_assertions_requested,
+                self.llvm_assertions,
+            );
+
+            debug = debug_toml;
+            rustc_debug_assertions = rustc_debug_assertions_toml;
+            std_debug_assertions = std_debug_assertions_toml;
+            tools_debug_assertions = tools_debug_assertions_toml;
+            overflow_checks = overflow_checks_toml;
+            overflow_checks_std = overflow_checks_std_toml;
+            debug_logging = debug_logging_toml;
+            debuginfo_level = debuginfo_level_toml;
+            debuginfo_level_rustc = debuginfo_level_rustc_toml;
+            debuginfo_level_std = debuginfo_level_std_toml;
+            debuginfo_level_tools = debuginfo_level_tools_toml;
+            debuginfo_level_tests = debuginfo_level_tests_toml;
+            lld_enabled = lld_enabled_toml;
+            std_features = std_features_toml;
+
+            optimize = optimize_toml;
+            self.rust_new_symbol_mangling = new_symbol_mangling;
+            set(&mut self.rust_optimize_tests, optimize_tests);
+            set(&mut self.codegen_tests, codegen_tests);
+            set(&mut self.rust_rpath, rpath);
+            set(&mut self.rust_strip, strip);
+            set(&mut self.rust_frame_pointers, frame_pointers);
+            self.rust_stack_protector = stack_protector;
+            set(&mut self.jemalloc, jemalloc);
+            set(&mut self.test_compare_mode, test_compare_mode);
+            set(&mut self.backtrace, backtrace);
+            if rust_description.is_some() {
+                eprintln!(
+                    "Warning: rust.description is deprecated. Use build.description instead."
+                );
+            }
+            if description.is_none() {
+                *description = rust_description;
+            }
+            set(&mut self.rust_dist_src, dist_src);
+            set(&mut self.verbose_tests, verbose_tests);
+            // in the case "false" is set explicitly, do not overwrite the command line args
+            if let Some(true) = incremental {
+                self.incremental = true;
+            }
+            set(&mut self.lld_mode, lld_mode);
+            set(&mut self.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
+
+            self.rust_randomize_layout = randomize_layout.unwrap_or_default();
+            self.llvm_tools_enabled = llvm_tools.unwrap_or(true);
+
+            self.llvm_enzyme = self.channel == "dev" || self.channel == "nightly";
+            self.rustc_default_linker = default_linker;
+            self.musl_root = musl_root.map(PathBuf::from);
+            self.save_toolstates = save_toolstates.map(PathBuf::from);
+            set(
+                &mut self.deny_warnings,
+                match warnings {
+                    Warnings::Deny => Some(true),
+                    Warnings::Warn => Some(false),
+                    Warnings::Default => deny_warnings,
+                },
+            );
+            set(&mut self.backtrace_on_ice, backtrace_on_ice);
+            set(&mut self.rust_verify_llvm_ir, verify_llvm_ir);
+            self.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit;
+            set(&mut self.rust_remap_debuginfo, remap_debuginfo);
+            set(&mut self.control_flow_guard, control_flow_guard);
+            set(&mut self.ehcont_guard, ehcont_guard);
+            self.llvm_libunwind_default =
+                llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
+
+            if let Some(ref backends) = codegen_backends {
+                let available_backends = ["llvm", "cranelift", "gcc"];
+
+                self.rust_codegen_backends = backends.iter().map(|s| {
+                    if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
+                        if available_backends.contains(&backend) {
+                            panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'.");
+                        } else {
+                            println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \
+                                Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
+                                In this case, it would be referred to as '{backend}'.");
+                        }
+                    }
+
+                    s.clone()
+                }).collect();
+            }
+
+            self.rust_codegen_units = codegen_units.map(threads_from_config);
+            self.rust_codegen_units_std = codegen_units_std.map(threads_from_config);
+
+            if self.rust_profile_use.is_none() {
+                self.rust_profile_use = profile_use;
+            }
+
+            if self.rust_profile_generate.is_none() {
+                self.rust_profile_generate = profile_generate;
+            }
+
+            self.rust_lto =
+                lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default();
+            self.rust_validate_mir_opts = validate_mir_opts;
+        }
+
+        self.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
+
+        // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will
+        // build our internal lld and use it as the default linker, by setting the `rust.lld` config
+        // to true by default:
+        // - on the `x86_64-unknown-linux-gnu` target
+        // - on the `dev` and `nightly` channels
+        // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
+        //   we're also able to build the corresponding lld
+        // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
+        //   lld
+        // - otherwise, we'd be using an external llvm, and lld would not necessarily available and
+        //   thus, disabled
+        // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
+        //   when the config sets `rust.lld = false`
+        if self.build.triple == "x86_64-unknown-linux-gnu"
+            && self.hosts == [self.build]
+            && (self.channel == "dev" || self.channel == "nightly")
+        {
+            let no_llvm_config = self
+                .target_config
+                .get(&self.build)
+                .is_some_and(|target_config| target_config.llvm_config.is_none());
+            let enable_lld = self.llvm_from_ci || no_llvm_config;
+            // Prefer the config setting in case an explicit opt-out is needed.
+            self.lld_enabled = lld_enabled.unwrap_or(enable_lld);
+        } else {
+            set(&mut self.lld_enabled, lld_enabled);
+        }
+
+        let default_std_features = BTreeSet::from([String::from("panic-unwind")]);
+        self.rust_std_features = std_features.unwrap_or(default_std_features);
+
+        let default = debug == Some(true);
+        self.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default);
+        self.std_debug_assertions = std_debug_assertions.unwrap_or(self.rustc_debug_assertions);
+        self.tools_debug_assertions = tools_debug_assertions.unwrap_or(self.rustc_debug_assertions);
+        self.rust_overflow_checks = overflow_checks.unwrap_or(default);
+        self.rust_overflow_checks_std = overflow_checks_std.unwrap_or(self.rust_overflow_checks);
+
+        self.rust_debug_logging = debug_logging.unwrap_or(self.rustc_debug_assertions);
+
+        let with_defaults = |debuginfo_level_specific: Option<_>| {
+            debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
+                DebuginfoLevel::Limited
+            } else {
+                DebuginfoLevel::None
+            })
+        };
+        self.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc);
+        self.rust_debuginfo_level_std = with_defaults(debuginfo_level_std);
+        self.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
+        self.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None);
+    }
+}
diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs
new file mode 100644
index 00000000000..7f074d1b25e
--- /dev/null
+++ b/src/bootstrap/src/core/config/toml/target.rs
@@ -0,0 +1,174 @@
+//! This module defines the structures and logic for handling target-specific configuration
+//! within the `bootstrap.toml` file. This allows you to customize build settings, tools,
+//! and flags for individual compilation targets.
+//!
+//! It includes:
+//!
+//! * [`TomlTarget`]: This struct directly mirrors the `[target.<triple>]` sections in your
+//!   `bootstrap.toml`. It's used for deserializing raw TOML data for a specific target.
+//! * [`Target`]: This struct represents the processed and validated configuration for a
+//!   build target, which is is stored in the main [`Config`] structure.
+//! * [`Config::apply_target_config`]: This method processes the `TomlTarget` data and
+//!   applies it to the global [`Config`], ensuring proper path resolution, validation,
+//!   and integration with other build settings.
+
+use std::collections::HashMap;
+
+use serde::{Deserialize, Deserializer};
+
+use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
+use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool};
+use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit};
+
+define_config! {
+    /// TOML representation of how each build target is configured.
+    struct TomlTarget {
+        cc: Option<String> = "cc",
+        cxx: Option<String> = "cxx",
+        ar: Option<String> = "ar",
+        ranlib: Option<String> = "ranlib",
+        default_linker: Option<PathBuf> = "default-linker",
+        linker: Option<String> = "linker",
+        split_debuginfo: Option<String> = "split-debuginfo",
+        llvm_config: Option<String> = "llvm-config",
+        llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches",
+        llvm_filecheck: Option<String> = "llvm-filecheck",
+        llvm_libunwind: Option<String> = "llvm-libunwind",
+        sanitizers: Option<bool> = "sanitizers",
+        profiler: Option<StringOrBool> = "profiler",
+        rpath: Option<bool> = "rpath",
+        crt_static: Option<bool> = "crt-static",
+        musl_root: Option<String> = "musl-root",
+        musl_libdir: Option<String> = "musl-libdir",
+        wasi_root: Option<String> = "wasi-root",
+        qemu_rootfs: Option<String> = "qemu-rootfs",
+        no_std: Option<bool> = "no-std",
+        codegen_backends: Option<Vec<String>> = "codegen-backends",
+        runner: Option<String> = "runner",
+        optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
+        jemalloc: Option<bool> = "jemalloc",
+    }
+}
+
+/// Per-target configuration stored in the global configuration structure.
+#[derive(Debug, Default, Clone, PartialEq, Eq)]
+pub struct Target {
+    /// Some(path to llvm-config) if using an external LLVM.
+    pub llvm_config: Option<PathBuf>,
+    pub llvm_has_rust_patches: Option<bool>,
+    /// Some(path to FileCheck) if one was specified.
+    pub llvm_filecheck: Option<PathBuf>,
+    pub llvm_libunwind: Option<LlvmLibunwind>,
+    pub cc: Option<PathBuf>,
+    pub cxx: Option<PathBuf>,
+    pub ar: Option<PathBuf>,
+    pub ranlib: Option<PathBuf>,
+    pub default_linker: Option<PathBuf>,
+    pub linker: Option<PathBuf>,
+    pub split_debuginfo: Option<SplitDebuginfo>,
+    pub sanitizers: Option<bool>,
+    pub profiler: Option<StringOrBool>,
+    pub rpath: Option<bool>,
+    pub crt_static: Option<bool>,
+    pub musl_root: Option<PathBuf>,
+    pub musl_libdir: Option<PathBuf>,
+    pub wasi_root: Option<PathBuf>,
+    pub qemu_rootfs: Option<PathBuf>,
+    pub runner: Option<String>,
+    pub no_std: bool,
+    pub codegen_backends: Option<Vec<String>>,
+    pub optimized_compiler_builtins: Option<bool>,
+    pub jemalloc: Option<bool>,
+}
+
+impl Target {
+    pub fn from_triple(triple: &str) -> Self {
+        let mut target: Self = Default::default();
+        if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") {
+            target.no_std = true;
+        }
+        if triple.contains("emscripten") {
+            target.runner = Some("node".into());
+        }
+        target
+    }
+}
+
+impl Config {
+    pub fn apply_target_config(&mut self, toml_target: Option<HashMap<String, TomlTarget>>) {
+        if let Some(t) = toml_target {
+            for (triple, cfg) in t {
+                let mut target = Target::from_triple(&triple);
+
+                if let Some(ref s) = cfg.llvm_config {
+                    if self.download_rustc_commit.is_some() && triple == *self.build.triple {
+                        panic!(
+                            "setting llvm_config for the host is incompatible with download-rustc"
+                        );
+                    }
+                    target.llvm_config = Some(self.src.join(s));
+                }
+                if let Some(patches) = cfg.llvm_has_rust_patches {
+                    assert!(
+                        self.submodules == Some(false) || cfg.llvm_config.is_some(),
+                        "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided"
+                    );
+                    target.llvm_has_rust_patches = Some(patches);
+                }
+                if let Some(ref s) = cfg.llvm_filecheck {
+                    target.llvm_filecheck = Some(self.src.join(s));
+                }
+                target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| {
+                    v.parse().unwrap_or_else(|_| {
+                        panic!("failed to parse target.{triple}.llvm-libunwind")
+                    })
+                });
+                if let Some(s) = cfg.no_std {
+                    target.no_std = s;
+                }
+                target.cc = cfg.cc.map(PathBuf::from);
+                target.cxx = cfg.cxx.map(PathBuf::from);
+                target.ar = cfg.ar.map(PathBuf::from);
+                target.ranlib = cfg.ranlib.map(PathBuf::from);
+                target.linker = cfg.linker.map(PathBuf::from);
+                target.crt_static = cfg.crt_static;
+                target.musl_root = cfg.musl_root.map(PathBuf::from);
+                target.musl_libdir = cfg.musl_libdir.map(PathBuf::from);
+                target.wasi_root = cfg.wasi_root.map(PathBuf::from);
+                target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from);
+                target.runner = cfg.runner;
+                target.sanitizers = cfg.sanitizers;
+                target.profiler = cfg.profiler;
+                target.rpath = cfg.rpath;
+                target.optimized_compiler_builtins = cfg.optimized_compiler_builtins;
+                target.jemalloc = cfg.jemalloc;
+
+                if let Some(ref backends) = cfg.codegen_backends {
+                    let available_backends = ["llvm", "cranelift", "gcc"];
+
+                    target.codegen_backends = Some(backends.iter().map(|s| {
+                        if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) {
+                            if available_backends.contains(&backend) {
+                                panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'.");
+                            } else {
+                                println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
+                                    Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
+                                    In this case, it would be referred to as '{backend}'.");
+                            }
+                        }
+
+                        s.clone()
+                    }).collect());
+                }
+
+                target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| {
+                    v.parse().unwrap_or_else(|_| {
+                        panic!("invalid value for target.{triple}.split-debuginfo")
+                    })
+                });
+
+                self.target_config.insert(TargetSelection::from_user(&triple), target);
+            }
+        }
+    }
+}
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index d942334d1c3..ba00b405c61 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -727,7 +727,7 @@ download-rustc = false
         use build_helper::git::PathFreshness;
 
         use crate::core::build_steps::llvm::detect_llvm_freshness;
-        use crate::core::config::check_incompatible_options_for_ci_llvm;
+        use crate::core::config::toml::llvm::check_incompatible_options_for_ci_llvm;
 
         if !self.llvm_from_ci {
             return;
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e8cf25b1906..7658e7ad35f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -371,10 +371,9 @@ fn clean_where_predicate<'tcx>(
             bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
         },
 
-        hir::WherePredicateKind::EqPredicate(wrp) => WherePredicate::EqPredicate {
-            lhs: clean_ty(wrp.lhs_ty, cx),
-            rhs: clean_ty(wrp.rhs_ty, cx).into(),
-        },
+        // We should never actually reach this case because these predicates should've already been
+        // rejected in an earlier compiler pass. This feature isn't fully implemented (#20041).
+        hir::WherePredicateKind::EqPredicate(_) => bug!("EqPredicate"),
     })
 }
 
@@ -470,49 +469,37 @@ fn clean_projection_predicate<'tcx>(
     cx: &mut DocContext<'tcx>,
 ) -> WherePredicate {
     WherePredicate::EqPredicate {
-        lhs: clean_projection(
-            pred.map_bound(|p| {
-                // FIXME: This needs to be made resilient for `AliasTerm`s that
-                // are associated consts.
-                p.projection_term.expect_ty(cx.tcx)
-            }),
-            cx,
-            None,
-        ),
+        lhs: clean_projection(pred.map_bound(|p| p.projection_term), cx, None),
         rhs: clean_middle_term(pred.map_bound(|p| p.term), cx),
     }
 }
 
 fn clean_projection<'tcx>(
-    ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
+    proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
     cx: &mut DocContext<'tcx>,
-    def_id: Option<DefId>,
-) -> Type {
-    if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) {
-        return clean_middle_opaque_bounds(cx, ty.skip_binder().def_id, ty.skip_binder().args);
-    }
-
+    parent_def_id: Option<DefId>,
+) -> QPathData {
     let trait_ = clean_trait_ref_with_constraints(
         cx,
-        ty.map_bound(|ty| ty.trait_ref(cx.tcx)),
+        proj.map_bound(|proj| proj.trait_ref(cx.tcx)),
         ThinVec::new(),
     );
-    let self_type = clean_middle_ty(ty.map_bound(|ty| ty.self_ty()), cx, None, None);
-    let self_def_id = if let Some(def_id) = def_id {
-        cx.tcx.opt_parent(def_id).or(Some(def_id))
-    } else {
-        self_type.def_id(&cx.cache)
+    let self_type = clean_middle_ty(proj.map_bound(|proj| proj.self_ty()), cx, None, None);
+    let self_def_id = match parent_def_id {
+        Some(parent_def_id) => cx.tcx.opt_parent(parent_def_id).or(Some(parent_def_id)),
+        None => self_type.def_id(&cx.cache),
     };
-    let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
-    Type::QPath(Box::new(QPathData {
-        assoc: projection_to_path_segment(ty, cx),
-        should_show_cast,
+    let should_fully_qualify = should_fully_qualify_path(self_def_id, &trait_, &self_type);
+
+    QPathData {
+        assoc: projection_to_path_segment(proj, cx),
         self_type,
+        should_fully_qualify,
         trait_: Some(trait_),
-    }))
+    }
 }
 
-fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
+fn should_fully_qualify_path(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
     !trait_.segments.is_empty()
         && self_def_id
             .zip(Some(trait_.def_id()))
@@ -520,18 +507,17 @@ fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type
 }
 
 fn projection_to_path_segment<'tcx>(
-    ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
+    proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
     cx: &mut DocContext<'tcx>,
 ) -> PathSegment {
-    let def_id = ty.skip_binder().def_id;
-    let item = cx.tcx.associated_item(def_id);
+    let def_id = proj.skip_binder().def_id;
     let generics = cx.tcx.generics_of(def_id);
     PathSegment {
-        name: item.name(),
+        name: cx.tcx.item_name(def_id),
         args: GenericArgs::AngleBracketed {
             args: clean_middle_generic_args(
                 cx,
-                ty.map_bound(|ty| &ty.args[generics.parent_count..]),
+                proj.map_bound(|ty| &ty.args[generics.parent_count..]),
                 false,
                 def_id,
             ),
@@ -845,7 +831,7 @@ fn clean_ty_generics<'tcx>(
         .predicates
         .iter()
         .flat_map(|(pred, _)| {
-            let mut projection = None;
+            let mut proj_pred = None;
             let param_idx = {
                 let bound_p = pred.kind();
                 match bound_p.skip_binder() {
@@ -860,7 +846,7 @@ fn clean_ty_generics<'tcx>(
                     ty::ClauseKind::Projection(p)
                         if let ty::Param(param) = p.projection_term.self_ty().kind() =>
                     {
-                        projection = Some(bound_p.rebind(p));
+                        proj_pred = Some(bound_p.rebind(p));
                         Some(param.index)
                     }
                     _ => None,
@@ -874,22 +860,12 @@ fn clean_ty_generics<'tcx>(
 
                 bounds.extend(pred.get_bounds().into_iter().flatten().cloned());
 
-                if let Some(proj) = projection
-                    && let lhs = clean_projection(
-                        proj.map_bound(|p| {
-                            // FIXME: This needs to be made resilient for `AliasTerm`s that
-                            // are associated consts.
-                            p.projection_term.expect_ty(cx.tcx)
-                        }),
-                        cx,
-                        None,
-                    )
-                    && let Some((_, trait_did, name)) = lhs.projection()
-                {
+                if let Some(pred) = proj_pred {
+                    let lhs = clean_projection(pred.map_bound(|p| p.projection_term), cx, None);
                     impl_trait_proj.entry(param_idx).or_default().push((
-                        trait_did,
-                        name,
-                        proj.map_bound(|p| p.term),
+                        lhs.trait_.unwrap().def_id(),
+                        lhs.assoc,
+                        pred.map_bound(|p| p.term),
                     ));
                 }
 
@@ -1695,10 +1671,11 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             register_res(cx, trait_.res);
             let self_def_id = DefId::local(qself.hir_id.owner.def_id.local_def_index);
             let self_type = clean_ty(qself, cx);
-            let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type);
+            let should_fully_qualify =
+                should_fully_qualify_path(Some(self_def_id), &trait_, &self_type);
             Type::QPath(Box::new(QPathData {
                 assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx),
-                should_show_cast,
+                should_fully_qualify,
                 self_type,
                 trait_: Some(trait_),
             }))
@@ -1707,16 +1684,16 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             let ty = lower_ty(cx.tcx, hir_ty);
             let self_type = clean_ty(qself, cx);
 
-            let (trait_, should_show_cast) = match ty.kind() {
+            let (trait_, should_fully_qualify) = match ty.kind() {
                 ty::Alias(ty::Projection, proj) => {
                     let res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id);
                     let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx);
                     register_res(cx, trait_.res);
                     let self_def_id = res.opt_def_id();
-                    let should_show_cast =
-                        compute_should_show_cast(self_def_id, &trait_, &self_type);
+                    let should_fully_qualify =
+                        should_fully_qualify_path(self_def_id, &trait_, &self_type);
 
-                    (Some(trait_), should_show_cast)
+                    (Some(trait_), should_fully_qualify)
                 }
                 ty::Alias(ty::Inherent, _) => (None, false),
                 // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
@@ -1726,7 +1703,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
 
             Type::QPath(Box::new(QPathData {
                 assoc: clean_path_segment(segment, cx),
-                should_show_cast,
+                should_fully_qualify,
                 self_type,
                 trait_,
             }))
@@ -2145,14 +2122,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
                 .map(|pb| AssocItemConstraint {
                     assoc: projection_to_path_segment(
                         pb.map_bound(|pb| {
-                            pb
-                                // HACK(compiler-errors): Doesn't actually matter what self
-                                // type we put here, because we're only using the GAT's args.
-                                .with_self_ty(cx.tcx, cx.tcx.types.self_param)
+                            pb.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self)
                                 .projection_term
-                                // FIXME: This needs to be made resilient for `AliasTerm`s
-                                // that are associated consts.
-                                .expect_ty(cx.tcx)
                         }),
                         cx,
                     ),
@@ -2185,18 +2156,25 @@ pub(crate) fn clean_middle_ty<'tcx>(
             Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect())
         }
 
-        ty::Alias(ty::Projection, data) => {
-            clean_projection(bound_ty.rebind(data), cx, parent_def_id)
+        ty::Alias(ty::Projection, alias_ty @ ty::AliasTy { def_id, args, .. }) => {
+            if cx.tcx.is_impl_trait_in_trait(def_id) {
+                clean_middle_opaque_bounds(cx, def_id, args)
+            } else {
+                Type::QPath(Box::new(clean_projection(
+                    bound_ty.rebind(alias_ty.into()),
+                    cx,
+                    parent_def_id,
+                )))
+            }
         }
 
-        ty::Alias(ty::Inherent, alias_ty) => {
-            let def_id = alias_ty.def_id;
+        ty::Alias(ty::Inherent, alias_ty @ ty::AliasTy { def_id, .. }) => {
             let alias_ty = bound_ty.rebind(alias_ty);
             let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None, None);
 
             Type::QPath(Box::new(QPathData {
                 assoc: PathSegment {
-                    name: cx.tcx.associated_item(def_id).name(),
+                    name: cx.tcx.item_name(def_id),
                     args: GenericArgs::AngleBracketed {
                         args: clean_middle_generic_args(
                             cx,
@@ -2207,26 +2185,21 @@ pub(crate) fn clean_middle_ty<'tcx>(
                         constraints: Default::default(),
                     },
                 },
-                should_show_cast: false,
+                should_fully_qualify: false,
                 self_type,
                 trait_: None,
             }))
         }
 
-        ty::Alias(ty::Free, data) => {
+        ty::Alias(ty::Free, ty::AliasTy { def_id, args, .. }) => {
             if cx.tcx.features().lazy_type_alias() {
                 // Free type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
                 // we need to use `type_of`.
-                let path = clean_middle_path(
-                    cx,
-                    data.def_id,
-                    false,
-                    ThinVec::new(),
-                    bound_ty.rebind(data.args),
-                );
+                let path =
+                    clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args));
                 Type::Path { path }
             } else {
-                let ty = cx.tcx.type_of(data.def_id).instantiate(cx.tcx, data.args);
+                let ty = cx.tcx.type_of(def_id).instantiate(cx.tcx, args);
                 clean_middle_ty(bound_ty.rebind(ty), cx, None, None)
             }
         }
@@ -2313,18 +2286,17 @@ fn clean_middle_opaque_bounds<'tcx>(
             let bindings: ThinVec<_> = bounds
                 .iter()
                 .filter_map(|(bound, _)| {
-                    if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder()
-                        && proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder()
+                    let bound = bound.kind();
+                    if let ty::ClauseKind::Projection(proj_pred) = bound.skip_binder()
+                        && proj_pred.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder()
                     {
                         return Some(AssocItemConstraint {
                             assoc: projection_to_path_segment(
-                                // FIXME: This needs to be made resilient for `AliasTerm`s that
-                                // are associated consts.
-                                bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)),
+                                bound.rebind(proj_pred.projection_term),
                                 cx,
                             ),
                             kind: AssocItemConstraintKind::Equality {
-                                term: clean_middle_term(bound.kind().rebind(proj.term), cx),
+                                term: clean_middle_term(bound.rebind(proj_pred.term), cx),
                             },
                         });
                     }
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 41943b94d1e..40efa997868 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -46,11 +46,8 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: ThinVec<WP>) -> ThinVe
     // Look for equality predicates on associated types that can be merged into
     // general bound predicates.
     equalities.retain(|(lhs, rhs)| {
-        let Some((ty, trait_did, name)) = lhs.projection() else {
-            return true;
-        };
-        let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
-        merge_bounds(cx, bounds, trait_did, name, rhs)
+        let Some((bounds, _)) = tybounds.get_mut(&lhs.self_type) else { return true };
+        merge_bounds(cx, bounds, lhs.trait_.as_ref().unwrap().def_id(), lhs.assoc.clone(), rhs)
     });
 
     // And finally, let's reassemble everything
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 9e46d0b47e9..bde1a2e5e66 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1277,7 +1277,7 @@ impl GenericBound {
     }
 
     fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
-        let did = cx.tcx.require_lang_item(LangItem::Sized, None);
+        let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
         let empty = ty::Binder::dummy(ty::GenericArgs::empty());
         let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
@@ -1341,7 +1341,7 @@ impl PreciseCapturingArg {
 pub(crate) enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
     RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
-    EqPredicate { lhs: Type, rhs: Term },
+    EqPredicate { lhs: QPathData, rhs: Term },
 }
 
 impl WherePredicate {
@@ -1704,14 +1704,6 @@ impl Type {
         matches!(self, Type::Tuple(v) if v.is_empty())
     }
 
-    pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> {
-        if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self {
-            Some((self_type, trait_.as_ref()?.def_id(), assoc.clone()))
-        } else {
-            None
-        }
-    }
-
     /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
     ///
     /// [clean]: crate::clean
@@ -1746,7 +1738,7 @@ pub(crate) struct QPathData {
     pub assoc: PathSegment,
     pub self_type: Type,
     /// FIXME: compute this field on demand.
-    pub should_show_cast: bool,
+    pub should_fully_qualify: bool,
     pub trait_: Option<Path>,
 }
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index e9a7f4367a3..6ab1520386d 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1019,18 +1019,33 @@ fn fmt_type(
             f.write_str("impl ")?;
             print_generic_bounds(bounds, cx).fmt(f)
         }
-        &clean::QPath(box clean::QPathData {
-            ref assoc,
-            ref self_type,
-            ref trait_,
-            should_show_cast,
-        }) => {
+        clean::QPath(qpath) => qpath.print(cx).fmt(f),
+    }
+}
+
+impl clean::Type {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
+        fmt::from_fn(move |f| fmt_type(self, f, false, cx))
+    }
+}
+
+impl clean::Path {
+    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
+        fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
+    }
+}
+
+impl clean::QPathData {
+    fn print(&self, cx: &Context<'_>) -> impl Display {
+        let Self { ref assoc, ref self_type, should_fully_qualify, ref trait_ } = *self;
+
+        fmt::from_fn(move |f| {
             // FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719),
             // we need to surround them with angle brackets in some cases (e.g. `<dyn …>::P`).
 
             if f.alternate() {
                 if let Some(trait_) = trait_
-                    && should_show_cast
+                    && should_fully_qualify
                 {
                     write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
                 } else {
@@ -1038,7 +1053,7 @@ fn fmt_type(
                 }
             } else {
                 if let Some(trait_) = trait_
-                    && should_show_cast
+                    && should_fully_qualify
                 {
                     write!(f, "&lt;{} as {}&gt;::", self_type.print(cx), trait_.print(cx))?
                 } else {
@@ -1090,19 +1105,7 @@ fn fmt_type(
             }?;
 
             assoc.args.print(cx).fmt(f)
-        }
-    }
-}
-
-impl clean::Type {
-    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
-        fmt::from_fn(move |f| fmt_type(self, f, false, cx))
-    }
-}
-
-impl clean::Path {
-    pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
-        fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
+        })
     }
 }
 
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index bfcb794b89a..3ade40940bc 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -468,6 +468,9 @@ impl FromClean<clean::WherePredicate> for WherePredicate {
                     .collect(),
             },
             EqPredicate { lhs, rhs } => WherePredicate::EqPredicate {
+                // The LHS currently has type `Type` but it should be a `QualifiedPath` since it may
+                // refer to an associated const. However, `EqPredicate` shouldn't exist in the first
+                // place: <https://github.com/rust-lang/rust/141368>.
                 lhs: lhs.into_json(renderer),
                 rhs: rhs.into_json(renderer),
             },
@@ -557,12 +560,7 @@ impl FromClean<clean::Type> for Type {
                 is_mutable: mutability == ast::Mutability::Mut,
                 type_: Box::new((*type_).into_json(renderer)),
             },
-            QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath {
-                name: assoc.name.to_string(),
-                args: Box::new(assoc.args.into_json(renderer)),
-                self_type: Box::new(self_type.into_json(renderer)),
-                trait_: trait_.map(|trait_| trait_.into_json(renderer)),
-            },
+            QPath(qpath) => (*qpath).into_json(renderer),
             // FIXME(unsafe_binder): Implement rustdoc-json.
             UnsafeBinder(_) => todo!(),
         }
@@ -579,6 +577,19 @@ impl FromClean<clean::Path> for Path {
     }
 }
 
+impl FromClean<clean::QPathData> for Type {
+    fn from_clean(qpath: clean::QPathData, renderer: &JsonRenderer<'_>) -> Self {
+        let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath;
+
+        Self::QualifiedPath {
+            name: assoc.name.to_string(),
+            args: Box::new(assoc.args.into_json(renderer)),
+            self_type: Box::new(self_type.into_json(renderer)),
+            trait_: trait_.map(|trait_| trait_.into_json(renderer)),
+        }
+    }
+}
+
 impl FromClean<clean::Term> for Term {
     fn from_clean(term: clean::Term, renderer: &JsonRenderer<'_>) -> Term {
         match term {
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 9ad184450de..b839b6f5672 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -426,7 +426,7 @@ fn drain_matching(
         // Check if we should extract, but only if `idx >= start`.
         if idx > start && predicate(&alternatives[i].kind) {
             let pat = alternatives.remove(i);
-            tail_or.push(extract(pat.into_inner().kind));
+            tail_or.push(extract(pat.kind));
         } else {
             i += 1;
         }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 5b4ec12cbec..8e16f943e9f 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -439,7 +439,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
             tcx,
             ObligationCause::dummy_with_span(body.span),
             param_env,
-            TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]),
+            TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, body.span), [ty]),
         );
 
         let mut selcx = SelectionContext::new(&infcx);
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 1477f103ca5..6f5f756e144 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -358,8 +358,8 @@ pub fn create_ecx<'tcx>(
         let argvs_layout =
             ecx.layout_of(Ty::new_array(tcx, u8_ptr_type, u64::try_from(argvs.len()).unwrap()))?;
         let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
-        for (idx, arg) in argvs.into_iter().enumerate() {
-            let place = ecx.project_field(&argvs_place, idx)?;
+        for (arg, idx) in argvs.into_iter().zip(0..) {
+            let place = ecx.project_index(&argvs_place, idx)?;
             ecx.write_immediate(arg, &place)?;
         }
         ecx.mark_immutable(&argvs_place);
@@ -388,8 +388,8 @@ pub fn create_ecx<'tcx>(
                 ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?;
             ecx.machine.cmd_line = Some(cmd_place.ptr());
             // Store the UTF-16 string. We just allocated so we know the bounds are fine.
-            for (idx, &c) in cmd_utf16.iter().enumerate() {
-                let place = ecx.project_field(&cmd_place, idx)?;
+            for (&c, idx) in cmd_utf16.iter().zip(0..) {
+                let place = ecx.project_index(&cmd_place, idx)?;
                 ecx.write_scalar(Scalar::from_u16(c), &place)?;
             }
             ecx.mark_immutable(&cmd_place);
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 20ea239b7e5..4edecc864dd 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -326,7 +326,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, Option<P>> {
         let this = self.eval_context_ref();
         let adt = base.layout().ty.ty_adt_def().unwrap();
-        for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() {
+        for (idx, field) in adt.non_enum_variant().fields.iter_enumerated() {
             if field.name.as_str() == name {
                 return interp_ok(Some(this.project_field(base, idx)?));
             }
@@ -376,6 +376,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
         for (idx, &val) in values.iter().enumerate() {
+            let idx = FieldIdx::from_usize(idx);
             let field = this.project_field(dest, idx)?;
             this.write_int(val, &field)?;
         }
@@ -763,10 +764,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// `EINVAL` in this case.
     fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option<Duration>> {
         let this = self.eval_context_mut();
-        let seconds_place = this.project_field(tp, 0)?;
+        let seconds_place = this.project_field(tp, FieldIdx::ZERO)?;
         let seconds_scalar = this.read_scalar(&seconds_place)?;
         let seconds = seconds_scalar.to_target_isize(this)?;
-        let nanoseconds_place = this.project_field(tp, 1)?;
+        let nanoseconds_place = this.project_field(tp, FieldIdx::ONE)?;
         let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?;
         let nanoseconds = nanoseconds_scalar.to_target_isize(this)?;
 
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index ab11553df63..8606735c913 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,4 +1,4 @@
-use rustc_abi::{CanonAbi, Size};
+use rustc_abi::{CanonAbi, FieldIdx, Size};
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol, hygiene};
@@ -159,23 +159,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             1 => {
                 this.write_scalar(
                     Scalar::from_target_usize(name.len().to_u64(), this),
-                    &this.project_field(dest, 0)?,
+                    &this.project_field(dest, FieldIdx::from_u32(0))?,
                 )?;
                 this.write_scalar(
                     Scalar::from_target_usize(filename.len().to_u64(), this),
-                    &this.project_field(dest, 1)?,
+                    &this.project_field(dest, FieldIdx::from_u32(1))?,
                 )?;
             }
             _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags),
         }
 
-        this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, 2)?)?;
-        this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, 3)?)?;
+        this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, FieldIdx::from_u32(2))?)?;
+        this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, FieldIdx::from_u32(3))?)?;
 
         // Support a 4-field struct for now - this is deprecated
         // and slated for removal.
         if num_fields == 5 {
-            this.write_pointer(fn_ptr, &this.project_field(dest, 4)?)?;
+            this.write_pointer(fn_ptr, &this.project_field(dest, FieldIdx::from_u32(4))?)?;
         }
 
         interp_ok(())
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 549d859a6e1..a6bce830149 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -247,7 +247,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             _ => {
                 // Call the lang item associated with this message.
-                let fn_item = this.tcx.require_lang_item(msg.panic_function(), None);
+                let fn_item = this.tcx.require_lang_item(msg.panic_function(), this.tcx.span);
                 let instance = ty::Instance::mono(this.tcx.tcx, fn_item);
                 this.call_function(
                     instance,
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index aebb5757aec..62ac7ee3806 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -2,8 +2,9 @@ use std::ffi::{OsStr, OsString};
 use std::io::ErrorKind;
 use std::{env, mem};
 
-use rustc_abi::Size;
+use rustc_abi::{FieldIdx, Size};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_index::IndexVec;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
 
@@ -118,7 +119,7 @@ fn alloc_env_var<'tcx>(
 /// Allocates an `environ` block with the given list of pointers.
 fn alloc_environ_block<'tcx>(
     ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
-    mut vars: Vec<Pointer>,
+    mut vars: IndexVec<FieldIdx, Pointer>,
 ) -> InterpResult<'tcx, Pointer> {
     // Add trailing null.
     vars.push(Pointer::null());
@@ -129,7 +130,7 @@ fn alloc_environ_block<'tcx>(
         u64::try_from(vars.len()).unwrap(),
     ))?;
     let vars_place = ecx.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
-    for (idx, var) in vars.into_iter().enumerate() {
+    for (idx, var) in vars.into_iter_enumerated() {
         let place = ecx.project_field(&vars_place, idx)?;
         ecx.write_pointer(var, &place)?;
     }
diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs
index 54650f35b2c..f4e7d9e58f9 100644
--- a/src/tools/miri/src/shims/unix/freebsd/sync.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs
@@ -2,6 +2,8 @@
 
 use core::time::Duration;
 
+use rustc_abi::FieldIdx;
+
 use crate::concurrency::sync::FutexRef;
 use crate::*;
 
@@ -214,18 +216,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Only flag allowed is UMTX_ABSTIME.
         let abs_time = this.eval_libc_u32("UMTX_ABSTIME");
 
-        let timespec_place = this.project_field(ut, 0)?;
+        let timespec_place = this.project_field(ut, FieldIdx::from_u32(0))?;
         // Inner `timespec` must still be valid.
         let duration = match this.read_timespec(&timespec_place)? {
             Some(dur) => dur,
             None => return interp_ok(None),
         };
 
-        let flags_place = this.project_field(ut, 1)?;
+        let flags_place = this.project_field(ut, FieldIdx::from_u32(1))?;
         let flags = this.read_scalar(&flags_place)?.to_u32()?;
         let abs_time_flag = flags == abs_time;
 
-        let clock_id_place = this.project_field(ut, 2)?;
+        let clock_id_place = this.project_field(ut, FieldIdx::from_u32(2))?;
         let clock_id = this.read_scalar(&clock_id_place)?.to_i32()?;
         let timeout_clock = this.translate_umtx_time_clock_id(clock_id)?;
 
diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
index b489595b4cd..f971fb10b19 100644
--- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
@@ -4,6 +4,8 @@ use std::io;
 use std::rc::{Rc, Weak};
 use std::time::Duration;
 
+use rustc_abi::FieldIdx;
+
 use crate::concurrency::VClock;
 use crate::shims::files::{
     DynFileDescriptionRef, FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef,
@@ -284,8 +286,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if op == epoll_ctl_add || op == epoll_ctl_mod {
             // Read event bitmask and data from epoll_event passed by caller.
-            let mut events = this.read_scalar(&this.project_field(&event, 0)?)?.to_u32()?;
-            let data = this.read_scalar(&this.project_field(&event, 1)?)?.to_u64()?;
+            let mut events = this.read_scalar(&this.project_field(&event, FieldIdx::ZERO)?)?.to_u32()?;
+            let data = this.read_scalar(&this.project_field(&event, FieldIdx::ONE)?)?.to_u64()?;
 
             // Unset the flag we support to discover if any unsupported flags are used.
             let mut flags = events;
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 7dee8ddd23c..1e82f521249 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1,4 +1,4 @@
-use rustc_abi::{CanonAbi, Size};
+use rustc_abi::{CanonAbi, FieldIdx, Size};
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::Single;
 use rustc_middle::ty::Ty;
@@ -54,8 +54,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
 
                 let (sum, cb_out) = carrying_add(this, cb_in, a, b, op)?;
-                this.write_scalar(cb_out, &this.project_field(dest, 0)?)?;
-                this.write_immediate(*sum, &this.project_field(dest, 1)?)?;
+                this.write_scalar(cb_out, &this.project_field(dest, FieldIdx::ZERO)?)?;
+                this.write_immediate(*sum, &this.project_field(dest, FieldIdx::ONE)?)?;
             }
 
             // Used to implement the `_addcarryx_u{32, 64}` functions. They are semantically identical with the `_addcarry_u{32, 64}` functions,
diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs
index bc5a6d3e704..44c8123517c 100644
--- a/src/tools/rustfmt/src/modules.rs
+++ b/src/tools/rustfmt/src/modules.rs
@@ -174,7 +174,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> {
     ) -> Result<(), ModuleResolutionError> {
         for item in items {
             if is_cfg_if(&item) {
-                self.visit_cfg_if(Cow::Owned(item.into_inner()))?;
+                self.visit_cfg_if(Cow::Owned(*item))?;
                 continue;
             }
 
diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
index 30b83373c17..26bf6c5326f 100644
--- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs
+++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
@@ -62,7 +62,7 @@ fn parse_cfg_if_inner<'a>(
 
         while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof {
             let item = match parser.parse_item(ForceCollect::No) {
-                Ok(Some(item_ptr)) => item_ptr.into_inner(),
+                Ok(Some(item_ptr)) => *item_ptr,
                 Ok(None) => continue,
                 Err(err) => {
                     err.cancel();
diff --git a/tests/rustdoc/inline_cross/assoc-const-equality.rs b/tests/rustdoc/inline_cross/assoc-const-equality.rs
index ec5c2f748ef..36ab027ef71 100644
--- a/tests/rustdoc/inline_cross/assoc-const-equality.rs
+++ b/tests/rustdoc/inline_cross/assoc-const-equality.rs
@@ -1,6 +1,5 @@
 //@ aux-crate:assoc_const_equality=assoc-const-equality.rs
 //@ edition:2021
-//@ ignore-test (FIXME: #125092)
 
 #![crate_name = "user"]
 
diff --git a/tests/ui/cleanup-rvalue-scopes-cf.rs b/tests/ui/borrowck/rvalue-borrow-scope-error.rs
index e3cecb1bffe..5bf96e800d3 100644
--- a/tests/ui/cleanup-rvalue-scopes-cf.rs
+++ b/tests/ui/borrowck/rvalue-borrow-scope-error.rs
@@ -1,15 +1,19 @@
-// Test that the borrow checker prevents pointers to temporaries
-// with statement lifetimes from escaping.
+//! Test that the borrow checker prevents pointers to temporaries
+//! with statement lifetimes from escaping.
 
 use std::ops::Drop;
 
 static mut FLAGS: u64 = 0;
 
-struct StackBox<T> { f: T }
-struct AddFlags { bits: u64 }
+struct StackBox<T> {
+    f: T,
+}
+struct AddFlags {
+    bits: u64,
+}
 
 fn AddFlags(bits: u64) -> AddFlags {
-    AddFlags { bits: bits }
+    AddFlags { bits }
 }
 
 fn arg(x: &AddFlags) -> &AddFlags {
diff --git a/tests/ui/cleanup-rvalue-scopes-cf.stderr b/tests/ui/borrowck/rvalue-borrow-scope-error.stderr
index 425cd75141c..bedcfce4541 100644
--- a/tests/ui/cleanup-rvalue-scopes-cf.stderr
+++ b/tests/ui/borrowck/rvalue-borrow-scope-error.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/cleanup-rvalue-scopes-cf.rs:26:19
+  --> $DIR/rvalue-borrow-scope-error.rs:30:19
    |
 LL |     let x1 = arg(&AddFlags(1));
    |                   ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -16,7 +16,7 @@ LL ~     let x1 = arg(&binding);
    |
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/cleanup-rvalue-scopes-cf.rs:27:14
+  --> $DIR/rvalue-borrow-scope-error.rs:31:14
    |
 LL |     let x2 = AddFlags(1).get();
    |              ^^^^^^^^^^^      - temporary value is freed at the end of this statement
@@ -33,7 +33,7 @@ LL ~     let x2 = binding.get();
    |
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/cleanup-rvalue-scopes-cf.rs:28:21
+  --> $DIR/rvalue-borrow-scope-error.rs:32:21
    |
 LL |     let x3 = &*arg(&AddFlags(1));
    |                     ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -50,7 +50,7 @@ LL ~     let x3 = &*arg(&binding);
    |
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/cleanup-rvalue-scopes-cf.rs:29:24
+  --> $DIR/rvalue-borrow-scope-error.rs:33:24
    |
 LL |     let ref x4 = *arg(&AddFlags(1));
    |                        ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -67,7 +67,7 @@ LL ~     let ref x4 = *arg(&binding);
    |
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/cleanup-rvalue-scopes-cf.rs:30:24
+  --> $DIR/rvalue-borrow-scope-error.rs:34:24
    |
 LL |     let &ref x5 = arg(&AddFlags(1));
    |                        ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -84,7 +84,7 @@ LL ~     let &ref x5 = arg(&binding);
    |
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/cleanup-rvalue-scopes-cf.rs:31:14
+  --> $DIR/rvalue-borrow-scope-error.rs:35:14
    |
 LL |     let x6 = AddFlags(1).get();
    |              ^^^^^^^^^^^      - temporary value is freed at the end of this statement
@@ -101,7 +101,7 @@ LL ~     let x6 = binding.get();
    |
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/cleanup-rvalue-scopes-cf.rs:32:44
+  --> $DIR/rvalue-borrow-scope-error.rs:36:44
    |
 LL |     let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() };
    |                                            ^^^^^^^^^^^        - temporary value is freed at the end of this statement
diff --git a/tests/ui/cleanup-rvalue-scopes.rs b/tests/ui/cleanup-rvalue-scopes.rs
deleted file mode 100644
index 09ceda065b9..00000000000
--- a/tests/ui/cleanup-rvalue-scopes.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-//@ run-pass
-#![allow(unused_braces)]
-#![allow(non_snake_case)]
-#![allow(unused_variables)]
-// Test that destructors for rvalue temporaries run either at end of
-// statement or end of block, as appropriate given the temporary
-// lifetime rules.
-
-#![feature(box_patterns)]
-
-static mut FLAGS: u64 = 0;
-
-struct Box<T> { f: T }
-struct AddFlags { bits: u64 }
-
-fn AddFlags(bits: u64) -> AddFlags {
-    AddFlags { bits: bits }
-}
-
-fn arg(exp: u64, _x: &AddFlags) {
-    check_flags(exp);
-}
-
-fn pass<T>(v: T) -> T {
-    v
-}
-
-fn check_flags(exp: u64) {
-    unsafe {
-        let x = FLAGS;
-        FLAGS = 0;
-        println!("flags {}, expected {}", x, exp);
-        assert_eq!(x, exp);
-    }
-}
-
-impl AddFlags {
-    fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
-        check_flags(exp);
-        self
-    }
-
-    fn bits(&self) -> u64 {
-        self.bits
-    }
-}
-
-impl Drop for AddFlags {
-    fn drop(&mut self) {
-        unsafe {
-            FLAGS = FLAGS + self.bits;
-        }
-    }
-}
-
-macro_rules! end_of_block {
-    ($pat:pat, $expr:expr) => (
-        {
-            println!("end_of_block({})", stringify!({let $pat = $expr;}));
-
-            {
-                // Destructor here does not run until exit from the block.
-                let $pat = $expr;
-                check_flags(0);
-            }
-            check_flags(1);
-        }
-    )
-}
-
-macro_rules! end_of_stmt {
-    ($pat:pat, $expr:expr) => (
-        {
-            println!("end_of_stmt({})", stringify!($expr));
-
-            {
-                // Destructor here run after `let` statement
-                // terminates.
-                let $pat = $expr;
-                check_flags(1);
-            }
-
-            check_flags(0);
-        }
-    )
-}
-
-pub fn main() {
-
-    // In all these cases, we trip over the rules designed to cover
-    // the case where we are taking addr of rvalue and storing that
-    // addr into a stack slot, either via `let ref` or via a `&` in
-    // the initializer.
-
-    end_of_block!(_x, AddFlags(1));
-    end_of_block!(_x, &AddFlags(1));
-    end_of_block!(_x, & &AddFlags(1));
-    end_of_block!(_x, Box { f: AddFlags(1) });
-    end_of_block!(_x, Box { f: &AddFlags(1) });
-    end_of_block!(_x, Box { f: &AddFlags(1) });
-    end_of_block!(_x, pass(AddFlags(1)));
-    end_of_block!(ref _x, AddFlags(1));
-    end_of_block!(AddFlags { bits: ref _x }, AddFlags(1));
-    end_of_block!(&AddFlags { bits }, &AddFlags(1));
-    end_of_block!((_, ref _y), (AddFlags(1), 22));
-    end_of_block!(box ref _x, std::boxed::Box::new(AddFlags(1)));
-    end_of_block!(box _x, std::boxed::Box::new(AddFlags(1)));
-    end_of_block!(_, { { check_flags(0); &AddFlags(1) } });
-    end_of_block!(_, &((Box { f: AddFlags(1) }).f));
-    end_of_block!(_, &(([AddFlags(1)])[0]));
-
-    // LHS does not create a ref binding, so temporary lives as long
-    // as statement, and we do not move the AddFlags out:
-    end_of_stmt!(_, AddFlags(1));
-    end_of_stmt!((_, _), (AddFlags(1), 22));
-
-    // `&` operator appears inside an arg to a function,
-    // so it is not prolonged:
-    end_of_stmt!(ref _x, arg(0, &AddFlags(1)));
-
-    // autoref occurs inside receiver, so temp lifetime is not
-    // prolonged:
-    end_of_stmt!(ref _x, AddFlags(1).check_flags(0).bits());
-
-    // No reference is created on LHS, thus RHS is moved into
-    // a temporary that lives just as long as the statement.
-    end_of_stmt!(AddFlags { bits }, AddFlags(1));
-}
diff --git a/tests/ui/close-over-big-then-small-data.rs b/tests/ui/close-over-big-then-small-data.rs
deleted file mode 100644
index d3cb1db8886..00000000000
--- a/tests/ui/close-over-big-then-small-data.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-//@ run-pass
-
-#![allow(dead_code)]
-// If we use GEPi rather than GEP_tup_like when
-// storing closure data (as we used to do), the u64 would
-// overwrite the u16.
-
-struct Pair<A,B> {
-    a: A, b: B
-}
-
-struct Invoker<A> {
-    a: A,
-    b: u16,
-}
-
-trait Invokable<A> {
-    fn f(&self) -> (A, u16);
-}
-
-impl<A:Clone> Invokable<A> for Invoker<A> {
-    fn f(&self) -> (A, u16) {
-        (self.a.clone(), self.b)
-    }
-}
-
-fn f<A:Clone + 'static>(a: A, b: u16) -> Box<dyn Invokable<A>+'static> {
-    Box::new(Invoker {
-        a: a,
-        b: b,
-    }) as Box<dyn Invokable<A>+'static>
-}
-
-pub fn main() {
-    let (a, b) = f(22_u64, 44u16).f();
-    println!("a={} b={}", a, b);
-    assert_eq!(a, 22u64);
-    assert_eq!(b, 44u16);
-}
diff --git a/tests/ui/const-generics/early/invalid-const-arguments.stderr b/tests/ui/const-generics/early/invalid-const-arguments.stderr
index 86b4d006454..3a9868836ec 100644
--- a/tests/ui/const-generics/early/invalid-const-arguments.stderr
+++ b/tests/ui/const-generics/early/invalid-const-arguments.stderr
@@ -51,9 +51,13 @@ error[E0747]: type provided when a constant was expected
   --> $DIR/invalid-const-arguments.rs:10:19
    |
 LL | impl<N> Foo for B<N> {}
-   |      -            ^
-   |      |
-   |      help: consider changing this type parameter to a const parameter: `const N: u8`
+   |                   ^
+   |
+help: consider changing this type parameter to a const parameter
+   |
+LL - impl<N> Foo for B<N> {}
+LL + impl<const N: u8> Foo for B<N> {}
+   |
 
 error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/invalid-const-arguments.rs:14:32
diff --git a/tests/ui/const-generics/kind_mismatch.stderr b/tests/ui/const-generics/kind_mismatch.stderr
index 1487b189619..12a2ab141a6 100644
--- a/tests/ui/const-generics/kind_mismatch.stderr
+++ b/tests/ui/const-generics/kind_mismatch.stderr
@@ -2,17 +2,25 @@ error[E0747]: type provided when a constant was expected
   --> $DIR/kind_mismatch.rs:11:38
    |
 LL | impl<K> ContainsKey<K> for KeyHolder<K> {}
-   |      -                               ^
-   |      |
-   |      help: consider changing this type parameter to a const parameter: `const K: u8`
+   |                                      ^
+   |
+help: consider changing this type parameter to a const parameter
+   |
+LL - impl<K> ContainsKey<K> for KeyHolder<K> {}
+LL + impl<const K: u8> ContainsKey<K> for KeyHolder<K> {}
+   |
 
 error[E0747]: type provided when a constant was expected
   --> $DIR/kind_mismatch.rs:11:21
    |
 LL | impl<K> ContainsKey<K> for KeyHolder<K> {}
-   |      -              ^
-   |      |
-   |      help: consider changing this type parameter to a const parameter: `const K: u8`
+   |                     ^
+   |
+help: consider changing this type parameter to a const parameter
+   |
+LL - impl<K> ContainsKey<K> for KeyHolder<K> {}
+LL + impl<const K: u8> ContainsKey<K> for KeyHolder<K> {}
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/command-line-diagnostics.rs b/tests/ui/diagnostic-width/command-line-error-format-human.rs
index 8a6cf5b8e32..a2cfbbcbeb1 100644
--- a/tests/ui/command-line-diagnostics.rs
+++ b/tests/ui/diagnostic-width/command-line-error-format-human.rs
@@ -1,4 +1,5 @@
-// This test checks the output format without the intermediate json representation
+//! This test checks the output format without the intermediate json representation
+
 //@ compile-flags: --error-format=human
 
 pub fn main() {
diff --git a/tests/ui/command-line-diagnostics.stderr b/tests/ui/diagnostic-width/command-line-error-format-human.stderr
index 6d33fb4172f..b4b78239f88 100644
--- a/tests/ui/command-line-diagnostics.stderr
+++ b/tests/ui/diagnostic-width/command-line-error-format-human.stderr
@@ -1,5 +1,5 @@
 error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/command-line-diagnostics.rs:6:5
+  --> $DIR/command-line-error-format-human.rs:7:5
    |
 LL |     let x = 42;
    |         - first assignment to `x`
diff --git a/tests/ui/drop/issue-2735-2.rs b/tests/ui/drop/issue-2735-2.rs
index 66025956e08..43fbafe7a0e 100644
--- a/tests/ui/drop/issue-2735-2.rs
+++ b/tests/ui/drop/issue-2735-2.rs
@@ -1,27 +1,24 @@
 //@ run-pass
-#![allow(non_camel_case_types)]
 
 use std::cell::Cell;
 
 // This test should behave exactly like issue-2735-3
-struct defer<'a> {
+struct Defer<'a> {
     b: &'a Cell<bool>,
 }
 
-impl<'a> Drop for defer<'a> {
+impl<'a> Drop for Defer<'a> {
     fn drop(&mut self) {
         self.b.set(true);
     }
 }
 
-fn defer(b: &Cell<bool>) -> defer<'_> {
-    defer {
-        b: b
-    }
+fn defer(b: &Cell<bool>) -> Defer<'_> {
+    Defer { b }
 }
 
 pub fn main() {
     let dtor_ran = &Cell::new(false);
-    let _  = defer(dtor_ran);
+    let _ = defer(dtor_ran);
     assert!(dtor_ran.get());
 }
diff --git a/tests/ui/drop/issue-2735-3.rs b/tests/ui/drop/issue-2735-3.rs
index c9535168653..cc28f96d2b0 100644
--- a/tests/ui/drop/issue-2735-3.rs
+++ b/tests/ui/drop/issue-2735-3.rs
@@ -1,23 +1,20 @@
 //@ run-pass
-#![allow(non_camel_case_types)]
 
 use std::cell::Cell;
 
 // This test should behave exactly like issue-2735-2
-struct defer<'a> {
+struct Defer<'a> {
     b: &'a Cell<bool>,
 }
 
-impl<'a> Drop for defer<'a> {
+impl<'a> Drop for Defer<'a> {
     fn drop(&mut self) {
         self.b.set(true);
     }
 }
 
-fn defer(b: &Cell<bool>) -> defer<'_> {
-    defer {
-        b: b
-    }
+fn defer(b: &Cell<bool>) -> Defer<'_> {
+    Defer { b }
 }
 
 pub fn main() {
diff --git a/tests/ui/drop/issue-2735.rs b/tests/ui/drop/issue-2735.rs
index cd7e0b8f461..838b9da109b 100644
--- a/tests/ui/drop/issue-2735.rs
+++ b/tests/ui/drop/issue-2735.rs
@@ -1,15 +1,13 @@
 //@ run-pass
 #![allow(dead_code)]
-#![allow(non_camel_case_types)]
 
-
-trait hax {
-    fn dummy(&self) { }
+trait Hax {
+    fn dummy(&self) {}
 }
-impl<A> hax for A { }
+impl<A> Hax for A {}
 
-fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
-    Box::new(x) as Box<dyn hax+'static>
+fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn Hax + 'static> {
+    Box::new(x) as Box<dyn Hax + 'static>
 }
 
 fn deadcode() {
diff --git a/tests/ui/drop/issue-979.rs b/tests/ui/drop/issue-979.rs
index 70052708be6..abbcc71de18 100644
--- a/tests/ui/drop/issue-979.rs
+++ b/tests/ui/drop/issue-979.rs
@@ -1,22 +1,19 @@
 //@ run-pass
-#![allow(non_camel_case_types)]
 
 use std::cell::Cell;
 
-struct r<'a> {
+struct R<'a> {
     b: &'a Cell<isize>,
 }
 
-impl<'a> Drop for r<'a> {
+impl<'a> Drop for R<'a> {
     fn drop(&mut self) {
         self.b.set(self.b.get() + 1);
     }
 }
 
-fn r(b: &Cell<isize>) -> r<'_> {
-    r {
-        b: b
-    }
+fn r(b: &Cell<isize>) -> R<'_> {
+    R { b }
 }
 
 pub fn main() {
diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs
index 7676b5557d2..25a4ff283ba 100644
--- a/tests/ui/lang-items/lang-item-generic-requirements.rs
+++ b/tests/ui/lang-items/lang-item-generic-requirements.rs
@@ -48,6 +48,7 @@ fn ice() {
 
     // Use index
     let arr = [0; 5];
+    //~^ ERROR requires `copy` lang_item
     let _ = arr[2];
     //~^ ERROR cannot index into a value of type `[{integer}; 5]`
 
@@ -61,5 +62,3 @@ fn ice() {
 
 // use `start`
 fn main() {}
-
-//~? ERROR requires `copy` lang_item
diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr
index 409fa05d637..c82bdb00fd1 100644
--- a/tests/ui/lang-items/lang-item-generic-requirements.stderr
+++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr
@@ -77,13 +77,13 @@ LL |     r + a;
    |     {integer}
 
 error[E0608]: cannot index into a value of type `[{integer}; 5]`
-  --> $DIR/lang-item-generic-requirements.rs:51:16
+  --> $DIR/lang-item-generic-requirements.rs:52:16
    |
 LL |     let _ = arr[2];
    |                ^^^
 
 error[E0308]: mismatched types
-  --> $DIR/lang-item-generic-requirements.rs:58:17
+  --> $DIR/lang-item-generic-requirements.rs:59:17
    |
 LL |     let _: () = Foo;
    |            --   ^^^ expected `()`, found `Foo`
@@ -91,6 +91,10 @@ LL |     let _: () = Foo;
    |            expected due to this
 
 error: requires `copy` lang_item
+  --> $DIR/lang-item-generic-requirements.rs:50:16
+   |
+LL |     let arr = [0; 5];
+   |                ^
 
 error: aborting due to 12 previous errors
 
diff --git a/tests/ui/cleanup-shortcircuit.rs b/tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs
index 40a5dfa94e3..dba899585c4 100644
--- a/tests/ui/cleanup-shortcircuit.rs
+++ b/tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs
@@ -1,10 +1,9 @@
-//@ run-pass
-// Test that cleanups for the RHS of shortcircuiting operators work.
+//! Test that cleanups for the RHS of shortcircuiting operators work.
 
+//@ run-pass
 
 #![allow(deref_nullptr)]
 
-
 use std::env;
 
 pub fn main() {
@@ -18,6 +17,8 @@ pub fn main() {
 
     if args.len() >= 2 && args[1] == "signal" {
         // Raise a segfault.
-        unsafe { *std::ptr::null_mut::<isize>() = 0; }
+        unsafe {
+            *std::ptr::null_mut::<isize>() = 0;
+        }
     }
 }
diff --git a/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs b/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs
new file mode 100644
index 00000000000..9e7b84bfccf
--- /dev/null
+++ b/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs
@@ -0,0 +1,104 @@
+//! Test that destructors for temporaries run either at end of
+//! statement or end of block as appropriate.
+
+//@ run-pass
+
+#![feature(box_patterns)]
+
+static mut FLAGS: u64 = 0;
+
+struct Box<T> {
+    f: T,
+}
+
+struct AddFlags {
+    bits: u64,
+}
+
+fn add_flags(bits: u64) -> AddFlags {
+    AddFlags { bits }
+}
+
+fn arg(expected: u64, _x: &AddFlags) {
+    check_flags(expected);
+}
+
+fn pass<T>(v: T) -> T {
+    v
+}
+
+fn check_flags(expected: u64) {
+    unsafe {
+        let actual = FLAGS;
+        FLAGS = 0;
+        assert_eq!(actual, expected, "flags {}, expected {}", actual, expected);
+    }
+}
+
+impl AddFlags {
+    fn check_flags(&self, expected: u64) -> &AddFlags {
+        check_flags(expected);
+        self
+    }
+
+    fn bits(&self) -> u64 {
+        self.bits
+    }
+}
+
+impl Drop for AddFlags {
+    fn drop(&mut self) {
+        unsafe {
+            FLAGS += self.bits;
+        }
+    }
+}
+
+macro_rules! end_of_block {
+    ($pat:pat, $expr:expr) => {{
+        {
+            let $pat = $expr;
+            check_flags(0);
+        }
+        check_flags(1);
+    }};
+}
+
+macro_rules! end_of_stmt {
+    ($pat:pat, $expr:expr) => {{
+        {
+            let $pat = $expr;
+            check_flags(1);
+        }
+        check_flags(0);
+    }};
+}
+
+fn main() {
+    end_of_block!(_x, add_flags(1));
+    end_of_block!(_x, &add_flags(1));
+    end_of_block!(_x, &&add_flags(1));
+    end_of_block!(_x, Box { f: add_flags(1) });
+    end_of_block!(_x, Box { f: &add_flags(1) });
+    end_of_block!(_x, pass(add_flags(1)));
+    end_of_block!(ref _x, add_flags(1));
+    end_of_block!(AddFlags { bits: ref _x }, add_flags(1));
+    end_of_block!(&AddFlags { bits: _ }, &add_flags(1));
+    end_of_block!((_, ref _y), (add_flags(1), 22));
+    end_of_block!(box ref _x, std::boxed::Box::new(add_flags(1)));
+    end_of_block!(box _x, std::boxed::Box::new(add_flags(1)));
+    end_of_block!(_, {
+        {
+            check_flags(0);
+            &add_flags(1)
+        }
+    });
+    end_of_block!(_, &((Box { f: add_flags(1) }).f));
+    end_of_block!(_, &(([add_flags(1)])[0]));
+
+    end_of_stmt!(_, add_flags(1));
+    end_of_stmt!((_, _), (add_flags(1), 22));
+    end_of_stmt!(ref _x, arg(0, &add_flags(1)));
+    end_of_stmt!(ref _x, add_flags(1).check_flags(0).bits());
+    end_of_stmt!(AddFlags { bits: _ }, add_flags(1));
+}
diff --git a/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs b/tests/ui/panics/rvalue-cleanup-during-box-panic.rs
index 4c59df24e4b..84c5d85d7e0 100644
--- a/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
+++ b/tests/ui/panics/rvalue-cleanup-during-box-panic.rs
@@ -25,16 +25,20 @@
 use std::thread;
 
 enum Conzabble {
-    Bickwick(Foo)
+    Bickwick(Foo),
 }
 
-struct Foo { field: Box<usize> }
+struct Foo {
+    field: Box<usize>,
+}
 
 fn do_it(x: &[usize]) -> Foo {
     panic!()
 }
 
-fn get_bar(x: usize) -> Vec<usize> { vec![x * 2] }
+fn get_bar(x: usize) -> Vec<usize> {
+    vec![x * 2]
+}
 
 pub fn fails() {
     let x = 2;
diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
index 57cba790b55..7d39c82d22f 100644
--- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
+++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
@@ -1,13 +1,10 @@
-error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
+error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`
   --> $DIR/coherence-fulfill-overflow.rs:12:1
    |
 LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
    | ------------------------------------- first implementation here
 LL | impl<T: ?Sized + TwoW> Trait for T {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
-   |
-   = note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>: TwoW`
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`)
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>`
 
 error: aborting due to 1 previous error
 
diff --git a/triagebot.toml b/triagebot.toml
index db263a3768f..15c56f8861f 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1210,6 +1210,7 @@ compiler = [
     "@fee1-dead",
     "@fmease",
     "@jieyouxu",
+    "@jdonszelmann",
     "@lcnr",
     "@Nadrieril",
     "@nnethercote",