about summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/Cargo.lock4
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/bootstrap.py2
-rw-r--r--src/bootstrap/defaults/bootstrap.library.toml14
-rw-r--r--src/bootstrap/mk/Makefile.in25
-rw-r--r--src/bootstrap/src/bin/rustc.rs57
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs76
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs28
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs225
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs40
-rw-r--r--src/bootstrap/src/core/build_steps/format.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs108
-rw-r--r--src/bootstrap/src/core/build_steps/perf.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs19
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs28
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs60
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs33
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs99
-rw-r--r--src/bootstrap/src/core/builder/mod.rs8
-rw-r--r--src/bootstrap/src/core/builder/tests.rs21
-rw-r--r--src/bootstrap/src/core/config/config.rs2187
-rw-r--r--src/bootstrap/src/core/config/flags.rs8
-rw-r--r--src/bootstrap/src/core/config/mod.rs409
-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.rs12
-rw-r--r--src/bootstrap/src/core/sanity.rs2
-rw-r--r--src/bootstrap/src/lib.rs169
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs34
-rw-r--r--src/bootstrap/src/utils/cc_detect/tests.rs113
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs18
-rw-r--r--src/bootstrap/src/utils/exec.rs3
-rw-r--r--src/bootstrap/src/utils/shared_helpers.rs11
43 files changed, 2939 insertions, 2598 deletions
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index d10d2d9bf8c..0c8e6633560 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -89,9 +89,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.2.17"
+version = "1.2.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
+checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
 dependencies = [
  "shlex",
 ]
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 9652d18f1a6..b12b3dfc7b2 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -32,7 +32,7 @@ test = false
 # Most of the time updating these dependencies requires modifications to the
 # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565);
 # otherwise, some targets will fail. That's why these dependencies are explicitly pinned.
-cc = "=1.2.17"
+cc = "=1.2.23"
 cmake = "=0.1.54"
 
 build_helper = { path = "../build_helper" }
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 42ad14a81d0..d8c6be78247 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -394,6 +394,7 @@ def default_build_triple(verbose):
         "i686": "i686",
         "i686-AT386": "i686",
         "i786": "i686",
+        "loongarch32": "loongarch32",
         "loongarch64": "loongarch64",
         "m68k": "m68k",
         "csky": "csky",
@@ -1118,7 +1119,6 @@ class RustBuild(object):
         if "RUSTFLAGS_BOOTSTRAP" in env:
             env["RUSTFLAGS"] += " " + env["RUSTFLAGS_BOOTSTRAP"]
 
-        env["PATH"] = os.path.join(self.bin_root(), "bin") + os.pathsep + env["PATH"]
         if not os.path.isfile(self.cargo()):
             raise Exception("no cargo executable found at `{}`".format(self.cargo()))
         args = [
diff --git a/src/bootstrap/defaults/bootstrap.library.toml b/src/bootstrap/defaults/bootstrap.library.toml
index b43796d6f20..895e50b9a20 100644
--- a/src/bootstrap/defaults/bootstrap.library.toml
+++ b/src/bootstrap/defaults/bootstrap.library.toml
@@ -1,17 +1,19 @@
 # These defaults are meant for contributors to the standard library and documentation.
 [build]
-# When building the standard library, you almost never want to build the compiler itself.
-build-stage = 0
-test-stage = 0
-bench-stage = 0
+bench-stage = 1
+build-stage = 1
+check-stage = 1
+test-stage = 1
 
 [rust]
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
 # Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
 lto = "off"
-# Download rustc by default for library profile if compiler-affecting
-# directories are not modified. For CI this is disabled.
+# When building the standard library, you almost never want to build the compiler itself.
+#
+# If compiler-affecting directories are not modified, use precompiled rustc to speed up
+# library development by skipping compiler builds.
 download-rustc = "if-unchanged"
 
 [llvm]
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 08a288170fa..82c05092dfa 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -51,16 +51,18 @@ check-aux:
 	$(Q)$(BOOTSTRAP) test --stage 2 \
 		src/tools/cargo \
 		src/tools/cargotest \
-		src/etc/test-float-parse \
+		src/tools/test-float-parse \
 		$(BOOTSTRAP_ARGS)
 	# Run standard library tests in Miri.
-	$(Q)$(BOOTSTRAP) miri --stage 2 \
+	$(Q)MIRIFLAGS="-Zmiri-strict-provenance" \
+		$(BOOTSTRAP) miri --stage 2 \
 		library/coretests \
 		library/alloctests \
 		library/alloc \
 		$(BOOTSTRAP_ARGS) \
 		--no-doc
-	# Some doctests use file system operations to demonstrate dealing with `Result`.
+	# Some doctests use file system operations to demonstrate dealing with `Result`,
+	# so we have to run them with isolation disabled.
 	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
 		$(BOOTSTRAP) miri --stage 2 \
 		library/coretests \
@@ -70,22 +72,19 @@ check-aux:
 		--doc
 	# In `std` we cannot test everything, so we skip some modules.
 	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
-		$(BOOTSTRAP) miri --stage 2 library/std \
-		$(BOOTSTRAP_ARGS) \
-		--no-doc -- \
-		--skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal::
-	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" \
-		$(BOOTSTRAP) miri --stage 2 library/std \
+		$(BOOTSTRAP) miri --stage 2 \
+		library/std \
 		$(BOOTSTRAP_ARGS) \
-		--doc -- \
+		-- \
 		--skip fs:: --skip net:: --skip process:: --skip sys::fd:: --skip sys::pal::
 	# Also test some very target-specific modules on other targets
 	# (making sure to cover an i686 target as well).
 	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \
-		$(BOOTSTRAP) miri --stage 2 library/std \
-		$(BOOTSTRAP_ARGS) \
+		$(BOOTSTRAP) miri --stage 2 \
+		library/std \
 		--target aarch64-apple-darwin,i686-pc-windows-msvc \
-		--no-doc -- \
+		$(BOOTSTRAP_ARGS) \
+		-- \
 		time:: sync:: thread:: env::
 dist:
 	$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 374884d8a9a..0671a8467e8 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -120,14 +120,12 @@ fn main() {
     };
     cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
 
-    if let Some(crate_name) = crate_name {
-        if let Some(target) = env::var_os("RUSTC_TIME") {
-            if target == "all"
-                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
-            {
-                cmd.arg("-Ztime-passes");
-            }
-        }
+    if let Some(crate_name) = crate_name
+        && let Some(target) = env::var_os("RUSTC_TIME")
+        && (target == "all"
+            || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name))
+    {
+        cmd.arg("-Ztime-passes");
     }
 
     // Print backtrace in case of ICE
@@ -242,10 +240,10 @@ fn main() {
         }
     }
 
-    if env::var_os("RUSTC_BOLT_LINK_FLAGS").is_some() {
-        if let Some("rustc_driver") = crate_name {
-            cmd.arg("-Clink-args=-Wl,-q");
-        }
+    if env::var_os("RUSTC_BOLT_LINK_FLAGS").is_some()
+        && let Some("rustc_driver") = crate_name
+    {
+        cmd.arg("-Clink-args=-Wl,-q");
     }
 
     let is_test = args.iter().any(|a| a == "--test");
@@ -282,25 +280,24 @@ fn main() {
         (child, status)
     };
 
-    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
-        || env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some()
+    if (env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some()
+        || env::var_os("RUSTC_PRINT_STEP_RUSAGE").is_some())
+        && let Some(crate_name) = crate_name
     {
-        if let Some(crate_name) = crate_name {
-            let dur = start.elapsed();
-            // If the user requested resource usage data, then
-            // include that in addition to the timing output.
-            let rusage_data =
-                env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data(child));
-            eprintln!(
-                "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
-                crate_name,
-                is_test,
-                dur.as_secs(),
-                dur.subsec_millis(),
-                if rusage_data.is_some() { " " } else { "" },
-                rusage_data.unwrap_or_default(),
-            );
-        }
+        let dur = start.elapsed();
+        // If the user requested resource usage data, then
+        // include that in addition to the timing output.
+        let rusage_data =
+            env::var_os("RUSTC_PRINT_STEP_RUSAGE").and_then(|_| format_rusage_data(child));
+        eprintln!(
+            "[RUSTC-TIMING] {} test:{} {}.{:03}{}{}",
+            crate_name,
+            is_test,
+            dur.as_secs(),
+            dur.subsec_millis(),
+            if rusage_data.is_some() { " " } else { "" },
+            rusage_data.unwrap_or_default(),
+        );
     }
 
     if status.success() {
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index fa848c492b4..911a51b0e16 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -1,5 +1,6 @@
 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
 
+use crate::core::build_steps::compile;
 use crate::core::build_steps::compile::{
     add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
 };
@@ -27,11 +28,16 @@ pub struct Std {
     /// passing `Builder::kind` to cargo invocations would run clippy on the entire compiler and library,
     /// which is not useful if we only want to lint a few crates with specific rules.
     override_build_kind: Option<Kind>,
+    /// Never use this from outside calls. It is intended for internal use only within `check::Std::make_run`
+    /// and `check::Std::run`.
+    custom_stage: Option<u32>,
 }
 
 impl Std {
+    const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"];
+
     pub fn new(target: TargetSelection) -> Self {
-        Self { target, crates: vec![], override_build_kind: None }
+        Self { target, crates: vec![], override_build_kind: None, custom_stage: None }
     }
 
     pub fn build_kind(mut self, kind: Option<Kind>) -> Self {
@@ -45,22 +51,64 @@ impl Step for Std {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.crate_or_deps("sysroot")
-            .crate_or_deps("coretests")
-            .crate_or_deps("alloctests")
-            .path("library")
+        let mut run = run;
+        for c in Std::CRATE_OR_DEPS {
+            run = run.crate_or_deps(c);
+        }
+
+        run.path("library")
     }
 
     fn make_run(run: RunConfig<'_>) {
         let crates = std_crates_for_run_make(&run);
-        run.builder.ensure(Std { target: run.target, crates, override_build_kind: None });
+
+        let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 1 {
+            run.builder.top_stage
+        } else {
+            1
+        };
+
+        run.builder.ensure(Std {
+            target: run.target,
+            crates,
+            override_build_kind: None,
+            custom_stage: Some(stage),
+        });
     }
 
     fn run(self, builder: &Builder<'_>) {
+        if !builder.download_rustc() && builder.config.skip_std_check_if_no_download_rustc {
+            eprintln!(
+                "WARNING: `--skip-std-check-if-no-download-rustc` flag was passed and `rust.download-rustc` is not available. Skipping."
+            );
+            return;
+        }
+
         builder.require_submodule("library/stdarch", None);
 
+        let stage = self.custom_stage.unwrap_or(builder.top_stage);
+
         let target = self.target;
-        let compiler = builder.compiler(builder.top_stage, builder.config.build);
+        let compiler = builder.compiler(stage, builder.config.build);
+
+        if stage == 0 {
+            let mut is_explicitly_called =
+                builder.paths.iter().any(|p| p.starts_with("library") || p.starts_with("std"));
+
+            if !is_explicitly_called {
+                for c in Std::CRATE_OR_DEPS {
+                    is_explicitly_called = builder.paths.iter().any(|p| p.starts_with(c));
+                }
+            }
+
+            if is_explicitly_called {
+                eprintln!("WARNING: stage 0 std is precompiled and does nothing during `x check`.");
+            }
+
+            // Reuse the stage0 libstd
+            builder.ensure(compile::Std::new(compiler, target));
+            return;
+        }
 
         let mut cargo = builder::Cargo::new(
             builder,
@@ -84,6 +132,7 @@ impl Step for Std {
         let _guard = builder.msg_check(
             format_args!("library artifacts{}", crate_description(&self.crates)),
             target,
+            Some(stage),
         );
 
         let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check");
@@ -136,7 +185,7 @@ impl Step for Std {
         }
 
         let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check-test");
-        let _guard = builder.msg_check("library test/bench/example targets", target);
+        let _guard = builder.msg_check("library test/bench/example targets", target, Some(stage));
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
     }
 }
@@ -237,6 +286,7 @@ impl Step for Rustc {
         let _guard = builder.msg_check(
             format_args!("compiler artifacts{}", crate_description(&self.crates)),
             target,
+            None,
         );
 
         let stamp = build_stamp::librustc_stamp(builder, compiler, target).with_prefix("check");
@@ -297,7 +347,7 @@ impl Step for CodegenBackend {
             .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
         rustc_cargo_env(builder, &mut cargo, target, compiler.stage);
 
-        let _guard = builder.msg_check(backend, target);
+        let _guard = builder.msg_check(backend, target, None);
 
         let stamp = build_stamp::codegen_backend_stamp(builder, compiler, target, backend)
             .with_prefix("check");
@@ -364,7 +414,7 @@ impl Step for RustAnalyzer {
         let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target))
             .with_prefix("rust-analyzer-check");
 
-        let _guard = builder.msg_check("rust-analyzer artifacts", target);
+        let _guard = builder.msg_check("rust-analyzer artifacts", target, None);
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
     }
 }
@@ -427,7 +477,7 @@ impl Step for Compiletest {
         let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target))
             .with_prefix("compiletest-check");
 
-        let _guard = builder.msg_check("compiletest artifacts", self.target);
+        let _guard = builder.msg_check("compiletest artifacts", self.target, None);
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
     }
 }
@@ -505,7 +555,7 @@ fn run_tool_check_step(
     let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target))
         .with_prefix(&format!("{}-check", step_type_name.to_lowercase()));
 
-    let _guard = builder.msg_check(format!("{display_name} artifacts"), target);
+    let _guard = builder.msg_check(format!("{display_name} artifacts"), target, None);
     run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
 }
 
@@ -519,7 +569,7 @@ tool_check_step!(Miri { path: "src/tools/miri" });
 tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri" });
 tool_check_step!(Rustfmt { path: "src/tools/rustfmt" });
 tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools" });
-tool_check_step!(TestFloatParse { path: "src/etc/test-float-parse" });
+tool_check_step!(TestFloatParse { path: "src/tools/test-float-parse" });
 tool_check_step!(FeaturesStatusDump { path: "src/tools/features-status-dump" });
 
 tool_check_step!(Bootstrap { path: "src/bootstrap", default: false });
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index 07fd51919d4..0652c08ff49 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -207,16 +207,18 @@ impl Step for Rustc {
         let compiler = builder.compiler(builder.top_stage, builder.config.build);
         let target = self.target;
 
-        if compiler.stage != 0 {
-            // If we're not in stage 0, then we won't have a std from the beta
-            // compiler around. That means we need to make sure there's one in
-            // the sysroot for the compiler to find. Otherwise, we're going to
-            // fail when building crates that need to generate code (e.g., build
-            // scripts and their dependencies).
-            builder.ensure(compile::Std::new(compiler, compiler.host));
-            builder.ensure(compile::Std::new(compiler, target));
-        } else {
-            builder.ensure(check::Std::new(target).build_kind(Some(Kind::Check)));
+        if !builder.download_rustc() {
+            if compiler.stage != 0 {
+                // If we're not in stage 0, then we won't have a std from the beta
+                // compiler around. That means we need to make sure there's one in
+                // the sysroot for the compiler to find. Otherwise, we're going to
+                // fail when building crates that need to generate code (e.g., build
+                // scripts and their dependencies).
+                builder.ensure(compile::Std::new(compiler, compiler.host));
+                builder.ensure(compile::Std::new(compiler, target));
+            } else {
+                builder.ensure(check::Std::new(target).build_kind(Some(Kind::Check)));
+            }
         }
 
         let mut cargo = builder::Cargo::new(
@@ -286,7 +288,9 @@ macro_rules! lint_any {
                 let compiler = builder.compiler(builder.top_stage, builder.config.build);
                 let target = self.target;
 
-                builder.ensure(check::Rustc::new(target, builder).build_kind(Some(Kind::Check)));
+                if !builder.download_rustc() {
+                    builder.ensure(check::Rustc::new(target, builder).build_kind(Some(Kind::Check)));
+                };
 
                 let cargo = prepare_tool_cargo(
                     builder,
@@ -351,7 +355,7 @@ lint_any!(
     Rustfmt, "src/tools/rustfmt", "rustfmt";
     RustInstaller, "src/tools/rust-installer", "rust-installer";
     Tidy, "src/tools/tidy", "tidy";
-    TestFloatParse, "src/etc/test-float-parse", "test-float-parse";
+    TestFloatParse, "src/tools/test-float-parse", "test-float-parse";
 );
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 67daf81ee54..5ecce31fe15 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -147,14 +147,27 @@ impl Step for Std {
     )]
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
-        let compiler = self.compiler;
+
+        // We already have std ready to be used for stage 0.
+        if self.compiler.stage == 0 {
+            let compiler = self.compiler;
+            builder.ensure(StdLink::from_std(self, compiler));
+
+            return;
+        }
+
+        let compiler = if builder.download_rustc() && self.force_recompile {
+            // When there are changes in the library tree with CI-rustc, we want to build
+            // the stageN library and that requires using stageN-1 compiler.
+            builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.build)
+        } else {
+            self.compiler
+        };
 
         // When using `download-rustc`, we already have artifacts for the host available. Don't
         // recompile them.
-        if builder.download_rustc() && builder.config.is_host_target(target)
-            // NOTE: the beta compiler may generate different artifacts than the downloaded compiler, so
-            // its artifacts can't be reused.
-            && compiler.stage != 0
+        if builder.download_rustc()
+            && builder.config.is_host_target(target)
             && !self.force_recompile
         {
             let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
@@ -189,7 +202,13 @@ impl Step for Std {
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         trace!(?compiler_to_use);
 
-        if compiler_to_use != compiler {
+        if compiler_to_use != compiler
+            // Never uplift std unless we have compiled stage 1; if stage 1 is compiled,
+            // uplift it from there.
+            //
+            // FIXME: improve `fn compiler_for` to avoid adding stage condition here.
+            && compiler.stage > 1
+        {
             trace!(?compiler_to_use, ?compiler, "compiler != compiler_to_use, uplifting library");
 
             builder.ensure(Std::new(compiler_to_use, target));
@@ -222,27 +241,6 @@ impl Step for Std {
 
         target_deps.extend(self.copy_extra_objects(builder, &compiler, target));
 
-        // The LLD wrappers and `rust-lld` are self-contained linking components that can be
-        // necessary to link the stdlib on some targets. We'll also need to copy these binaries to
-        // the `stage0-sysroot` to ensure the linker is found when bootstrapping on such a target.
-        if compiler.stage == 0 && builder.config.is_host_target(compiler.host) {
-            trace!(
-                "(build == host) copying linking components to `stage0-sysroot` for bootstrapping"
-            );
-            // We want to copy the host `bin` folder within the `rustlib` folder in the sysroot.
-            let src_sysroot_bin = builder
-                .rustc_snapshot_sysroot()
-                .join("lib")
-                .join("rustlib")
-                .join(compiler.host)
-                .join("bin");
-            if src_sysroot_bin.exists() {
-                let target_sysroot_bin = builder.sysroot_target_bindir(compiler, target);
-                t!(fs::create_dir_all(&target_sysroot_bin));
-                builder.cp_link_r(&src_sysroot_bin, &target_sysroot_bin);
-            }
-        }
-
         // We build a sysroot for mir-opt tests using the same trick that Miri does: A check build
         // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the
         // fact that this is a check build integrates nicely with run_cargo.
@@ -628,18 +626,18 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
 
         // Help the libc crate compile by assisting it in finding various
         // sysroot native libraries.
-        if target.contains("musl") {
-            if let Some(p) = builder.musl_libdir(target) {
-                let root = format!("native={}", p.to_str().unwrap());
-                cargo.rustflag("-L").rustflag(&root);
-            }
+        if target.contains("musl")
+            && let Some(p) = builder.musl_libdir(target)
+        {
+            let root = format!("native={}", p.to_str().unwrap());
+            cargo.rustflag("-L").rustflag(&root);
         }
 
-        if target.contains("-wasi") {
-            if let Some(dir) = builder.wasi_libdir(target) {
-                let root = format!("native={}", dir.to_str().unwrap());
-                cargo.rustflag("-L").rustflag(&root);
-            }
+        if target.contains("-wasi")
+            && let Some(dir) = builder.wasi_libdir(target)
+        {
+            let root = format!("native={}", dir.to_str().unwrap());
+            cargo.rustflag("-L").rustflag(&root);
         }
     }
 
@@ -670,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(),);
@@ -737,7 +736,7 @@ impl Step for StdLink {
         let target = self.target;
 
         // NOTE: intentionally does *not* check `target == builder.build` to avoid having to add the same check in `test::Crate`.
-        let (libdir, hostdir) = if self.force_recompile && builder.download_rustc() {
+        let (libdir, hostdir) = if !self.force_recompile && builder.download_rustc() {
             // NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too
             let lib = builder.sysroot_libdir_relative(self.compiler);
             let sysroot = builder.ensure(crate::core::build_steps::compile::Sysroot {
@@ -753,23 +752,16 @@ impl Step for StdLink {
             (libdir, hostdir)
         };
 
-        add_to_sysroot(
-            builder,
-            &libdir,
-            &hostdir,
-            &build_stamp::libstd_stamp(builder, compiler, target),
-        );
+        let is_downloaded_beta_stage0 = builder
+            .build
+            .config
+            .initial_rustc
+            .starts_with(builder.out.join(compiler.host).join("stage0/bin"));
 
         // Special case for stage0, to make `rustup toolchain link` and `x dist --stage 0`
         // work for stage0-sysroot. We only do this if the stage0 compiler comes from beta,
         // and is not set to a custom path.
-        if compiler.stage == 0
-            && builder
-                .build
-                .config
-                .initial_rustc
-                .starts_with(builder.out.join(compiler.host).join("stage0/bin"))
-        {
+        if compiler.stage == 0 && is_downloaded_beta_stage0 {
             // Copy bin files from stage0/bin to stage0-sysroot/bin
             let sysroot = builder.out.join(compiler.host).join("stage0-sysroot");
 
@@ -779,21 +771,9 @@ impl Step for StdLink {
             t!(fs::create_dir_all(&sysroot_bin_dir));
             builder.cp_link_r(&stage0_bin_dir, &sysroot_bin_dir);
 
-            // Copy all files from stage0/lib to stage0-sysroot/lib
             let stage0_lib_dir = builder.out.join(host).join("stage0/lib");
-            if let Ok(files) = fs::read_dir(stage0_lib_dir) {
-                for file in files {
-                    let file = t!(file);
-                    let path = file.path();
-                    if path.is_file() {
-                        builder.copy_link(
-                            &path,
-                            &sysroot.join("lib").join(path.file_name().unwrap()),
-                            FileType::Regular,
-                        );
-                    }
-                }
-            }
+            t!(fs::create_dir_all(sysroot.join("lib")));
+            builder.cp_link_r(&stage0_lib_dir, &sysroot.join("lib"));
 
             // Copy codegen-backends from stage0
             let sysroot_codegen_backends = builder.sysroot_codegen_backends(compiler);
@@ -807,6 +787,30 @@ impl Step for StdLink {
             if stage0_codegen_backends.exists() {
                 builder.cp_link_r(&stage0_codegen_backends, &sysroot_codegen_backends);
             }
+        } else if compiler.stage == 0 {
+            let sysroot = builder.out.join(compiler.host.triple).join("stage0-sysroot");
+
+            if builder.local_rebuild {
+                // On local rebuilds this path might be a symlink to the project root,
+                // which can be read-only (e.g., on CI). So remove it before copying
+                // the stage0 lib.
+                let _ = fs::remove_dir_all(sysroot.join("lib/rustlib/src/rust"));
+            }
+
+            builder.cp_link_r(&builder.initial_sysroot.join("lib"), &sysroot.join("lib"));
+        } else {
+            if builder.download_rustc() {
+                // Ensure there are no CI-rustc std artifacts.
+                let _ = fs::remove_dir_all(&libdir);
+                let _ = fs::remove_dir_all(&hostdir);
+            }
+
+            add_to_sysroot(
+                builder,
+                &libdir,
+                &hostdir,
+                &build_stamp::libstd_stamp(builder, compiler, target),
+            );
         }
     }
 }
@@ -1029,7 +1033,7 @@ impl Step for Rustc {
         let compiler = self.compiler;
         let target = self.target;
 
-        // NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
+        // NOTE: the ABI of the stage0 compiler is different from the ABI of the downloaded compiler,
         // so its artifacts can't be reused.
         if builder.download_rustc() && compiler.stage != 0 {
             trace!(stage = compiler.stage, "`download_rustc` requested");
@@ -1275,6 +1279,17 @@ pub fn rustc_cargo(
         ));
     }
 
+    // The stage0 compiler changes infrequently and does not directly depend on code
+    // in the current working directory. Therefore, caching it with sccache should be
+    // useful.
+    // This is only performed for non-incremental builds, as ccache cannot deal with these.
+    if let Some(ref ccache) = builder.config.ccache
+        && compiler.stage == 0
+        && !builder.config.incremental
+    {
+        cargo.env("RUSTC_WRAPPER", ccache);
+    }
+
     rustc_cargo_env(builder, cargo, target, compiler.stage);
 }
 
@@ -1388,12 +1403,13 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
     // found. This is to avoid the linker errors about undefined references to
     // `__llvm_profile_instrument_memop` when linking `rustc_driver`.
     let mut llvm_linker_flags = String::new();
-    if builder.config.llvm_profile_generate && target.is_msvc() {
-        if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl {
-            // Add clang's runtime library directory to the search path
-            let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
-            llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
-        }
+    if builder.config.llvm_profile_generate
+        && target.is_msvc()
+        && let Some(ref clang_cl_path) = builder.config.llvm_clang_cl
+    {
+        // Add clang's runtime library directory to the search path
+        let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
+        llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
     }
 
     // The config can also specify its own llvm linker flags.
@@ -1409,7 +1425,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
         cargo.env("LLVM_LINKER_FLAGS", llvm_linker_flags);
     }
 
-    // Building with a static libstdc++ is only supported on linux right now,
+    // Building with a static libstdc++ is only supported on Linux and windows-gnu* right now,
     // not for MSVC or macOS
     if builder.config.llvm_static_stdcpp
         && !target.contains("freebsd")
@@ -1417,12 +1433,14 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
         && !target.contains("apple")
         && !target.contains("solaris")
     {
+        let libstdcxx_name =
+            if target.contains("windows-gnullvm") { "libc++.a" } else { "libstdc++.a" };
         let file = compiler_file(
             builder,
             &builder.cxx(target).unwrap(),
             target,
             CLang::Cxx,
-            "libstdc++.a",
+            libstdcxx_name,
         );
         cargo.env("LLVM_STATIC_STDCPP", file);
     }
@@ -1783,9 +1801,9 @@ impl Step for Sysroot {
         t!(fs::create_dir_all(&sysroot));
 
         // In some cases(see https://github.com/rust-lang/rust/issues/109314), when the stage0
-        // compiler relies on more recent version of LLVM than the beta compiler, it may not
+        // compiler relies on more recent version of LLVM than the stage0 compiler, it may not
         // be able to locate the correct LLVM in the sysroot. This situation typically occurs
-        // when we upgrade LLVM version while the beta compiler continues to use an older version.
+        // when we upgrade LLVM version while the stage0 compiler continues to use an older version.
         //
         // Make sure to add the correct version of LLVM into the stage0 sysroot.
         if compiler.stage == 0 {
@@ -1861,23 +1879,27 @@ impl Step for Sysroot {
         // so that any tools relying on `rust-src` also work for local builds,
         // and also for translating the virtual `/rustc/$hash` back to the real
         // directory (for running tests with `rust.remap-debuginfo = true`).
-        let sysroot_lib_rustlib_src = sysroot.join("lib/rustlib/src");
-        t!(fs::create_dir_all(&sysroot_lib_rustlib_src));
-        let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust");
-        if let Err(e) = symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust) {
-            eprintln!(
-                "ERROR: creating symbolic link `{}` to `{}` failed with {}",
-                sysroot_lib_rustlib_src_rust.display(),
-                builder.src.display(),
-                e,
-            );
-            if builder.config.rust_remap_debuginfo {
+        if compiler.stage != 0 {
+            let sysroot_lib_rustlib_src = sysroot.join("lib/rustlib/src");
+            t!(fs::create_dir_all(&sysroot_lib_rustlib_src));
+            let sysroot_lib_rustlib_src_rust = sysroot_lib_rustlib_src.join("rust");
+            if let Err(e) =
+                symlink_dir(&builder.config, &builder.src, &sysroot_lib_rustlib_src_rust)
+            {
                 eprintln!(
-                    "ERROR: some `tests/ui` tests will fail when lacking `{}`",
+                    "ERROR: creating symbolic link `{}` to `{}` failed with {}",
                     sysroot_lib_rustlib_src_rust.display(),
+                    builder.src.display(),
+                    e,
                 );
+                if builder.config.rust_remap_debuginfo {
+                    eprintln!(
+                        "ERROR: some `tests/ui` tests will fail when lacking `{}`",
+                        sysroot_lib_rustlib_src_rust.display(),
+                    );
+                }
+                build_helper::exit!(1);
             }
-            build_helper::exit!(1);
         }
 
         // rustc-src component is already part of CI rustc's sysroot
@@ -1984,17 +2006,20 @@ impl Step for Assemble {
                     trace!("installing `{tool}`");
                     let tool_exe = exe(tool, target_compiler.host);
                     let src_path = llvm_bin_dir.join(&tool_exe);
-                    // When using `download-ci-llvm`, some of the tools
-                    // may not exist, so skip trying to copy them.
-                    if src_path.exists() {
-                        // There is a chance that these tools are being installed from an external LLVM.
-                        // Use `Builder::resolve_symlink_and_copy` instead of `Builder::copy_link` to ensure
-                        // we are copying the original file not the symlinked path, which causes issues for
-                        // tarball distribution.
-                        //
-                        // See https://github.com/rust-lang/rust/issues/135554.
-                        builder.resolve_symlink_and_copy(&src_path, &libdir_bin.join(&tool_exe));
+
+                    // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
+                    if !src_path.exists() && builder.config.llvm_from_ci {
+                        eprintln!("{} does not exist; skipping copy", src_path.display());
+                        continue;
                     }
+
+                    // There is a chance that these tools are being installed from an external LLVM.
+                    // Use `Builder::resolve_symlink_and_copy` instead of `Builder::copy_link` to ensure
+                    // we are copying the original file not the symlinked path, which causes issues for
+                    // tarball distribution.
+                    //
+                    // See https://github.com/rust-lang/rust/issues/135554.
+                    builder.resolve_symlink_and_copy(&src_path, &libdir_bin.join(&tool_exe));
                 }
             }
         }
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index aa2c7509c2a..587fca80374 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -776,7 +776,8 @@ impl Step for RustcDev {
         copy_src_dirs(
             builder,
             &builder.src,
-            &["compiler"],
+            // The compiler has a path dependency on proc_macro, so make sure to include it.
+            &["compiler", "library/proc_macro"],
             &[],
             &tarball.image_dir().join("lib/rustlib/rustc-src/rust"),
         );
@@ -2274,12 +2275,17 @@ impl Step for LlvmTools {
 
         let target = self.target;
 
-        /* run only if llvm-config isn't used */
-        if let Some(config) = builder.config.target_config.get(&target) {
-            if let Some(ref _s) = config.llvm_config {
-                builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
-                return None;
-            }
+        // Run only if a custom llvm-config is not used
+        if let Some(config) = builder.config.target_config.get(&target)
+            && !builder.config.llvm_from_ci
+            && config.llvm_config.is_some()
+        {
+            builder.info(&format!("Skipping LlvmTools ({target}): external LLVM"));
+            return None;
+        }
+
+        if !builder.config.dry_run() {
+            builder.require_submodule("src/llvm-project", None);
         }
 
         builder.ensure(crate::core::build_steps::llvm::Llvm { target });
@@ -2294,6 +2300,12 @@ impl Step for LlvmTools {
             let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
             for tool in tools_to_install(&builder.paths) {
                 let exe = src_bindir.join(exe(tool, target));
+                // When using `download-ci-llvm`, some of the tools may not exist, so skip trying to copy them.
+                if !exe.exists() && builder.config.llvm_from_ci {
+                    eprintln!("{} does not exist; skipping copy", exe.display());
+                    continue;
+                }
+
                 tarball.add_file(&exe, &dst_bindir, FileType::Executable);
             }
         }
@@ -2387,11 +2399,15 @@ impl Step for RustDev {
         let target = self.target;
 
         /* run only if llvm-config isn't used */
-        if let Some(config) = builder.config.target_config.get(&target) {
-            if let Some(ref _s) = config.llvm_config {
-                builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
-                return None;
-            }
+        if let Some(config) = builder.config.target_config.get(&target)
+            && let Some(ref _s) = config.llvm_config
+        {
+            builder.info(&format!("Skipping RustDev ({target}): external LLVM"));
+            return None;
+        }
+
+        if !builder.config.dry_run() {
+            builder.require_submodule("src/llvm-project", None);
         }
 
         let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 1c317ce4b86..61268df7336 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -318,10 +318,10 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
                     // `into_path` produces an absolute path. Try to strip `cwd` to get a shorter
                     // relative path.
                     let mut path = entry.clone().into_path();
-                    if let Ok(cwd) = cwd {
-                        if let Ok(path2) = path.strip_prefix(cwd) {
-                            path = path2.to_path_buf();
-                        }
+                    if let Ok(cwd) = cwd
+                        && let Ok(path2) = path.strip_prefix(cwd)
+                    {
+                        path = path2.to_path_buf();
                     }
                     path.display().to_string()
                 });
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index c31c40e846b..5419540aa2e 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -38,7 +38,9 @@ fn sanitize_sh(path: &Path, is_cygwin: bool) -> String {
         if ch.next() != Some('/') {
             return None;
         }
-        Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
+        // The prefix for Windows drives in Cygwin/MSYS2 is configurable, but
+        // /proc/cygdrive is available regardless of configuration since 1.7.33
+        Some(format!("/proc/cygdrive/{}/{}", drive, &s[drive.len_utf8() + 2..]))
     }
 }
 
@@ -244,7 +246,7 @@ install!((self, builder, _config),
             );
         }
     };
-    LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, {
+    LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.build), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) {
             install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
         } else {
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index a3788197471..2b7703000cb 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -107,18 +107,18 @@ pub fn prebuilt_llvm_config(
 
     // If we're using a custom LLVM bail out here, but we can only use a
     // custom LLVM for the build triple.
-    if let Some(config) = builder.config.target_config.get(&target) {
-        if let Some(ref s) = config.llvm_config {
-            check_llvm_version(builder, s);
-            let llvm_config = s.to_path_buf();
-            let mut llvm_cmake_dir = llvm_config.clone();
-            llvm_cmake_dir.pop();
-            llvm_cmake_dir.pop();
-            llvm_cmake_dir.push("lib");
-            llvm_cmake_dir.push("cmake");
-            llvm_cmake_dir.push("llvm");
-            return LlvmBuildStatus::AlreadyBuilt(LlvmResult { llvm_config, llvm_cmake_dir });
-        }
+    if let Some(config) = builder.config.target_config.get(&target)
+        && let Some(ref s) = config.llvm_config
+    {
+        check_llvm_version(builder, s);
+        let llvm_config = s.to_path_buf();
+        let mut llvm_cmake_dir = llvm_config.clone();
+        llvm_cmake_dir.pop();
+        llvm_cmake_dir.pop();
+        llvm_cmake_dir.push("lib");
+        llvm_cmake_dir.push("cmake");
+        llvm_cmake_dir.push("llvm");
+        return LlvmBuildStatus::AlreadyBuilt(LlvmResult { llvm_config, llvm_cmake_dir });
     }
 
     if handle_submodule_when_needed {
@@ -285,7 +285,8 @@ impl Step for Llvm {
             LlvmBuildStatus::ShouldBuild(m) => m,
         };
 
-        if builder.llvm_link_shared() && target.is_windows() {
+        if builder.llvm_link_shared() && target.is_windows() && !target.ends_with("windows-gnullvm")
+        {
             panic!("shared linking to LLVM is not currently supported on {}", target.triple);
         }
 
@@ -442,23 +443,26 @@ impl Step for Llvm {
         // See https://github.com/rust-lang/rust/pull/50104
         cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
 
-        if !enabled_llvm_projects.is_empty() {
-            enabled_llvm_projects.sort();
-            enabled_llvm_projects.dedup();
-            cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";"));
-        }
-
         let mut enabled_llvm_runtimes = Vec::new();
 
         if helpers::forcing_clang_based_tests() {
             enabled_llvm_runtimes.push("compiler-rt");
         }
 
+        // This is an experimental flag, which likely builds more than necessary.
+        // We will optimize it when we get closer to releasing it on nightly.
         if builder.config.llvm_offload {
             enabled_llvm_runtimes.push("offload");
             //FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp.
             //Remove this line once they achieved it.
             enabled_llvm_runtimes.push("openmp");
+            enabled_llvm_projects.push("compiler-rt");
+        }
+
+        if !enabled_llvm_projects.is_empty() {
+            enabled_llvm_projects.sort();
+            enabled_llvm_projects.dedup();
+            cfg.define("LLVM_ENABLE_PROJECTS", enabled_llvm_projects.join(";"));
         }
 
         if !enabled_llvm_runtimes.is_empty() {
@@ -467,10 +471,10 @@ impl Step for Llvm {
             cfg.define("LLVM_ENABLE_RUNTIMES", enabled_llvm_runtimes.join(";"));
         }
 
-        if let Some(num_linkers) = builder.config.llvm_link_jobs {
-            if num_linkers > 0 {
-                cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
-            }
+        if let Some(num_linkers) = builder.config.llvm_link_jobs
+            && num_linkers > 0
+        {
+            cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
         }
 
         // https://llvm.org/docs/HowToCrossCompileLLVM.html
@@ -596,10 +600,10 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
 
     let version = get_llvm_version(builder, llvm_config);
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
-    if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
-        if major >= 19 {
-            return;
-        }
+    if let (Some(major), Some(_minor)) = (parts.next(), parts.next())
+        && major >= 19
+    {
+        return;
     }
     panic!("\n\nbad LLVM version: {version}, need >=19\n\n")
 }
@@ -729,11 +733,9 @@ fn configure_cmake(
 
     // If ccache is configured we inform the build a little differently how
     // to invoke ccache while also invoking our compilers.
-    if use_compiler_launcher {
-        if let Some(ref ccache) = builder.config.ccache {
-            cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache)
-                .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache);
-        }
+    if use_compiler_launcher && let Some(ref ccache) = builder.config.ccache {
+        cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache)
+            .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache);
     }
     cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
         .define("CMAKE_CXX_COMPILER", sanitize_cc(&cxx))
@@ -791,20 +793,20 @@ fn configure_cmake(
         cxxflags.push(format!(" --target={target}"));
     }
     cfg.define("CMAKE_CXX_FLAGS", cxxflags);
-    if let Some(ar) = builder.ar(target) {
-        if ar.is_absolute() {
-            // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
-            // tries to resolve this path in the LLVM build directory.
-            cfg.define("CMAKE_AR", sanitize_cc(&ar));
-        }
+    if let Some(ar) = builder.ar(target)
+        && ar.is_absolute()
+    {
+        // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
+        // tries to resolve this path in the LLVM build directory.
+        cfg.define("CMAKE_AR", sanitize_cc(&ar));
     }
 
-    if let Some(ranlib) = builder.ranlib(target) {
-        if ranlib.is_absolute() {
-            // LLVM build breaks if `CMAKE_RANLIB` is a relative path, for some reason it
-            // tries to resolve this path in the LLVM build directory.
-            cfg.define("CMAKE_RANLIB", sanitize_cc(&ranlib));
-        }
+    if let Some(ranlib) = builder.ranlib(target)
+        && ranlib.is_absolute()
+    {
+        // LLVM build breaks if `CMAKE_RANLIB` is a relative path, for some reason it
+        // tries to resolve this path in the LLVM build directory.
+        cfg.define("CMAKE_RANLIB", sanitize_cc(&ranlib));
     }
 
     if let Some(ref flags) = builder.config.llvm_ldflags {
@@ -1037,13 +1039,14 @@ impl Step for Lld {
         // when doing PGO on CI, cmake or clang-cl don't automatically link clang's
         // profiler runtime in. In that case, we need to manually ask cmake to do it, to avoid
         // linking errors, much like LLVM's cmake setup does in that situation.
-        if builder.config.llvm_profile_generate && target.is_msvc() {
-            if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() {
-                // Find clang's runtime library directory and push that as a search path to the
-                // cmake linker flags.
-                let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
-                ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
-            }
+        if builder.config.llvm_profile_generate
+            && target.is_msvc()
+            && let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref()
+        {
+            // Find clang's runtime library directory and push that as a search path to the
+            // cmake linker flags.
+            let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
+            ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
         }
 
         // LLD is built as an LLVM tool, but is distributed outside of the `llvm-tools` component,
@@ -1430,6 +1433,7 @@ impl Step for Libunwind {
             cfg.flag("-funwind-tables");
             cfg.flag("-fvisibility=hidden");
             cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+            cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1");
             cfg.include(root.join("include"));
             cfg.cargo_metadata(false);
             cfg.out_dir(&out_dir);
@@ -1447,12 +1451,10 @@ impl Step for Libunwind {
                 cfg.define("__NO_STRING_INLINES", None);
                 cfg.define("__NO_MATH_INLINES", None);
                 cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
-                cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
                 cfg.define("NDEBUG", None);
             }
             if self.target.is_windows() {
                 cfg.define("_LIBUNWIND_HIDE_SYMBOLS", "1");
-                cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1");
             }
         }
 
diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs
index 7f4e88bd73c..14c7b7cf5e9 100644
--- a/src/bootstrap/src/core/build_steps/perf.rs
+++ b/src/bootstrap/src/core/build_steps/perf.rs
@@ -1,3 +1,4 @@
+use std::env::consts::EXE_EXTENSION;
 use std::fmt::{Display, Formatter};
 
 use crate::core::build_steps::compile::{Std, Sysroot};
@@ -153,14 +154,17 @@ Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#);
     let compiler = builder.compiler(builder.top_stage, builder.config.build);
     builder.ensure(Std::new(compiler, builder.config.build));
 
-    if let Some(opts) = args.cmd.shared_opts() {
-        if opts.profiles.contains(&Profile::Doc) {
-            builder.ensure(Rustdoc { compiler });
-        }
+    if let Some(opts) = args.cmd.shared_opts()
+        && opts.profiles.contains(&Profile::Doc)
+    {
+        builder.ensure(Rustdoc { compiler });
     }
 
     let sysroot = builder.ensure(Sysroot::new(compiler));
-    let rustc = sysroot.join("bin/rustc");
+    let mut rustc = sysroot.clone();
+    rustc.push("bin");
+    rustc.push("rustc");
+    rustc.set_extension(EXE_EXTENSION);
 
     let rustc_perf_dir = builder.build.tempdir().join("rustc-perf");
     let results_dir = rustc_perf_dir.join("results");
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 0bba441c3fa..6ef1b13abcd 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -5,7 +5,6 @@
 
 use std::path::PathBuf;
 
-use crate::Mode;
 use crate::core::build_steps::dist::distdir;
 use crate::core::build_steps::test;
 use crate::core::build_steps::tool::{self, SourceType, Tool};
@@ -14,6 +13,7 @@ use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::core::config::flags::get_completion;
 use crate::utils::exec::command;
+use crate::{Mode, t};
 
 #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
 pub struct BuildManifest;
@@ -118,15 +118,25 @@ impl Step for Miri {
     fn run(self, builder: &Builder<'_>) {
         let host = builder.build.build;
         let target = self.target;
-        let stage = builder.top_stage;
+
+        // `x run` uses stage 0 by default but miri does not work well with stage 0.
+        // Change the stage to 1 if it's not set explicitly.
+        let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 {
+            builder.top_stage
+        } else {
+            1
+        };
+
         if stage == 0 {
             eprintln!("miri cannot be run at stage 0");
             std::process::exit(1);
         }
 
         // This compiler runs on the host, we'll just use it for the target.
-        let target_compiler = builder.compiler(stage, host);
-        let host_compiler = tool::get_tool_rustc_compiler(builder, target_compiler);
+        let target_compiler = builder.compiler(stage, target);
+        let miri_build = builder.ensure(tool::Miri { compiler: target_compiler, target });
+        // Rustc tools are off by one stage, so use the build compiler to run miri.
+        let host_compiler = miri_build.build_compiler;
 
         // Get a target sysroot for Miri.
         let miri_sysroot = test::Miri::build_miri_sysroot(builder, target_compiler, target);
@@ -243,6 +253,7 @@ impl Step for GenerateCopyright {
         cmd.env("SRC_DIR", &builder.src);
         cmd.env("VENDOR_DIR", &vendored_sources);
         cmd.env("CARGO", &builder.initial_cargo);
+        cmd.env("CARGO_HOME", t!(home::cargo_home()));
         // it is important that generate-copyright runs from the root of the
         // source tree, because it uses relative paths
         cmd.current_dir(&builder.src);
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 31ec462134d..25adfdf1601 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -241,10 +241,10 @@ impl Step for Link {
         if run.builder.config.dry_run() {
             return;
         }
-        if let [cmd] = &run.paths[..] {
-            if cmd.assert_single_path().path.as_path().as_os_str() == "link" {
-                run.builder.ensure(Link);
-            }
+        if let [cmd] = &run.paths[..]
+            && cmd.assert_single_path().path.as_path().as_os_str() == "link"
+        {
+            run.builder.ensure(Link);
         }
     }
     fn run(self, builder: &Builder<'_>) -> Self::Output {
@@ -457,10 +457,10 @@ impl Step for Hook {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        if let [cmd] = &run.paths[..] {
-            if cmd.assert_single_path().path.as_path().as_os_str() == "hook" {
-                run.builder.ensure(Hook);
-            }
+        if let [cmd] = &run.paths[..]
+            && cmd.assert_single_path().path.as_path().as_os_str() == "hook"
+        {
+            run.builder.ensure(Hook);
         }
     }
 
@@ -585,11 +585,13 @@ Select which editor you would like to set up [default: None]: ";
                 "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
                 "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
                 "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
+                "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
             ],
             EditorKind::Helix => &[
                 "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
                 "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040",
                 "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
+                "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
             ],
             EditorKind::Vim | EditorKind::VsCode => &[
                 "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
@@ -604,11 +606,13 @@ Select which editor you would like to set up [default: None]: ";
                 "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
                 "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
                 "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
+                "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
             ],
             EditorKind::Zed => &[
                 "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
                 "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
                 "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
+                "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
             ],
         }
     }
@@ -668,10 +672,10 @@ impl Step for Editor {
         if run.builder.config.dry_run() {
             return;
         }
-        if let [cmd] = &run.paths[..] {
-            if cmd.assert_single_path().path.as_path().as_os_str() == "editor" {
-                run.builder.ensure(Editor);
-            }
+        if let [cmd] = &run.paths[..]
+            && cmd.assert_single_path().path.as_path().as_os_str() == "editor"
+        {
+            run.builder.ensure(Editor);
         }
     }
 
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 27791825aa0..dddce8fe05d 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -739,7 +739,7 @@ impl Step for Clippy {
     const DEFAULT: bool = false;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/tools/clippy")
+        run.suite_path("src/tools/clippy/tests").path("src/tools/clippy")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -783,6 +783,23 @@ impl Step for Clippy {
         let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
         cargo.env("HOST_LIBS", host_libs);
 
+        // Collect paths of tests to run
+        'partially_test: {
+            let paths = &builder.config.paths[..];
+            let mut test_names = Vec::new();
+            for path in paths {
+                if let Some(path) =
+                    helpers::is_valid_test_suite_arg(path, "src/tools/clippy/tests", builder)
+                {
+                    test_names.push(path);
+                } else if path.ends_with("src/tools/clippy") {
+                    // When src/tools/clippy is called directly, all tests should be run.
+                    break 'partially_test;
+                }
+            }
+            cargo.env("TESTNAME", test_names.join(","));
+        }
+
         cargo.add_rustc_lib_path(builder);
         let cargo = prepare_cargo_test(cargo, &[], &[], host, builder);
 
@@ -1559,7 +1576,7 @@ impl Step for Compiletest {
 
         if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
             eprintln!("\
-ERROR: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail
+ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
 HELP: to test the compiler, use `--stage 1` instead
 HELP: to test the standard library, use `--stage 0 library/std` instead
 NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
@@ -1587,9 +1604,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         // NOTE: Only stage 1 is special cased because we need the rustc_private artifacts to match the
         // running compiler in stage 2 when plugins run.
         let (stage, stage_id) = if suite == "ui-fulldeps" && compiler.stage == 1 {
-            // At stage 0 (stage - 1) we are using the beta compiler. Using `self.target` can lead
-            // finding an incorrect compiler path on cross-targets, as the stage 0 beta compiler is
-            // always equal to `build.build` in the configuration.
+            // At stage 0 (stage - 1) we are using the stage0 compiler. Using `self.target` can lead
+            // finding an incorrect compiler path on cross-targets, as the stage 0 is always equal to
+            // `build.build` in the configuration.
             let build = builder.build.build;
             compiler = builder.compiler(compiler.stage - 1, build);
             let test_stage = compiler.stage + 1;
@@ -1675,7 +1692,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         }
 
         if mode == "rustdoc-json" {
-            // Use the beta compiler for jsondocck
+            // Use the stage0 compiler for jsondocck
             let json_compiler = compiler.with_stage(0);
             cmd.arg("--jsondocck-path")
                 .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);
@@ -2400,10 +2417,10 @@ impl Step for ErrorIndex {
 }
 
 fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> bool {
-    if let Ok(contents) = fs::read_to_string(markdown) {
-        if !contents.contains("```") {
-            return true;
-        }
+    if let Ok(contents) = fs::read_to_string(markdown)
+        && !contents.contains("```")
+    {
+        return true;
     }
 
     builder.verbose(|| println!("doc tests for: {}", markdown.display()));
@@ -2690,16 +2707,6 @@ impl Step for Crate {
                         .arg(builder.src.join("library/sysroot/Cargo.toml"));
                 } else {
                     compile::std_cargo(builder, target, compiler.stage, &mut cargo);
-                    // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`,
-                    // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`.
-                    // Override it.
-                    if builder.download_rustc() && compiler.stage > 0 {
-                        let sysroot = builder
-                            .out
-                            .join(compiler.host)
-                            .join(format!("stage{}-test-sysroot", compiler.stage));
-                        cargo.env("RUSTC_SYSROOT", sysroot);
-                    }
                 }
             }
             Mode::Rustc => {
@@ -2947,7 +2954,14 @@ impl Step for Distcheck {
         run.builder.ensure(Distcheck);
     }
 
-    /// Runs "distcheck", a 'make check' from a tarball
+    /// Runs `distcheck`, which is a collection of smoke tests:
+    ///
+    /// - Run `make check` from an unpacked dist tarball to make sure we can at the minimum run
+    ///   check steps from those sources.
+    /// - Check that selected dist components (`rust-src` only at the moment) at least have expected
+    ///   directory shape and crate manifests that cargo can generate a lockfile from.
+    ///
+    /// FIXME(#136822): dist components are under-tested.
     fn run(self, builder: &Builder<'_>) {
         builder.info("Distcheck");
         let dir = builder.tempdir().join("distcheck");
@@ -3520,7 +3534,7 @@ impl Step for CodegenGCC {
 }
 
 /// Test step that does two things:
-/// - Runs `cargo test` for the `src/etc/test-float-parse` tool.
+/// - Runs `cargo test` for the `src/tools/test-float-parse` tool.
 /// - Invokes the `test-float-parse` tool to test the standard library's
 ///   float parsing routines.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -3535,7 +3549,7 @@ impl Step for TestFloatParse {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/etc/test-float-parse")
+        run.path("src/tools/test-float-parse")
     }
 
     fn make_run(run: RunConfig<'_>) {
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 678aa9b01e4..9861637d8c8 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -148,6 +148,17 @@ impl Step for ToolBuild {
             &self.extra_features,
         );
 
+        // The stage0 compiler changes infrequently and does not directly depend on code
+        // in the current working directory. Therefore, caching it with sccache should be
+        // useful.
+        // This is only performed for non-incremental builds, as ccache cannot deal with these.
+        if let Some(ref ccache) = builder.config.ccache
+            && matches!(self.mode, Mode::ToolBootstrap)
+            && !builder.config.incremental
+        {
+            cargo.env("RUSTC_WRAPPER", ccache);
+        }
+
         // Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer)
         // could use the additional optimizations.
         if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) {
@@ -329,9 +340,9 @@ pub(crate) fn get_tool_rustc_compiler(
         return target_compiler;
     }
 
-    if builder.download_rustc() && target_compiler.stage > 0 {
-        // We already have the stage N compiler, we don't need to cut the stage.
-        return builder.compiler(target_compiler.stage, builder.config.build);
+    if builder.download_rustc() && target_compiler.stage == 1 {
+        // We shouldn't drop to stage0 compiler when using CI rustc.
+        return builder.compiler(1, builder.config.build);
     }
 
     // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
@@ -1197,9 +1208,9 @@ fn run_tool_build_step(
             artifact_kind: ToolArtifactKind::Binary,
         });
 
-    // FIXME: This should just be an if-let-chain, but those are unstable.
-    if let Some(add_bins_to_sysroot) =
-        add_bins_to_sysroot.filter(|bins| !bins.is_empty() && target_compiler.stage > 0)
+    if let Some(add_bins_to_sysroot) = add_bins_to_sysroot
+        && !add_bins_to_sysroot.is_empty()
+        && target_compiler.stage > 0
     {
         let bindir = builder.sysroot(target_compiler).join("bin");
         t!(fs::create_dir_all(&bindir));
@@ -1269,7 +1280,7 @@ impl Step for TestFloatParse {
     const DEFAULT: bool = false;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/etc/test-float-parse")
+        run.path("src/tools/test-float-parse")
     }
 
     fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
@@ -1281,7 +1292,7 @@ impl Step for TestFloatParse {
             target: bootstrap_host,
             tool: "test-float-parse",
             mode: Mode::ToolStd,
-            path: "src/etc/test-float-parse",
+            path: "src/tools/test-float-parse",
             source_type: SourceType::InTree,
             extra_features: Vec::new(),
             allow_features: Self::ALLOW_FEATURES,
@@ -1302,10 +1313,8 @@ impl Builder<'_> {
         //
         // Notably this munges the dynamic library lookup path to point to the
         // right location to run `compiler`.
-        let mut lib_paths: Vec<PathBuf> = vec![
-            self.build.rustc_snapshot_libdir(),
-            self.cargo_out(compiler, Mode::ToolBootstrap, *host).join("deps"),
-        ];
+        let mut lib_paths: Vec<PathBuf> =
+            vec![self.cargo_out(compiler, Mode::ToolBootstrap, *host).join("deps")];
 
         // On MSVC a tool may invoke a C compiler (e.g., compiletest in run-make
         // mode) and that C compiler may need some extra PATH modification. Do
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index e41f6f16b02..cf7f962d026 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -11,7 +11,7 @@ use crate::utils::build_stamp;
 use crate::utils::helpers::{self, LldThreads, check_cfg_arg, linker_args, linker_flags};
 use crate::{
     BootstrapCommand, CLang, Compiler, Config, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode,
-    TargetSelection, command, prepare_behaviour_dump_dir, t,
+    RemapScheme, TargetSelection, command, prepare_behaviour_dump_dir, t,
 };
 
 /// Represents flag values in `String` form with whitespace delimiter to pass it to the compiler
@@ -636,6 +636,15 @@ impl Builder<'_> {
         for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
             if restricted_mode.is_none() || *restricted_mode == Some(mode) {
                 rustflags.arg(&check_cfg_arg(name, *values));
+
+                if *name == "bootstrap" {
+                    // Cargo doesn't pass RUSTFLAGS to proc_macros:
+                    // https://github.com/rust-lang/cargo/issues/4423
+                    // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`.
+                    // We also declare that the flag is expected, which we need to do to not
+                    // get warnings about it being unexpected.
+                    hostflags.arg(check_cfg_arg(name, *values));
+                }
             }
         }
 
@@ -645,13 +654,6 @@ impl Builder<'_> {
         if stage == 0 {
             hostflags.arg("--cfg=bootstrap");
         }
-        // Cargo doesn't pass RUSTFLAGS to proc_macros:
-        // https://github.com/rust-lang/cargo/issues/4423
-        // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`.
-        // We also declare that the flag is expected, which we need to do to not
-        // get warnings about it being unexpected.
-        hostflags.arg("-Zunstable-options");
-        hostflags.arg("--check-cfg=cfg(bootstrap)");
 
         // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
         // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
@@ -920,13 +922,46 @@ impl Builder<'_> {
             hostflags.arg(format!("-Ctarget-feature={sign}crt-static"));
         }
 
-        if let Some(map_to) = self.build.debuginfo_map_to(GitRepo::Rustc) {
-            let map = format!("{}={}", self.build.src.display(), map_to);
-            cargo.env("RUSTC_DEBUGINFO_MAP", map);
+        // `rustc` needs to know the remapping scheme, in order to know how to reverse it (unremap)
+        // later. Two env vars are set and made available to the compiler
+        //
+        // - `CFG_VIRTUAL_RUST_SOURCE_BASE_DIR`: `rust-src` remap scheme (`NonCompiler`)
+        // - `CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR`: `rustc-dev` remap scheme (`Compiler`)
+        //
+        // Keep this scheme in sync with `rustc_metadata::rmeta::decoder`'s
+        // `try_to_translate_virtual_to_real`.
+        //
+        // `RUSTC_DEBUGINFO_MAP` is used to pass through to the underlying rustc
+        // `--remap-path-prefix`.
+        match mode {
+            Mode::Rustc | Mode::Codegen => {
+                if let Some(ref map_to) =
+                    self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler)
+                {
+                    cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to);
+                }
 
-            // `rustc` needs to know the virtual `/rustc/$hash` we're mapping to,
-            // in order to opportunistically reverse it later.
-            cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to);
+                if let Some(ref map_to) =
+                    self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::Compiler)
+                {
+                    // When building compiler sources, we want to apply the compiler remap scheme.
+                    cargo.env(
+                        "RUSTC_DEBUGINFO_MAP",
+                        format!("{}={}", self.build.src.display(), map_to),
+                    );
+                    cargo.env("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR", map_to);
+                }
+            }
+            Mode::Std | Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd => {
+                if let Some(ref map_to) =
+                    self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler)
+                {
+                    cargo.env(
+                        "RUSTC_DEBUGINFO_MAP",
+                        format!("{}={}", self.build.src.display(), map_to),
+                    );
+                }
+            }
         }
 
         if self.config.rust_remap_debuginfo {
@@ -988,15 +1023,15 @@ impl Builder<'_> {
         // requirement, but the `-L` library path is not propagated across
         // separate Cargo projects. We can add LLVM's library path to the
         // rustc args as a workaround.
-        if mode == Mode::ToolRustc || mode == Mode::Codegen {
-            if let Some(llvm_config) = self.llvm_config(target) {
-                let llvm_libdir =
-                    command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout();
-                if target.is_msvc() {
-                    rustflags.arg(&format!("-Clink-arg=-LIBPATH:{llvm_libdir}"));
-                } else {
-                    rustflags.arg(&format!("-Clink-arg=-L{llvm_libdir}"));
-                }
+        if (mode == Mode::ToolRustc || mode == Mode::Codegen)
+            && let Some(llvm_config) = self.llvm_config(target)
+        {
+            let llvm_libdir =
+                command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout();
+            if target.is_msvc() {
+                rustflags.arg(&format!("-Clink-arg=-LIBPATH:{llvm_libdir}"));
+            } else {
+                rustflags.arg(&format!("-Clink-arg=-L{llvm_libdir}"));
             }
         }
 
@@ -1004,7 +1039,12 @@ impl Builder<'_> {
         // efficient initial-exec TLS model. This doesn't work with `dlopen`,
         // so we can't use it by default in general, but we can use it for tools
         // and our own internal libraries.
-        if !mode.must_support_dlopen() && !target.triple.starts_with("powerpc-") {
+        //
+        // Cygwin only supports emutls.
+        if !mode.must_support_dlopen()
+            && !target.triple.starts_with("powerpc-")
+            && !target.triple.contains("cygwin")
+        {
             cargo.env("RUSTC_TLS_MODEL_INITIAL_EXEC", "1");
         }
 
@@ -1226,12 +1266,11 @@ impl Builder<'_> {
                 _ => None,
             };
 
-            if let Some(limit) = limit {
-                if stage == 0
-                    || self.config.default_codegen_backend(target).unwrap_or_default() == "llvm"
-                {
-                    rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
-                }
+            if let Some(limit) = limit
+                && (stage == 0
+                    || self.config.default_codegen_backend(target).unwrap_or_default() == "llvm")
+            {
+                rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
             }
         }
 
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index af3e3cc37b9..19b79bfe818 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -945,7 +945,6 @@ impl<'a> Builder<'a> {
                 clippy::CI,
             ),
             Kind::Check | Kind::Fix => describe!(
-                check::Std,
                 check::Rustc,
                 check::Rustdoc,
                 check::CodegenBackend,
@@ -961,6 +960,13 @@ impl<'a> Builder<'a> {
                 check::Compiletest,
                 check::FeaturesStatusDump,
                 check::CoverageDump,
+                // This has special staging logic, it may run on stage 1 while others run on stage 0.
+                // It takes quite some time to build stage 1, so put this at the end.
+                //
+                // FIXME: This also helps bootstrap to not interfere with stage 0 builds. We should probably fix
+                // that issue somewhere else, but we still want to keep `check::Std` at the end so that the
+                // quicker steps run before this.
+                check::Std,
             ),
             Kind::Test => describe!(
                 crate::core::build_steps::toolstate::ToolStateCheck,
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 51852099dc3..baa22fc7f72 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -237,7 +237,7 @@ fn alias_and_path_for_library() {
     );
     assert_eq!(
         first(cache.all::<doc::Std>()),
-        &[doc_std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0)]
+        &[doc_std!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1)]
     );
 }
 
@@ -255,19 +255,6 @@ fn ci_rustc_if_unchanged_invalidate_on_compiler_changes() {
 }
 
 #[test]
-fn ci_rustc_if_unchanged_invalidate_on_library_changes_in_ci() {
-    git_test(|ctx| {
-        prepare_rustc_checkout(ctx);
-        ctx.create_upstream_merge(&["compiler/bar"]);
-        // This change should invalidate download-ci-rustc
-        ctx.create_nonupstream_merge(&["library/foo"]);
-
-        let config = parse_config_download_rustc_at(ctx.get_path(), "if-unchanged", true);
-        assert_eq!(config.download_rustc_commit, None);
-    });
-}
-
-#[test]
 fn ci_rustc_if_unchanged_do_not_invalidate_on_library_changes_outside_ci() {
     git_test(|ctx| {
         prepare_rustc_checkout(ctx);
@@ -433,14 +420,14 @@ mod defaults {
         assert_eq!(first(cache.all::<doc::ErrorIndex>()), &[doc::ErrorIndex { target: a },]);
         assert_eq!(
             first(cache.all::<tool::ErrorIndex>()),
-            &[tool::ErrorIndex { compiler: Compiler::new(0, a) }]
+            &[tool::ErrorIndex { compiler: Compiler::new(1, a) }]
         );
-        // docs should be built with the beta compiler, not with the stage0 artifacts.
+        // docs should be built with the stage0 compiler, not with the stage0 artifacts.
         // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to,
         // not the one it was built by.
         assert_eq!(
             first(cache.all::<tool::Rustdoc>()),
-            &[tool::Rustdoc { compiler: Compiler::new(0, a) },]
+            &[tool::Rustdoc { compiler: Compiler::new(1, a) },]
         );
     }
 }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 3b8c3655b8d..a92d58ef9e8 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1,36 +1,54 @@
-//! 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};
 
-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 +62,8 @@ 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",
     ":!src/rustdoc-json-types",
@@ -52,138 +71,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.
@@ -249,9 +136,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,
@@ -268,10 +152,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>,
@@ -344,9 +224,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,
@@ -422,932 +299,11 @@ pub struct Config {
 
     /// Cache for determining path modifications
     pub path_modification_cache: Arc<Mutex<HashMap<Vec<&'static str>, PathFreshness>>>,
-}
-
-#[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",
-    }
+    /// Skip checking the standard library if `rust.download-rustc` isn't available.
+    /// This is mostly for RA as building the stage1 compiler to check the library tree
+    /// on each code change might be too much for some computers.
+    pub skip_std_check_if_no_download_rustc: bool,
 }
 
 impl Config {
@@ -1404,47 +360,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)
@@ -1506,6 +421,7 @@ impl Config {
         config.enable_bolt_settings = flags.enable_bolt_settings;
         config.bypass_bootstrap_lock = flags.bypass_bootstrap_lock;
         config.is_running_on_ci = flags.ci.unwrap_or(CiEnv::is_ci());
+        config.skip_std_check_if_no_download_rustc = flags.skip_std_check_if_no_download_rustc;
 
         // Infer the rest of the configuration.
 
@@ -1699,20 +615,20 @@ impl Config {
             };
             // We want to be able to set string values without quotes,
             // like in `configure.py`. Try adding quotes around the right hand side
-            if let Some((key, value)) = option.split_once('=') {
-                if !value.contains('"') {
-                    match get_table(&format!(r#"{key}="{value}""#)) {
-                        Ok(v) => {
-                            override_toml.merge(
-                                None,
-                                &mut Default::default(),
-                                v,
-                                ReplaceOpt::ErrorOnDuplicate,
-                            );
-                            continue;
-                        }
-                        Err(e) => err = e,
+            if let Some((key, value)) = option.split_once('=')
+                && !value.contains('"')
+            {
+                match get_table(&format!(r#"{key}="{value}""#)) {
+                    Ok(v) => {
+                        override_toml.merge(
+                            None,
+                            &mut Default::default(),
+                            v,
+                            ReplaceOpt::ErrorOnDuplicate,
+                        );
+                        continue;
                     }
+                    Err(e) => err = e,
                 }
             }
             eprintln!("failed to parse override `{option}`: `{err}");
@@ -1832,7 +748,9 @@ impl Config {
                 .join(exe("rustc", config.build))
         };
 
-        config.initial_sysroot = config.initial_rustc.ancestors().nth(2).unwrap().into();
+        config.initial_sysroot = t!(PathBuf::from_str(
+            output(Command::new(&config.initial_rustc).args(["--print", "sysroot"])).trim()
+        ));
 
         config.initial_cargo_clippy = cargo_clippy;
 
@@ -1903,42 +821,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();
 
@@ -1982,191 +869,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 {
-                if let Some(ref opt) = download_rustc {
-                    if 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.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_profile_use = flags.rust_profile_use;
+        config.rust_profile_generate = flags.rust_profile_generate;
 
-            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;
@@ -2174,221 +880,24 @@ impl Config {
         // We need to override `rust.channel` if it's manually specified when using the CI rustc.
         // This is because if the compiler uses a different channel than the one specified in bootstrap.toml,
         // tests may fail due to using a different channel than the one used by the compiler during tests.
-        if let Some(commit) = &config.download_rustc_commit {
-            if is_user_configured_rust_channel {
-                println!(
-                    "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
-                );
-
-                let channel = config
-                    .read_file_by_commit(Path::new("src/ci/channel"), commit)
-                    .trim()
-                    .to_owned();
-
-                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 let Some(commit) = &config.download_rustc_commit
+            && is_user_configured_rust_channel
+        {
+            println!(
+                "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
+            );
 
-            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);
-        }
+            let channel =
+                config.read_file_by_commit(Path::new("src/ci/channel"), commit).trim().to_owned();
 
-        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.channel = channel;
         }
 
-        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 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}'.");
-                            }
-                        }
+        config.apply_llvm_config(toml.llvm, &mut ccache);
 
-                        s.clone()
-                    }).collect());
-                }
+        config.apply_gcc_config(toml.gcc);
 
-                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()),
@@ -2412,69 +921,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
@@ -2490,31 +941,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;
@@ -2532,9 +958,10 @@ impl Config {
         // See https://github.com/rust-lang/compiler-team/issues/326
         config.stage = match config.cmd {
             Subcommand::Check { .. } => flags.stage.or(check_stage).unwrap_or(0),
+            Subcommand::Clippy { .. } | Subcommand::Fix => flags.stage.or(check_stage).unwrap_or(1),
             // `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden.
             Subcommand::Doc { .. } => {
-                flags.stage.or(doc_stage).unwrap_or(if download_rustc { 2 } else { 0 })
+                flags.stage.or(doc_stage).unwrap_or(if download_rustc { 2 } else { 1 })
             }
             Subcommand::Build => {
                 flags.stage.or(build_stage).unwrap_or(if download_rustc { 2 } else { 1 })
@@ -2549,8 +976,6 @@ impl Config {
             // These are all bootstrap tools, which don't depend on the compiler.
             // The stage we pass shouldn't matter, but use 0 just in case.
             Subcommand::Clean { .. }
-            | Subcommand::Clippy { .. }
-            | Subcommand::Fix
             | Subcommand::Run { .. }
             | Subcommand::Setup { .. }
             | Subcommand::Format { .. }
@@ -2696,10 +1121,10 @@ impl Config {
         let bindir = &self.bindir;
         if bindir.is_absolute() {
             // Try to make it relative to the prefix.
-            if let Some(prefix) = &self.prefix {
-                if let Ok(stripped) = bindir.strip_prefix(prefix) {
-                    return stripped;
-                }
+            if let Some(prefix) = &self.prefix
+                && let Ok(stripped) = bindir.strip_prefix(prefix)
+            {
+                return stripped;
             }
         }
         bindir
@@ -2840,75 +1265,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
@@ -2916,21 +1283,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,
@@ -3114,7 +1466,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,
@@ -3148,24 +1500,10 @@ impl Config {
             }
         };
 
-        // RUSTC_IF_UNCHANGED_ALLOWED_PATHS
-        let mut allowed_paths = RUSTC_IF_UNCHANGED_ALLOWED_PATHS.to_vec();
-
-        // In CI, disable ci-rustc if there are changes in the library tree. But for non-CI, allow
-        // these changes to speed up the build process for library developers. This provides consistent
-        // functionality for library developers between `download-rustc=true` and `download-rustc="if-unchanged"`
-        // options.
-        //
-        // If you update "library" logic here, update `builder::tests::ci_rustc_if_unchanged_logic` test
-        // logic accordingly.
-        if !self.is_running_on_ci {
-            allowed_paths.push(":!library");
-        }
-
         let commit = if self.rust_info.is_managed_git_subrepository() {
             // Look for a version to compare to based on the current commit.
             // Only commits merged by bors will have CI artifacts.
-            let freshness = self.check_path_modifications(&allowed_paths);
+            let freshness = self.check_path_modifications(RUSTC_IF_UNCHANGED_ALLOWED_PATHS);
             self.verbose(|| {
                 eprintln!("rustc freshness: {freshness:?}");
             });
@@ -3208,7 +1546,7 @@ impl Config {
         Some(commit)
     }
 
-    fn parse_download_ci_llvm(
+    pub fn parse_download_ci_llvm(
         &self,
         download_ci_llvm: Option<StringOrBool>,
         asserts: bool,
@@ -3291,6 +1629,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
@@ -3326,290 +1741,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)) {
-        if 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 08bd87e03a1..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)]
@@ -182,6 +183,11 @@ pub struct Flags {
     /// Make bootstrap to behave as it's running on the CI environment or not.
     #[arg(global = true, long, value_name = "bool")]
     pub ci: Option<bool>,
+    /// Skip checking the standard library if `rust.download-rustc` isn't available.
+    /// This is mostly for RA as building the stage1 compiler to check the library tree
+    /// on each code change might be too much for some computers.
+    #[arg(global = true, long)]
+    pub skip_std_check_if_no_download_rustc: bool,
 }
 
 impl Flags {
diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs
index 179e15e778b..285d20917e7 100644
--- a/src/bootstrap/src/core/config/mod.rs
+++ b/src/bootstrap/src/core/config/mod.rs
@@ -1,7 +1,416 @@
+//! 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;
+
+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 e0c9877cd55..ba00b405c61 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -666,7 +666,7 @@ impl Config {
             }
         };
 
-        // For the beta compiler, put special effort into ensuring the checksums are valid.
+        // For the stage0 compiler, put special effort into ensuring the checksums are valid.
         let checksum = if should_verify {
             let error = format!(
                 "src/stage0 doesn't contain a checksum for {url}. \
@@ -709,10 +709,10 @@ download-rustc = false
 ";
         }
         self.download_file(&format!("{base_url}/{url}"), &tarball, help_on_error);
-        if let Some(sha256) = checksum {
-            if !self.verify(&tarball, sha256) {
-                panic!("failed to verify {}", tarball.display());
-            }
+        if let Some(sha256) = checksum
+            && !self.verify(&tarball, sha256)
+        {
+            panic!("failed to verify {}", tarball.display());
         }
 
         self.unpack(&tarball, &bin_root, prefix);
@@ -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/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index af4ec679d08..59ae303e21e 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -34,6 +34,8 @@ pub struct Finder {
 // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
+    "loongarch32-unknown-none",
+    "loongarch32-unknown-none-softfloat",
 ];
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 9492ffaed75..7db57889009 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -81,7 +81,10 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"];
 /// (Mode restriction, config name, config values (if any))
 #[expect(clippy::type_complexity)] // It's fine for hard-coded list and type is explained above.
 const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
-    (None, "bootstrap", None),
+    (Some(Mode::Rustc), "bootstrap", None),
+    (Some(Mode::Codegen), "bootstrap", None),
+    (Some(Mode::ToolRustc), "bootstrap", None),
+    (Some(Mode::ToolStd), "bootstrap", None),
     (Some(Mode::Rustc), "llvm_enzyme", None),
     (Some(Mode::Codegen), "llvm_enzyme", None),
     (Some(Mode::ToolRustc), "llvm_enzyme", None),
@@ -272,6 +275,16 @@ impl Mode {
     }
 }
 
+/// When `rust.rust_remap_debuginfo` is requested, the compiler needs to know how to
+/// opportunistically unremap compiler vs non-compiler sources. We use two schemes,
+/// [`RemapScheme::Compiler`] and [`RemapScheme::NonCompiler`].
+pub enum RemapScheme {
+    /// The [`RemapScheme::Compiler`] scheme will remap to `/rustc-dev/{hash}`.
+    Compiler,
+    /// The [`RemapScheme::NonCompiler`] scheme will remap to `/rustc/{hash}`.
+    NonCompiler,
+}
+
 #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 pub enum CLang {
     C,
@@ -363,19 +376,35 @@ impl Build {
         let in_tree_llvm_info = config.in_tree_llvm_info.clone();
         let in_tree_gcc_info = config.in_tree_gcc_info.clone();
 
-        let initial_target_libdir_str =
-            config.initial_sysroot.join("lib/rustlib").join(config.build).join("lib");
+        let initial_target_libdir =
+            output(Command::new(&config.initial_rustc).args(["--print", "target-libdir"]))
+                .trim()
+                .to_owned();
+
+        let initial_target_dir = Path::new(&initial_target_libdir)
+            .parent()
+            .unwrap_or_else(|| panic!("{initial_target_libdir} has no parent"));
 
-        let initial_target_dir = Path::new(&initial_target_libdir_str).parent().unwrap();
         let initial_lld = initial_target_dir.join("bin").join("rust-lld");
 
-        let initial_relative_libdir = initial_target_dir
-            .ancestors()
-            .nth(2)
-            .unwrap()
-            .strip_prefix(&config.initial_sysroot)
-            .expect("Couldn’t determine initial relative libdir.")
-            .to_path_buf();
+        let initial_relative_libdir = if cfg!(test) {
+            // On tests, bootstrap uses the shim rustc, not the one from the stage0 toolchain.
+            PathBuf::default()
+        } else {
+            let ancestor = initial_target_dir.ancestors().nth(2).unwrap_or_else(|| {
+                panic!("Not enough ancestors for {}", initial_target_dir.display())
+            });
+
+            ancestor
+                .strip_prefix(&config.initial_sysroot)
+                .unwrap_or_else(|_| {
+                    panic!(
+                        "Couldn’t resolve the initial relative libdir from {}",
+                        initial_target_dir.display()
+                    )
+                })
+                .to_path_buf()
+        };
 
         let version = std::fs::read_to_string(src.join("src").join("version"))
             .expect("failed to read src/version");
@@ -1088,8 +1117,15 @@ Executed at: {executed_at}"#,
         &self,
         what: impl Display,
         target: impl Into<Option<TargetSelection>>,
+        custom_stage: Option<u32>,
     ) -> Option<gha::Group> {
-        self.msg(Kind::Check, self.config.stage, what, self.config.build, target)
+        self.msg(
+            Kind::Check,
+            custom_stage.unwrap_or(self.config.stage),
+            what,
+            self.config.build,
+            target,
+        )
     }
 
     #[must_use = "Groups should not be dropped until the Step finishes running"]
@@ -1194,7 +1230,7 @@ Executed at: {executed_at}"#,
         })
     }
 
-    fn debuginfo_map_to(&self, which: GitRepo) -> Option<String> {
+    fn debuginfo_map_to(&self, which: GitRepo, remap_scheme: RemapScheme) -> Option<String> {
         if !self.config.rust_remap_debuginfo {
             return None;
         }
@@ -1202,7 +1238,24 @@ Executed at: {executed_at}"#,
         match which {
             GitRepo::Rustc => {
                 let sha = self.rust_sha().unwrap_or(&self.version);
-                Some(format!("/rustc/{sha}"))
+
+                match remap_scheme {
+                    RemapScheme::Compiler => {
+                        // For compiler sources, remap via `/rustc-dev/{sha}` to allow
+                        // distinguishing between compiler sources vs library sources, since
+                        // `rustc-dev` dist component places them under
+                        // `$sysroot/lib/rustlib/rustc-src/rust` as opposed to `rust-src`'s
+                        // `$sysroot/lib/rustlib/src/rust`.
+                        //
+                        // Keep this scheme in sync with `rustc_metadata::rmeta::decoder`'s
+                        // `try_to_translate_virtual_to_real`.
+                        Some(format!("/rustc-dev/{sha}"))
+                    }
+                    RemapScheme::NonCompiler => {
+                        // For non-compiler sources, use `/rustc/{sha}` remapping scheme.
+                        Some(format!("/rustc/{sha}"))
+                    }
+                }
             }
             GitRepo::Llvm => Some(String::from("/rustc/llvm")),
         }
@@ -1269,7 +1322,7 @@ Executed at: {executed_at}"#,
             base.push("-fno-omit-frame-pointer".into());
         }
 
-        if let Some(map_to) = self.debuginfo_map_to(which) {
+        if let Some(map_to) = self.debuginfo_map_to(which, RemapScheme::NonCompiler) {
             let map = format!("{}={}", self.src.display(), map_to);
             let cc = self.cc(target);
             if cc.ends_with("clang") || cc.ends_with("gcc") {
@@ -1435,23 +1488,23 @@ Executed at: {executed_at}"#,
         // Look for Wasmtime, and for its default options be sure to disable
         // its caching system since we're executing quite a lot of tests and
         // ideally shouldn't pollute the cache too much.
-        if let Some(path) = finder.maybe_have("wasmtime") {
-            if let Ok(mut path) = path.into_os_string().into_string() {
-                path.push_str(" run -C cache=n --dir .");
-                // Make sure that tests have access to RUSTC_BOOTSTRAP. This (for example) is
-                // required for libtest to work on beta/stable channels.
-                //
-                // NB: with Wasmtime 20 this can change to `-S inherit-env` to
-                // inherit the entire environment rather than just this single
-                // environment variable.
-                path.push_str(" --env RUSTC_BOOTSTRAP");
-
-                if target.contains("wasip2") {
-                    path.push_str(" --wasi inherit-network --wasi allow-ip-name-lookup");
-                }
-
-                return Some(path);
+        if let Some(path) = finder.maybe_have("wasmtime")
+            && let Ok(mut path) = path.into_os_string().into_string()
+        {
+            path.push_str(" run -C cache=n --dir .");
+            // Make sure that tests have access to RUSTC_BOOTSTRAP. This (for example) is
+            // required for libtest to work on beta/stable channels.
+            //
+            // NB: with Wasmtime 20 this can change to `-S inherit-env` to
+            // inherit the entire environment rather than just this single
+            // environment variable.
+            path.push_str(" --env RUSTC_BOOTSTRAP");
+
+            if target.contains("wasip2") {
+                path.push_str(" --wasi inherit-network --wasi allow-ip-name-lookup");
             }
+
+            return Some(path);
         }
 
         None
@@ -1621,12 +1674,12 @@ Executed at: {executed_at}"#,
     /// sha, version, etc.
     fn rust_version(&self) -> String {
         let mut version = self.rust_info().version(self, &self.version);
-        if let Some(ref s) = self.config.description {
-            if !s.is_empty() {
-                version.push_str(" (");
-                version.push_str(s);
-                version.push(')');
-            }
+        if let Some(ref s) = self.config.description
+            && !s.is_empty()
+        {
+            version.push_str(" (");
+            version.push_str(s);
+            version.push(')');
         }
         version
     }
@@ -1744,14 +1797,14 @@ Executed at: {executed_at}"#,
     pub fn copy_link(&self, src: &Path, dst: &Path, file_type: FileType) {
         self.copy_link_internal(src, dst, false);
 
-        if file_type.could_have_split_debuginfo() {
-            if let Some(dbg_file) = split_debuginfo(src) {
-                self.copy_link_internal(
-                    &dbg_file,
-                    &dst.with_extension(dbg_file.extension().unwrap()),
-                    false,
-                );
-            }
+        if file_type.could_have_split_debuginfo()
+            && let Some(dbg_file) = split_debuginfo(src)
+        {
+            self.copy_link_internal(
+                &dbg_file,
+                &dst.with_extension(dbg_file.extension().unwrap()),
+                false,
+            );
         }
     }
 
@@ -1763,19 +1816,21 @@ Executed at: {executed_at}"#,
         if src == dst {
             return;
         }
-        if let Err(e) = fs::remove_file(dst) {
-            if cfg!(windows) && e.kind() != io::ErrorKind::NotFound {
-                // workaround for https://github.com/rust-lang/rust/issues/127126
-                // if removing the file fails, attempt to rename it instead.
-                let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH));
-                let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos()));
-            }
+        if let Err(e) = fs::remove_file(dst)
+            && cfg!(windows)
+            && e.kind() != io::ErrorKind::NotFound
+        {
+            // workaround for https://github.com/rust-lang/rust/issues/127126
+            // if removing the file fails, attempt to rename it instead.
+            let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH));
+            let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos()));
         }
-        let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display()));
+        let mut metadata = t!(src.symlink_metadata(), format!("src = {}", src.display()));
         let mut src = src.to_path_buf();
         if metadata.file_type().is_symlink() {
             if dereference_symlinks {
                 src = t!(fs::canonicalize(src));
+                metadata = t!(fs::metadata(&src), format!("target = {}", src.display()));
             } else {
                 let link = t!(fs::read_link(src));
                 t!(self.symlink_file(link, dst));
@@ -1878,10 +1933,10 @@ Executed at: {executed_at}"#,
         chmod(&dst, file_type.perms());
 
         // If this file can have debuginfo, look for split debuginfo and install it too.
-        if file_type.could_have_split_debuginfo() {
-            if let Some(dbg_file) = split_debuginfo(src) {
-                self.install(&dbg_file, dstdir, FileType::Regular);
-            }
+        if file_type.could_have_split_debuginfo()
+            && let Some(dbg_file) = split_debuginfo(src)
+        {
+            self.install(&dbg_file, dstdir, FileType::Regular);
         }
     }
 
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index ceac24d4315..5c9e30706ee 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -22,43 +22,13 @@
 //! everything.
 
 use std::collections::HashSet;
+use std::iter;
 use std::path::{Path, PathBuf};
-use std::{env, iter};
 
 use crate::core::config::TargetSelection;
 use crate::utils::exec::{BootstrapCommand, command};
 use crate::{Build, CLang, GitRepo};
 
-/// Finds archiver tool for the given target if possible.
-/// FIXME(onur-ozkan): This logic should be replaced by calling into the `cc` crate.
-fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option<PathBuf> {
-    if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace('-', "_"))) {
-        Some(PathBuf::from(ar))
-    } else if let Some(ar) = env::var_os("AR") {
-        Some(PathBuf::from(ar))
-    } else if target.is_msvc() {
-        None
-    } else if target.contains("musl") || target.contains("openbsd") {
-        Some(PathBuf::from("ar"))
-    } else if target.contains("vxworks") {
-        Some(PathBuf::from("wr-ar"))
-    } else if target.contains("-nto-") {
-        if target.starts_with("i586") {
-            Some(PathBuf::from("ntox86-ar"))
-        } else if target.starts_with("aarch64") {
-            Some(PathBuf::from("ntoaarch64-ar"))
-        } else if target.starts_with("x86_64") {
-            Some(PathBuf::from("ntox86_64-ar"))
-        } else {
-            panic!("Unknown architecture, cannot determine archiver for Neutrino QNX");
-        }
-    } else if target.contains("android") || target.contains("-wasi") {
-        Some(cc.parent().unwrap().join(PathBuf::from("llvm-ar")))
-    } else {
-        Some(default_ar)
-    }
-}
-
 /// Creates and configures a new [`cc::Build`] instance for the given target.
 fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
     let mut cfg = cc::Build::new();
@@ -140,7 +110,7 @@ pub fn find_target(build: &Build, target: TargetSelection) {
     let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
         ar
     } else {
-        cc2ar(compiler.path(), target, PathBuf::from(cfg.get_archiver().get_program()))
+        cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok()
     };
 
     build.cc.borrow_mut().insert(target, compiler.clone());
diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs
index 43d61ce02c5..225fb7619b5 100644
--- a/src/bootstrap/src/utils/cc_detect/tests.rs
+++ b/src/bootstrap/src/utils/cc_detect/tests.rs
@@ -6,119 +6,6 @@ use crate::core::config::{Target, TargetSelection};
 use crate::{Build, Config, Flags};
 
 #[test]
-fn test_cc2ar_env_specific() {
-    let triple = "x86_64-unknown-linux-gnu";
-    let key = "AR_x86_64_unknown_linux_gnu";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::set_var(key, "custom-ar") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var(key) };
-    assert_eq!(result, Some(PathBuf::from("custom-ar")));
-}
-
-#[test]
-fn test_cc2ar_musl() {
-    let triple = "x86_64-unknown-linux-musl";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_x86_64_unknown_linux_musl") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ar")));
-}
-
-#[test]
-fn test_cc2ar_openbsd() {
-    let triple = "x86_64-unknown-openbsd";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_x86_64_unknown_openbsd") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/cc");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ar")));
-}
-
-#[test]
-fn test_cc2ar_vxworks() {
-    let triple = "armv7-wrs-vxworks";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_armv7_wrs_vxworks") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("wr-ar")));
-}
-
-#[test]
-fn test_cc2ar_nto_i586() {
-    let triple = "i586-unknown-nto-something";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_i586_unknown_nto_something") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ntox86-ar")));
-}
-
-#[test]
-fn test_cc2ar_nto_aarch64() {
-    let triple = "aarch64-unknown-nto-something";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_aarch64_unknown_nto_something") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ntoaarch64-ar")));
-}
-
-#[test]
-fn test_cc2ar_nto_x86_64() {
-    let triple = "x86_64-unknown-nto-something";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_x86_64_unknown_nto_something") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let result = cc2ar(cc, target, default_ar);
-    assert_eq!(result, Some(PathBuf::from("ntox86_64-ar")));
-}
-
-#[test]
-#[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")]
-fn test_cc2ar_nto_unknown() {
-    let triple = "powerpc-unknown-nto-something";
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR_powerpc_unknown_nto_something") };
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::remove_var("AR") };
-    let target = TargetSelection::from_user(triple);
-    let cc = Path::new("/usr/bin/clang");
-    let default_ar = PathBuf::from("default-ar");
-    let _ = cc2ar(cc, target, default_ar);
-}
-
-#[test]
 fn test_ndk_compiler_c() {
     let ndk_path = PathBuf::from("/ndk");
     let target_triple = "arm-unknown-linux-android";
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 1d0ea3ebf61..e939a8362ad 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -46,10 +46,10 @@ pub fn find_recent_config_change_ids(current_id: usize) -> &'static [ChangeInfo]
         // an empty list (it may be due to switching from a recent branch to an
         // older one); otherwise, return the full list (assuming the user provided
         // the incorrect change-id by accident).
-        if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id) {
-            if current_id > config.change_id {
-                return &[];
-            }
+        if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id)
+            && current_id > config.change_id
+        {
+            return &[];
         }
 
         CONFIG_CHANGE_HISTORY
@@ -411,4 +411,14 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "`./x run` now supports running in-tree `rustfmt`, e.g., `./x run rustfmt -- --check /path/to/file.rs`.",
     },
+    ChangeInfo {
+        change_id: 119899,
+        severity: ChangeSeverity::Warning,
+        summary: "Stage0 library no longer matches the in-tree library, which means stage1 compiler now uses the beta library.",
+    },
+    ChangeInfo {
+        change_id: 141970,
+        severity: ChangeSeverity::Info,
+        summary: "Added new bootstrap flag `--skip-std-check-if-no-download-rustc` that skips std checks when download-rustc is unavailable. Mainly intended for developers to reduce RA overhead.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index d07300e21d0..64e46f10563 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -332,16 +332,19 @@ impl Default for CommandOutput {
 
 /// Helper trait to format both Command and BootstrapCommand as a short execution line,
 /// without all the other details (e.g. environment variables).
+#[cfg(feature = "tracing")]
 pub trait FormatShortCmd {
     fn format_short_cmd(&self) -> String;
 }
 
+#[cfg(feature = "tracing")]
 impl FormatShortCmd for BootstrapCommand {
     fn format_short_cmd(&self) -> String {
         self.command.format_short_cmd()
     }
 }
 
+#[cfg(feature = "tracing")]
 impl FormatShortCmd for Command {
     fn format_short_cmd(&self) -> String {
         let program = Path::new(self.get_program());
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
index 08e1c21e58e..561af34a447 100644
--- a/src/bootstrap/src/utils/shared_helpers.rs
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -46,7 +46,16 @@ pub fn dylib_path() -> Vec<std::path::PathBuf> {
 /// Given an executable called `name`, return the filename for the
 /// executable for a particular target.
 pub fn exe(name: &str, target: &str) -> String {
-    if target.contains("windows") {
+    // On Cygwin, the decision to append .exe or not is not as straightforward.
+    // Executable files do actually have .exe extensions so on hosts other than
+    // Cygwin it is necessary.  But on a Cygwin host there is magic happening
+    // that redirects requests for file X to file X.exe if it exists, and
+    // furthermore /proc/self/exe (and thus std::env::current_exe) always
+    // returns the name *without* the .exe extension.  For comparisons against
+    // that to match, we therefore do not append .exe for Cygwin targets on
+    // a Cygwin host.
+    if target.contains("windows") || (cfg!(not(target_os = "cygwin")) && target.contains("cygwin"))
+    {
         format!("{name}.exe")
     } else if target.contains("uefi") {
         format!("{name}.efi")