about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2024-12-31 05:12:50 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2024-12-31 05:12:50 +0000
commite898da11d2149358e87f7c4f89dcc0654fcfac3b (patch)
tree6f09bd54aead12fa9e0155cda3dcb7e0f46f97ae /src
parent332fefbd3e686d0d76a43119e374997543338389 (diff)
parent5079acc060b1c7225de95ee3cdd84b5719ff189c (diff)
downloadrust-e898da11d2149358e87f7c4f89dcc0654fcfac3b.tar.gz
rust-e898da11d2149358e87f7c4f89dcc0654fcfac3b.zip
Merge from rustc
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/src/bin/rustc.rs5
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs10
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs225
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs7
-rw-r--r--src/bootstrap/src/core/builder/mod.rs1
-rw-r--r--src/bootstrap/src/core/builder/tests.rs2
-rw-r--r--src/bootstrap/src/core/config/config.rs37
-rw-r--r--src/bootstrap/src/core/config/flags.rs10
-rw-r--r--src/bootstrap/src/core/download.rs17
-rw-r--r--src/bootstrap/src/core/sanity.rs11
-rw-r--r--src/bootstrap/src/lib.rs7
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs10
-rw-r--r--src/bootstrap/src/utils/mod.rs2
-rw-r--r--src/bootstrap/src/utils/proc_macro_deps.rs71
-rw-r--r--src/bootstrap/src/utils/shared_helpers.rs5
-rw-r--r--src/bootstrap/src/utils/tarball.rs2
-rw-r--r--src/bootstrap/src/utils/tests/mod.rs1
-rw-r--r--src/bootstrap/src/utils/tests/shared_helpers_tests.rs (renamed from src/bootstrap/src/utils/shared_helpers/tests.rs)9
-rw-r--r--src/ci/docker/README.md6
-rw-r--r--src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile7
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh1
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh5
-rwxr-xr-xsrc/ci/docker/run.sh3
-rwxr-xr-xsrc/ci/scripts/install-clang.sh2
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md108
-rw-r--r--src/doc/rustc/src/platform-support/android.md2
-rw-r--r--src/doc/rustc/src/platform-support/illumos.md42
-rw-r--r--src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md2
-rw-r--r--src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md5
-rw-r--r--src/doc/rustc/src/targets/custom.md4
-rw-r--r--src/doc/rustdoc/src/write-documentation/documentation-tests.md2
-rw-r--r--src/doc/unstable-book/src/language-features/rustc-private.md7
-rw-r--r--src/etc/completions/x.fish1
-rw-r--r--src/etc/completions/x.ps11
-rw-r--r--src/etc/completions/x.py.fish1
-rw-r--r--src/etc/completions/x.py.ps11
-rw-r--r--src/etc/completions/x.py.sh2
-rw-r--r--src/etc/completions/x.py.zsh1
-rw-r--r--src/etc/completions/x.sh2
-rw-r--r--src/etc/completions/x.zsh1
-rw-r--r--src/etc/test-float-parse/README.md2
-rw-r--r--src/etc/test-float-parse/src/lib.rs8
-rw-r--r--src/librustdoc/clean/mod.rs28
-rw-r--r--src/librustdoc/doctest.rs2
-rw-r--r--src/librustdoc/doctest/make.rs2
-rw-r--r--src/librustdoc/formats/cache.rs21
-rw-r--r--src/librustdoc/html/escape.rs7
-rw-r--r--src/librustdoc/html/markdown.rs6
-rw-r--r--src/librustdoc/html/render/context.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs2
-rw-r--r--src/librustdoc/json/conversions.rs11
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/tools/compiletest/src/directive-list.rs4
-rw-r--r--src/tools/compiletest/src/header.rs75
-rw-r--r--src/tools/compiletest/src/header/cfg.rs4
-rw-r--r--src/tools/compiletest/src/header/tests.rs25
-rw-r--r--src/tools/compiletest/src/lib.rs8
-rw-r--r--src/tools/compiletest/src/runtest.rs99
-rw-r--r--src/tools/compiletest/src/runtest/coverage.rs12
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs25
-rw-r--r--src/tools/compiletest/src/runtest/debuginfo.rs12
-rw-r--r--src/tools/compiletest/src/runtest/ui.rs7
-rw-r--r--src/tools/linkchecker/main.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr (renamed from src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr)4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr20
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs10
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs13
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.stderr15
-rw-r--r--src/tools/nix-dev-shell/envrc-flake2
-rw-r--r--src/tools/nix-dev-shell/envrc-shell2
-rw-r--r--src/tools/rustbook/Cargo.lock28
-rw-r--r--src/tools/rustc-perf-wrapper/src/main.rs4
-rw-r--r--src/tools/suggest-tests/src/static_suggestions.rs2
-rw-r--r--src/tools/tidy/Cargo.toml2
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt3
-rw-r--r--src/tools/tidy/src/deps.rs75
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--src/tools/tidy/src/style.rs7
86 files changed, 792 insertions, 419 deletions
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 6da716b7a89..d8775a67e19 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -7,7 +7,6 @@ default-run = "bootstrap"
 
 [features]
 build-metrics = ["sysinfo"]
-bootstrap-self-test = [] # enabled in the bootstrap unit tests
 
 [lib]
 path = "src/lib.rs"
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 88595ff7e51..61045067592 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -28,6 +28,9 @@ use shared_helpers::{
 #[path = "../utils/shared_helpers.rs"]
 mod shared_helpers;
 
+#[path = "../utils/proc_macro_deps.rs"]
+mod proc_macro_deps;
+
 fn main() {
     let orig_args = env::args_os().skip(1).collect::<Vec<_>>();
     let mut args = orig_args.clone();
@@ -167,7 +170,7 @@ fn main() {
         // issue https://github.com/rust-lang/rust/issues/100530
         if env::var("RUSTC_TLS_MODEL_INITIAL_EXEC").is_ok()
             && crate_type != Some("proc-macro")
-            && !matches!(crate_name, Some("proc_macro2" | "quote" | "syn" | "synstructure"))
+            && proc_macro_deps::CRATES.binary_search(&crate_name.unwrap_or_default()).is_err()
         {
             cmd.arg("-Ztls-model=initial-exec");
         }
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index f32d95fe836..b4d37b25a6c 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -501,6 +501,9 @@ tool_check_step!(
 );
 
 tool_check_step!(Bootstrap, "bootstrap", "src/bootstrap", SourceType::InTree, false);
+// Compiletest is implicitly "checked" when it gets built in order to run tests,
+// so this is mainly for people working on compiletest to run locally.
+tool_check_step!(Compiletest, "compiletest", "src/tools/compiletest", SourceType::InTree, false);
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index d30a0d028ff..ca337aa9f4c 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -396,7 +396,7 @@ fn copy_self_contained_objects(
 /// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.).
 pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec<String> {
     // FIXME: Extend builder tests to cover the `crates` field of `Std` instances.
-    if cfg!(feature = "bootstrap-self-test") {
+    if cfg!(test) {
         return vec![];
     }
 
@@ -984,6 +984,7 @@ impl Step for Rustc {
             true, // Only ship rustc_driver.so and .rmeta files, not all intermediate .rlib files.
         );
 
+        let target_root_dir = stamp.parent().unwrap();
         // When building `librustc_driver.so` (like `libLLVM.so`) on linux, it can contain
         // unexpected debuginfo from dependencies, for example from the C++ standard library used in
         // our LLVM wrapper. Unless we're explicitly requesting `librustc_driver` to be built with
@@ -992,11 +993,16 @@ impl Step for Rustc {
         if builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None
             && builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None
         {
-            let target_root_dir = stamp.parent().unwrap();
             let rustc_driver = target_root_dir.join("librustc_driver.so");
             strip_debug(builder, target, &rustc_driver);
         }
 
+        if builder.config.rust_debuginfo_level_rustc == DebuginfoLevel::None {
+            // Due to LTO a lot of debug info from C++ dependencies such as jemalloc can make it into
+            // our final binaries
+            strip_debug(builder, target, &target_root_dir.join("rustc-main"));
+        }
+
         builder.ensure(RustcLink::from_rustc(
             self,
             builder.compiler(compiler.stage, builder.config.build),
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 636c88b099b..6aa6e4e277d 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1133,69 +1133,21 @@ fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf {
     builder.out.join(host).join("test")
 }
 
-macro_rules! default_test {
-    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
-        test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: false });
-    };
-}
-
-macro_rules! default_test_with_compare_mode {
-    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr,
-                   compare_mode: $compare_mode:expr }) => {
-        test_with_compare_mode!($name {
-            path: $path,
-            mode: $mode,
-            suite: $suite,
-            default: true,
-            host: false,
-            compare_mode: $compare_mode
-        });
-    };
-}
-
-macro_rules! host_test {
-    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
-        test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true });
-    };
-}
-
+/// Declares a test step that invokes compiletest on a particular test suite.
 macro_rules! test {
-    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
-                   host: $host:expr }) => {
-        test_definitions!($name {
-            path: $path,
-            mode: $mode,
-            suite: $suite,
-            default: $default,
-            host: $host,
-            compare_mode: None
-        });
-    };
-}
-
-macro_rules! test_with_compare_mode {
-    ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
-                   host: $host:expr, compare_mode: $compare_mode:expr }) => {
-        test_definitions!($name {
-            path: $path,
-            mode: $mode,
-            suite: $suite,
-            default: $default,
-            host: $host,
-            compare_mode: Some($compare_mode)
-        });
-    };
-}
-
-macro_rules! test_definitions {
-    ($name:ident {
-        path: $path:expr,
-        mode: $mode:expr,
-        suite: $suite:expr,
-        default: $default:expr,
-        host: $host:expr,
-        compare_mode: $compare_mode:expr
-    }) => {
+    (
+        $( #[$attr:meta] )* // allow docstrings and attributes
+        $name:ident {
+            path: $path:expr,
+            mode: $mode:expr,
+            suite: $suite:expr,
+            default: $default:expr
+            $( , only_hosts: $only_hosts:expr )? // default: false
+            $( , compare_mode: $compare_mode:expr )? // default: None
+            $( , )? // optional trailing comma
+        }
+    ) => {
+        $( #[$attr] )*
         #[derive(Debug, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
             pub compiler: Compiler,
@@ -1205,7 +1157,12 @@ macro_rules! test_definitions {
         impl Step for $name {
             type Output = ();
             const DEFAULT: bool = $default;
-            const ONLY_HOSTS: bool = $host;
+            const ONLY_HOSTS: bool = (const {
+                #[allow(unused_assignments, unused_mut)]
+                let mut value = false;
+                $( value = $only_hosts; )?
+                value
+            });
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                 run.suite_path($path)
@@ -1224,7 +1181,12 @@ macro_rules! test_definitions {
                     mode: $mode,
                     suite: $suite,
                     path: $path,
-                    compare_mode: $compare_mode,
+                    compare_mode: (const {
+                        #[allow(unused_assignments, unused_mut)]
+                        let mut value = None;
+                        $( value = $compare_mode; )?
+                        value
+                    }),
                 })
             }
         }
@@ -1232,13 +1194,18 @@ macro_rules! test_definitions {
 }
 
 /// Declares an alias for running the [`Coverage`] tests in only one mode.
-/// Adapted from [`test_definitions`].
+/// Adapted from [`test`].
 macro_rules! coverage_test_alias {
-    ($name:ident {
-        alias_and_mode: $alias_and_mode:expr, // &'static str
-        default: $default:expr, // bool
-        only_hosts: $only_hosts:expr $(,)? // bool
-    }) => {
+    (
+        $( #[$attr:meta] )* // allow docstrings and attributes
+        $name:ident {
+            alias_and_mode: $alias_and_mode:expr, // &'static str
+            default: $default:expr, // bool
+            only_hosts: $only_hosts:expr // bool
+            $( , )? // optional trailing comma
+        }
+    ) => {
+        $( #[$attr] )*
         #[derive(Debug, Clone, PartialEq, Eq, Hash)]
         pub struct $name {
             pub compiler: Compiler,
@@ -1410,37 +1377,74 @@ impl Step for CrateBuildHelper {
     }
 }
 
-default_test!(Ui { path: "tests/ui", mode: "ui", suite: "ui" });
+test!(Ui { path: "tests/ui", mode: "ui", suite: "ui", default: true });
 
-default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" });
+test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes", default: true });
 
-default_test!(Codegen { path: "tests/codegen", mode: "codegen", suite: "codegen" });
+test!(Codegen { path: "tests/codegen", mode: "codegen", suite: "codegen", default: true });
 
-default_test!(CodegenUnits {
+test!(CodegenUnits {
     path: "tests/codegen-units",
     mode: "codegen-units",
-    suite: "codegen-units"
+    suite: "codegen-units",
+    default: true,
 });
 
-default_test!(Incremental { path: "tests/incremental", mode: "incremental", suite: "incremental" });
+test!(Incremental {
+    path: "tests/incremental",
+    mode: "incremental",
+    suite: "incremental",
+    default: true,
+});
 
-default_test_with_compare_mode!(Debuginfo {
+test!(Debuginfo {
     path: "tests/debuginfo",
     mode: "debuginfo",
     suite: "debuginfo",
-    compare_mode: "split-dwarf"
+    default: true,
+    compare_mode: Some("split-dwarf"),
 });
 
-host_test!(UiFullDeps { path: "tests/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" });
+test!(UiFullDeps {
+    path: "tests/ui-fulldeps",
+    mode: "ui",
+    suite: "ui-fulldeps",
+    default: true,
+    only_hosts: true,
+});
 
-host_test!(Rustdoc { path: "tests/rustdoc", mode: "rustdoc", suite: "rustdoc" });
-host_test!(RustdocUi { path: "tests/rustdoc-ui", mode: "ui", suite: "rustdoc-ui" });
+test!(Rustdoc {
+    path: "tests/rustdoc",
+    mode: "rustdoc",
+    suite: "rustdoc",
+    default: true,
+    only_hosts: true,
+});
+test!(RustdocUi {
+    path: "tests/rustdoc-ui",
+    mode: "ui",
+    suite: "rustdoc-ui",
+    default: true,
+    only_hosts: true,
+});
 
-host_test!(RustdocJson { path: "tests/rustdoc-json", mode: "rustdoc-json", suite: "rustdoc-json" });
+test!(RustdocJson {
+    path: "tests/rustdoc-json",
+    mode: "rustdoc-json",
+    suite: "rustdoc-json",
+    default: true,
+    only_hosts: true,
+});
 
-host_test!(Pretty { path: "tests/pretty", mode: "pretty", suite: "pretty" });
+test!(Pretty {
+    path: "tests/pretty",
+    mode: "pretty",
+    suite: "pretty",
+    default: true,
+    only_hosts: true,
+});
 
-/// Special-handling is needed for `run-make`, so don't use `default_test` for defining `RunMake`
+/// Special-handling is needed for `run-make`, so don't use `test!` for defining `RunMake`
 /// tests.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct RunMake {
@@ -1475,7 +1479,7 @@ impl Step for RunMake {
     }
 }
 
-default_test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly" });
+test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly", default: true });
 
 /// Coverage tests are a bit more complicated than other test suites, because
 /// we want to run the same set of test files in multiple different modes,
@@ -1552,27 +1556,33 @@ impl Step for Coverage {
     }
 }
 
-// Runs `tests/coverage` in "coverage-map" mode only.
-// Used by `x test` and `x test coverage-map`.
-coverage_test_alias!(CoverageMap {
-    alias_and_mode: "coverage-map",
-    default: true,
-    only_hosts: false,
-});
-// Runs `tests/coverage` in "coverage-run" mode only.
-// Used by `x test` and `x test coverage-run`.
-coverage_test_alias!(CoverageRun {
-    alias_and_mode: "coverage-run",
-    default: true,
-    // Compiletest knows how to automatically skip these tests when cross-compiling,
-    // but skipping the whole step here makes it clearer that they haven't run at all.
-    only_hosts: true,
-});
+coverage_test_alias! {
+    /// Runs the `tests/coverage` test suite in "coverage-map" mode only.
+    /// Used by `x test` and `x test coverage-map`.
+    CoverageMap {
+        alias_and_mode: "coverage-map",
+        default: true,
+        only_hosts: false,
+    }
+}
+coverage_test_alias! {
+    /// Runs the `tests/coverage` test suite in "coverage-run" mode only.
+    /// Used by `x test` and `x test coverage-run`.
+    CoverageRun {
+        alias_and_mode: "coverage-run",
+        default: true,
+        // Compiletest knows how to automatically skip these tests when cross-compiling,
+        // but skipping the whole step here makes it clearer that they haven't run at all.
+        only_hosts: true,
+    }
+}
 
-host_test!(CoverageRunRustdoc {
+test!(CoverageRunRustdoc {
     path: "tests/coverage-run-rustdoc",
     mode: "coverage-run",
-    suite: "coverage-run-rustdoc"
+    suite: "coverage-run-rustdoc",
+    default: true,
+    only_hosts: true,
 });
 
 // For the mir-opt suite we do not use macros, as we need custom behavior when blessing.
@@ -1829,6 +1839,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             cmd.arg("--force-rerun");
         }
 
+        if builder.config.cmd.no_capture() {
+            cmd.arg("--no-capture");
+        }
+
         let compare_mode =
             builder.config.cmd.compare_mode().or_else(|| {
                 if builder.config.test_compare_mode { self.compare_mode } else { None }
@@ -2623,7 +2637,7 @@ fn prepare_cargo_test(
 ) -> BootstrapCommand {
     let mut cargo = cargo.into();
 
-    // Propegate `--bless` if it has not already been set/unset
+    // Propagate `--bless` if it has not already been set/unset
     // Any tools that want to use this should bless if `RUSTC_BLESS` is set to
     // anything other than `0`.
     if builder.config.cmd.bless() && !cargo.get_envs().any(|v| v.0 == "RUSTC_BLESS") {
@@ -3148,9 +3162,8 @@ impl Step for Bootstrap {
 
         let mut cmd = command(&builder.initial_cargo);
         cmd.arg("test")
-            .args(["--features", "bootstrap-self-test"])
             .current_dir(builder.src.join("src/bootstrap"))
-            .env("RUSTFLAGS", "-Cdebuginfo=2")
+            .env("RUSTFLAGS", "--cfg test -Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
             .env("RUSTC_BOOTSTRAP", "1")
             .env("RUSTDOC", builder.rustdoc(compiler))
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 04f1e10f493..6b809a52bd2 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -5,7 +5,7 @@ use crate::core::build_steps::toolstate::ToolState;
 use crate::core::build_steps::{compile, llvm};
 use crate::core::builder;
 use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
-use crate::core::config::TargetSelection;
+use crate::core::config::{DebuginfoLevel, TargetSelection};
 use crate::utils::channel::GitInfo;
 use crate::utils::exec::{BootstrapCommand, command};
 use crate::utils::helpers::{add_dylib_path, exe, t};
@@ -671,6 +671,11 @@ impl Step for Rustdoc {
 
         // don't create a stage0-sysroot/bin directory.
         if target_compiler.stage > 0 {
+            if builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None {
+                // Due to LTO a lot of debug info from C++ dependencies such as jemalloc can make it into
+                // our final binaries
+                compile::strip_debug(builder, target, &tool_rustdoc);
+            }
             let bin_rustdoc = bin_rustdoc();
             builder.copy_link(&tool_rustdoc, &bin_rustdoc);
             bin_rustdoc
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 98f765dbd0f..18beaf3676d 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -905,6 +905,7 @@ impl<'a> Builder<'a> {
                 check::RustAnalyzer,
                 check::TestFloatParse,
                 check::Bootstrap,
+                check::Compiletest,
             ),
             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 819a552093b..a0acd839374 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -637,6 +637,7 @@ mod dist {
             run: None,
             only_modified: false,
             extra_checks: None,
+            no_capture: false,
         };
 
         let build = Build::new(config);
@@ -702,6 +703,7 @@ mod dist {
             run: None,
             only_modified: false,
             extra_checks: None,
+            no_capture: false,
         };
         // Make sure rustfmt binary not being found isn't an error.
         config.channel = "beta".to_string();
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 435216ef534..dd2f11ad469 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1154,7 +1154,6 @@ define_config! {
         debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests",
         backtrace: Option<bool> = "backtrace",
         incremental: Option<bool> = "incremental",
-        parallel_compiler: Option<bool> = "parallel-compiler",
         default_linker: Option<String> = "default-linker",
         channel: Option<String> = "channel",
         description: Option<String> = "description",
@@ -1325,23 +1324,14 @@ impl Config {
             .into_iter()
             .chain(flags.exclude)
             .map(|p| {
-                let p = if cfg!(windows) {
+                // Never return top-level path here as it would break `--skip`
+                // logic on rustc's internal test framework which is utilized
+                // by compiletest.
+                if cfg!(windows) {
                     PathBuf::from(p.to_str().unwrap().replace('/', "\\"))
                 } else {
                     p
-                };
-
-                // Jump to top-level project path to support passing paths
-                // from sub directories.
-                let top_level_path = config.src.join(&p);
-                if !config.src.join(&top_level_path).exists() {
-                    eprintln!("WARNING: '{}' does not exist.", top_level_path.display());
                 }
-
-                // Never return top-level path here as it would break `--skip`
-                // logic on rustc's internal test framework which is utilized
-                // by compiletest.
-                p
             })
             .collect();
 
@@ -1441,7 +1431,7 @@ impl Config {
         // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
         // but not if `config.toml` hasn't been created.
         let mut toml = if !using_default_path || toml_path.exists() {
-            config.config = Some(if cfg!(not(feature = "bootstrap-self-test")) {
+            config.config = Some(if cfg!(not(test)) {
                 toml_path.canonicalize().unwrap()
             } else {
                 toml_path.clone()
@@ -1764,7 +1754,6 @@ impl Config {
                 debuginfo_level_tests: debuginfo_level_tests_toml,
                 backtrace,
                 incremental,
-                parallel_compiler,
                 randomize_layout,
                 default_linker,
                 channel: _, // already handled above
@@ -1874,13 +1863,6 @@ impl Config {
             config.rust_randomize_layout = randomize_layout.unwrap_or_default();
             config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
 
-            // FIXME: Remove this option at the end of 2024.
-            if parallel_compiler.is_some() {
-                println!(
-                    "WARNING: The `rust.parallel-compiler` option is deprecated and does nothing. The parallel compiler (with one thread) is now the default"
-                );
-            }
-
             config.llvm_enzyme =
                 llvm_enzyme.unwrap_or(config.channel == "dev" || config.channel == "nightly");
             config.rustc_default_linker = default_linker;
@@ -2793,11 +2775,11 @@ impl Config {
         }
     }
 
-    #[cfg(feature = "bootstrap-self-test")]
+    #[cfg(test)]
     pub fn check_stage0_version(&self, _program_path: &Path, _component_name: &'static str) {}
 
     /// check rustc/cargo version is same or lower with 1 apart from the building one
-    #[cfg(not(feature = "bootstrap-self-test"))]
+    #[cfg(not(test))]
     pub fn check_stage0_version(&self, program_path: &Path, component_name: &'static str) {
         use build_helper::util::fail;
 
@@ -2939,7 +2921,7 @@ impl Config {
             }
 
             // Fetching the LLVM submodule is unnecessary for self-tests.
-            #[cfg(not(feature = "bootstrap-self-test"))]
+            #[cfg(not(test))]
             self.update_submodule("src/llvm-project");
 
             // Check for untracked changes in `src/llvm-project`.
@@ -3014,7 +2996,7 @@ impl 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(feature = "bootstrap-self-test"))]
+#[cfg(not(test))]
 pub(crate) fn check_incompatible_options_for_ci_llvm(
     current_config_toml: TomlConfig,
     ci_config_toml: TomlConfig,
@@ -3222,7 +3204,6 @@ fn check_incompatible_options_for_ci_rustc(
         debuginfo_level_tools: _,
         debuginfo_level_tests: _,
         backtrace: _,
-        parallel_compiler: _,
         musl_root: _,
         verbose_tests: _,
         optimize_tests: _,
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 00bcbe9f86d..f17103f97dc 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -388,6 +388,9 @@ pub enum Subcommand {
         /// enable this to generate a Rustfix coverage file, which is saved in
         /// `/<build_base>/rustfix_missing_coverage.txt`
         rustfix_coverage: bool,
+        #[arg(long)]
+        /// don't capture stdout/stderr of tests
+        no_capture: bool,
     },
     /// Build and run some test suites *in Miri*
     Miri {
@@ -563,6 +566,13 @@ impl Subcommand {
         }
     }
 
+    pub fn no_capture(&self) -> bool {
+        match *self {
+            Subcommand::Test { no_capture, .. } => no_capture,
+            _ => false,
+        }
+    }
+
     pub fn rustfix_coverage(&self) -> bool {
         match *self {
             Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index db35e6907e6..b5f7ed53131 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -197,8 +197,7 @@ impl Config {
         if !path_is_dylib(fname) {
             // Finally, set the correct .interp for binaries
             let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
-            // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ...
-            let dynamic_linker = t!(String::from_utf8(t!(fs::read(dynamic_linker_path))));
+            let dynamic_linker = t!(fs::read_to_string(dynamic_linker_path));
             patchelf.args(["--set-interpreter", dynamic_linker.trim_end()]);
         }
 
@@ -444,14 +443,14 @@ impl Config {
         cargo_clippy
     }
 
-    #[cfg(feature = "bootstrap-self-test")]
+    #[cfg(test)]
     pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
         None
     }
 
     /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't
     /// reuse target directories or artifacts
-    #[cfg(not(feature = "bootstrap-self-test"))]
+    #[cfg(not(test))]
     pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
         use build_helper::stage0_parser::VersionMetadata;
 
@@ -534,10 +533,10 @@ impl Config {
         );
     }
 
-    #[cfg(feature = "bootstrap-self-test")]
+    #[cfg(test)]
     pub(crate) fn download_beta_toolchain(&self) {}
 
-    #[cfg(not(feature = "bootstrap-self-test"))]
+    #[cfg(not(test))]
     pub(crate) fn download_beta_toolchain(&self) {
         self.verbose(|| println!("downloading stage0 beta artifacts"));
 
@@ -714,10 +713,10 @@ download-rustc = false
         self.unpack(&tarball, &bin_root, prefix);
     }
 
-    #[cfg(feature = "bootstrap-self-test")]
+    #[cfg(test)]
     pub(crate) fn maybe_download_ci_llvm(&self) {}
 
-    #[cfg(not(feature = "bootstrap-self-test"))]
+    #[cfg(not(test))]
     pub(crate) fn maybe_download_ci_llvm(&self) {
         use build_helper::exit;
 
@@ -789,7 +788,7 @@ download-rustc = false
         };
     }
 
-    #[cfg(not(feature = "bootstrap-self-test"))]
+    #[cfg(not(test))]
     fn download_ci_llvm(&self, llvm_sha: &str) {
         let llvm_assertions = self.llvm_assertions;
 
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index dcf68cbeeda..ed0155622c2 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -14,10 +14,10 @@ use std::path::PathBuf;
 use std::{env, fs};
 
 use crate::Build;
-#[cfg(not(feature = "bootstrap-self-test"))]
+#[cfg(not(test))]
 use crate::builder::Builder;
 use crate::builder::Kind;
-#[cfg(not(feature = "bootstrap-self-test"))]
+#[cfg(not(test))]
 use crate::core::build_steps::tool;
 use crate::core::config::Target;
 use crate::utils::exec::command;
@@ -38,7 +38,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
 /// from CI (with`llvm.download-ci-llvm` option).
-#[cfg(not(feature = "bootstrap-self-test"))]
+#[cfg(not(test))]
 const LIBSTDCXX_MIN_VERSION_THRESHOLD: usize = 8;
 
 impl Finder {
@@ -106,7 +106,7 @@ pub fn check(build: &mut Build) {
     }
 
     // Ensure that a compatible version of libstdc++ is available on the system when using `llvm.download-ci-llvm`.
-    #[cfg(not(feature = "bootstrap-self-test"))]
+    #[cfg(not(test))]
     if !build.config.dry_run() && !build.build.is_msvc() && build.config.llvm_from_ci {
         let builder = Builder::new(build);
         let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.build });
@@ -226,8 +226,7 @@ than building it.
         }
 
         // Ignore fake targets that are only used for unit tests in bootstrap.
-        if cfg!(not(feature = "bootstrap-self-test")) && !skip_target_sanity && !build.local_rebuild
-        {
+        if cfg!(not(test)) && !skip_target_sanity && !build.local_rebuild {
             let mut has_target = false;
             let target_str = target.to_string();
 
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 0ecf61ffcd9..4cc812829f9 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -635,11 +635,12 @@ impl Build {
         if self.config.backtrace {
             features.insert("backtrace");
         }
+
         if self.config.profiler_enabled(target) {
             features.insert("profiler");
         }
-        // Generate memcpy, etc.  FIXME: Remove this once compiler-builtins
-        // automatically detects this target.
+
+        // If zkvm target, generate memcpy, etc.
         if target.contains("zkvm") {
             features.insert("compiler-builtins-mem");
         }
@@ -1690,7 +1691,7 @@ Executed at: {executed_at}"#,
             }
         }
         if let Ok(()) = fs::hard_link(&src, dst) {
-            // Attempt to "easy copy" by creating a hard link (symlinks are priviledged on windows),
+            // Attempt to "easy copy" by creating a hard link (symlinks are privileged on windows),
             // but if that fails just fall back to a slow `copy` operation.
         } else {
             if let Err(e) = fs::copy(&src, dst) {
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index f4f189c718a..8fd6c8aa23a 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -315,4 +315,14 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "`build.vendor` is now enabled by default for dist/tarball sources when 'vendor' directory and '.cargo/config.toml' file are present.",
     },
+    ChangeInfo {
+        change_id: 134809,
+        severity: ChangeSeverity::Warning,
+        summary: "compiletest now takes `--no-capture` instead of `--nocapture`; bootstrap now accepts `--no-capture` as an argument to test commands directly",
+    },
+    ChangeInfo {
+        change_id: 134650,
+        severity: ChangeSeverity::Warning,
+        summary: "Removed `rust.parallel-compiler` as it was deprecated in #132282 long time ago.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs
index 53b41f15780..b5f5e2ba6dc 100644
--- a/src/bootstrap/src/utils/mod.rs
+++ b/src/bootstrap/src/utils/mod.rs
@@ -14,3 +14,5 @@ pub(crate) mod metrics;
 pub(crate) mod render_tests;
 pub(crate) mod shared_helpers;
 pub(crate) mod tarball;
+#[cfg(test)]
+mod tests;
diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs
new file mode 100644
index 00000000000..dbfd6f47dc6
--- /dev/null
+++ b/src/bootstrap/src/utils/proc_macro_deps.rs
@@ -0,0 +1,71 @@
+/// Do not update manually - use `./x.py test tidy --bless`
+/// Holds all direct and indirect dependencies of proc-macro crates in tree.
+/// See <https://github.com/rust-lang/rust/issues/134863>
+pub static CRATES: &[&str] = &[
+    // tidy-alphabetical-start
+    "annotate-snippets",
+    "anstyle",
+    "basic-toml",
+    "block-buffer",
+    "bumpalo",
+    "cfg-if",
+    "cpufeatures",
+    "crypto-common",
+    "darling",
+    "darling_core",
+    "derive_builder_core",
+    "digest",
+    "fluent-bundle",
+    "fluent-langneg",
+    "fluent-syntax",
+    "fnv",
+    "generic-array",
+    "heck",
+    "ident_case",
+    "intl-memoizer",
+    "intl_pluralrules",
+    "libc",
+    "log",
+    "memchr",
+    "mime",
+    "mime_guess",
+    "minimal-lexical",
+    "nom",
+    "num-conv",
+    "once_cell",
+    "pest",
+    "pest_generator",
+    "pest_meta",
+    "proc-macro2",
+    "quote",
+    "rinja_parser",
+    "rustc-hash",
+    "self_cell",
+    "serde",
+    "sha2",
+    "smallvec",
+    "stable_deref_trait",
+    "strsim",
+    "syn",
+    "synstructure",
+    "thiserror",
+    "time-core",
+    "tinystr",
+    "type-map",
+    "typenum",
+    "ucd-trie",
+    "unic-langid",
+    "unic-langid-impl",
+    "unic-langid-macros",
+    "unicase",
+    "unicode-ident",
+    "unicode-width",
+    "version_check",
+    "wasm-bindgen-backend",
+    "wasm-bindgen-macro-support",
+    "wasm-bindgen-shared",
+    "yoke",
+    "zerofrom",
+    "zerovec",
+    // tidy-alphabetical-end
+];
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
index 6d3c276cc05..7b206c3ffe8 100644
--- a/src/bootstrap/src/utils/shared_helpers.rs
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -13,8 +13,9 @@ use std::io::Write;
 use std::process::Command;
 use std::str::FromStr;
 
-#[cfg(test)]
-mod tests;
+// If we were to declare a tests submodule here, the shim binaries that include this
+// module via `#[path]` would fail to find it, which breaks `./x check bootstrap`.
+// So instead the unit tests for this module are in `super::tests::shared_helpers_tests`.
 
 /// Returns the environment variable which the dynamic library lookup path
 /// resides in for this platform.
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 3c6c7a7fa18..843ea65e838 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -1,7 +1,7 @@
 //! Facilitates the management and generation of tarballs.
 //!
 //! Tarballs efficiently hold Rust compiler build artifacts and
-//! capture a snapshot of each boostrap stage.
+//! capture a snapshot of each bootstrap stage.
 //! In uplifting, a tarball from Stage N captures essential components
 //! to assemble Stage N + 1 compiler.
 
diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs
new file mode 100644
index 00000000000..0791f7a6e20
--- /dev/null
+++ b/src/bootstrap/src/utils/tests/mod.rs
@@ -0,0 +1 @@
+mod shared_helpers_tests;
diff --git a/src/bootstrap/src/utils/shared_helpers/tests.rs b/src/bootstrap/src/utils/tests/shared_helpers_tests.rs
index da7924276f7..6c47e7f2438 100644
--- a/src/bootstrap/src/utils/shared_helpers/tests.rs
+++ b/src/bootstrap/src/utils/tests/shared_helpers_tests.rs
@@ -1,4 +1,11 @@
-use super::parse_value_from_args;
+//! The `shared_helpers` module can't have its own tests submodule, because
+//! that would cause problems for the shim binaries that include it via
+//! `#[path]`, so instead those unit tests live here.
+//!
+//! To prevent tidy from complaining about this file not being named `tests.rs`,
+//! it lives inside a submodule directory named `tests`.
+
+use crate::utils::shared_helpers::parse_value_from_args;
 
 #[test]
 fn test_parse_value_from_args() {
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 2f35e605026..508b7b40c01 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -26,6 +26,12 @@ DEPLOY=1 ./src/ci/docker/run.sh x86_64-gnu
 while locally, to the `obj/$image_name` directory. This is primarily to prevent
 strange linker errors when using multiple Docker images.
 
+For some Linux workflows (for example `x86_64-gnu-llvm-18-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-18-3` workflow, you can run the following script:
+
+```
+DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-18
+```
+
 ## Local Development
 
 Refer to the [dev guide](https://rustc-dev-guide.rust-lang.org/tests/docker.html) for more information on testing locally.
diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
index 414bcc52484..7e946df6163 100644
--- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
@@ -50,6 +50,7 @@ COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 
 # Need at least GCC 5.1 to compile LLVM nowadays
 COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
+ENV GCC_VERSION=9.5.0
 RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
 
 COPY scripts/cmake.sh /tmp/
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index e857f38e68a..bbb4fe216a5 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -44,12 +44,14 @@ RUN mkdir -p /rustroot/bin
 ENV PATH=/rustroot/bin:$PATH
 ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
 ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
+# Clang needs to access GCC headers to enable linker plugin LTO
 WORKDIR /tmp
 RUN mkdir /home/user
 COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 
 # Need at least GCC 5.1 to compile LLVM nowadays
 COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
+ENV GCC_VERSION=9.5.0
 RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
 
 # LLVM 17 needs cmake 3.20 or higher.
@@ -89,6 +91,7 @@ ENV RUST_CONFIGURE_ARGS \
       --set rust.lto=thin \
       --set rust.codegen-units=1
 
+# Note that `rust.debug` is set to true *only* for `opt-dist`
 ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \
     ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \
     --host $HOSTS --target $HOSTS \
@@ -104,3 +107,7 @@ ENV DIST_SRC 1
 ENV LIBCURL_NO_PKG_CONFIG 1
 
 ENV DIST_REQUIRE_ALL_TOOLS 1
+
+# FIXME: Without this, LLVMgold.so incorrectly resolves to the system
+# libstdc++, instead of the one we build.
+ENV LD_PRELOAD=/rustroot/lib64/libstdc++.so.6
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
index 2e08c87f278..3c8123d90de 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
@@ -39,6 +39,7 @@ hide_output \
       -DLLVM_INCLUDE_TESTS=OFF \
       -DLLVM_INCLUDE_EXAMPLES=OFF \
       -DLLVM_ENABLE_PROJECTS="clang;lld;compiler-rt;bolt" \
+      -DLLVM_BINUTILS_INCDIR="/rustroot/lib/gcc/x86_64-pc-linux-gnu/$GCC_VERSION/plugin/include/" \
       -DC_INCLUDE_DIRS="$INC"
 
 hide_output make -j$(nproc)
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
index e939a5d7eac..57d4d338a50 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
@@ -1,10 +1,11 @@
 #!/usr/bin/env bash
-set -ex
+set -eux
 
 source shared.sh
 
 # Note: in the future when bumping to version 10.1.0, also take care of the sed block below.
-GCC=9.5.0
+# This version is specified in the Dockerfile
+GCC=$GCC_VERSION
 
 curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | xzcat | tar xf -
 cd gcc-$GCC
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index a0adf60b6b2..d1bc0519bc1 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -76,8 +76,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
     # Include cache version. Can be used to manually bust the Docker cache.
     echo "2" >> $hash_key
 
-    echo "Image input"
+    echo "::group::Image checksum input"
     cat $hash_key
+    echo "::endgroup::"
 
     cksum=$(sha512sum $hash_key | \
     awk '{print $1}')
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index 6103aa61248..5522095e304 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -15,7 +15,7 @@ LLVM_VERSION="18.1.4"
 
 if isMacOS; then
     # FIXME: This is the latest pre-built version of LLVM that's available for
-    # x86_64 MacOS. We may want to consider bulding our own LLVM binaries
+    # x86_64 MacOS. We may want to consider building our own LLVM binaries
     # instead, or set `USE_XCODE_CLANG` like AArch64 does.
     LLVM_VERSION="15.0.7"
 
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 9743b3ba442..f0c3720eae1 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -56,6 +56,7 @@
     - [csky-unknown-linux-gnuabiv2\*](platform-support/csky-unknown-linux-gnuabiv2.md)
     - [hexagon-unknown-linux-musl](platform-support/hexagon-unknown-linux-musl.md)
     - [hexagon-unknown-none-elf](platform-support/hexagon-unknown-none-elf.md)
+    - [illumos](platform-support/illumos.md)
     - [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md)
     - [loongarch\*-unknown-none\*](platform-support/loongarch-none.md)
     - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 00ab61051c3..24e9a3c8121 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -32,8 +32,8 @@ All tier 1 targets with host tools support the full standard library.
 
 target | notes
 -------|-------
-`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
 [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
+`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
 `i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI]
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]
@@ -102,7 +102,7 @@ target | notes
 [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
 [`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2, glibc 2.17)
 [`x86_64-unknown-freebsd`](platform-support/freebsd.md) | 64-bit amd64 FreeBSD
-`x86_64-unknown-illumos` | illumos
+[`x86_64-unknown-illumos`](platform-support/illumos.md) | illumos
 `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3
 [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64
 
@@ -139,12 +139,12 @@ target | std | notes
 [`aarch64-apple-ios`](platform-support/apple-ios.md) | ✓ | ARM64 iOS
 [`aarch64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on ARM64
 [`aarch64-apple-ios-sim`](platform-support/apple-ios.md) | ✓ | Apple iOS Simulator on ARM64
-[`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
 [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ARM64 MinGW (Windows 10+), LLVM ABI
+[`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia
 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | ARM64 OpenHarmony
-`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
 `aarch64-unknown-none` | * | Bare ARM64, hardfloat
+`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
 [`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | ARM64 UEFI
 [`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android
 `arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
@@ -173,11 +173,11 @@ target | std | notes
 [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI)
 [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI)
 [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
-[`riscv32imac-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA)
 [`riscv32i-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32I ISA)
 [`riscv32im-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IM ISA)
-[`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA)
+[`riscv32imac-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA)
 [`riscv32imafc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA)
+[`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA)
 `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
 `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
 `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
@@ -194,16 +194,16 @@ target | std | notes
 [`wasm32-unknown-emscripten`](platform-support/wasm32-unknown-emscripten.md) | ✓ | WebAssembly via Emscripten
 [`wasm32-unknown-unknown`](platform-support/wasm32-unknown-unknown.md) | ✓ | WebAssembly
 [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASIp1
-[`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ | WebAssembly with WASIp2
 [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ | WebAssembly with WASI Preview 1 and threads
+[`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ | WebAssembly with WASIp2
 [`wasm32v1-none`](platform-support/wasm32v1-none.md) | * | WebAssembly limited to 1.0 features and no imports
 [`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS
 [`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ | Mac Catalyst on x86_64
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
-[`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia
 [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android
 [`x86_64-pc-solaris`](platform-support/solaris.md) | ✓ | 64-bit x86 Solaris 11.4
 [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI
+[`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia
 `x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
 [`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | x86_64 OpenHarmony
 [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat
@@ -245,34 +245,34 @@ host tools.
 
 target | std | host | notes
 -------|:---:|:----:|-------
-[`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md)  | ✓ | ✓ | ARM64e Apple Darwin
-[`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
-[`arm64e-apple-tvos`](platform-support/arm64e-apple-tvos.md)  | ✓ | | ARM64e Apple tvOS
 [`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ✓ |  | ARM64 tvOS
 [`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ✓ |  | ARM64 tvOS Simulator
-[`aarch64-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARM64 Apple WatchOS
-[`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | ARM64 Apple WatchOS Simulator
 [`aarch64-apple-visionos`](platform-support/apple-visionos.md) | ✓ |  | ARM64 Apple visionOS
 [`aarch64-apple-visionos-sim`](platform-support/apple-visionos.md) | ✓ |  | ARM64 Apple visionOS Simulator
+[`aarch64-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARM64 Apple WatchOS
+[`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | ARM64 Apple WatchOS Simulator
 [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ |  | ARM64 SOLID with TOPPERS/ASP3
 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * |  | ARM64 Nintendo Switch, Horizon
-[`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? |  | ARM64 TEEOS |
-[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? |  | ARM64 QNX Neutrino 7.0 RTOS |
-[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | ARM64 QNX Neutrino 7.1 RTOS |
 [`aarch64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | ARM64 FreeBSD
 [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ |  | ARM64 Hermit
-`aarch64-unknown-illumos` | ✓ | ✓ | ARM64 illumos
+[`aarch64-unknown-illumos`](platform-support/illumos.md) | ✓ | ✓ | ARM64 illumos
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
 [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD
+[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? |  | ARM64 QNX Neutrino 7.0 RTOS |
+[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | ARM64 QNX Neutrino 7.1 RTOS |
 [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
 [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ |  | ARM64 Redox OS
+[`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? |  | ARM64 TEEOS |
 [`aarch64-unknown-trusty`](platform-support/trusty.md) | ? |  |
 `aarch64-uwp-windows-msvc` | ✓ |  |
 [`aarch64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  | ARM64 VxWorks OS
-`aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
 `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
+`aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
 [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
 [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | Arm Apple WatchOS 64-bit with 32-bit pointers
+[`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md)  | ✓ | ✓ | ARM64e Apple Darwin
+[`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
+[`arm64e-apple-tvos`](platform-support/arm64e-apple-tvos.md)  | ✓ | | ARM64e Apple tvOS
 [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | Arm BE8 the default Arm big-endian architecture since [Armv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).
 [`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Bare Armv4T
 `armv4t-unknown-linux-gnueabi` | ? |  | Armv4T Linux
@@ -283,9 +283,9 @@ target | std | host | notes
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 [`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? |  | RTEMS OS for ARM BSPs
 [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ |  | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
+[`armv7-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | Armv7-A FreeBSD
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat
-[`armv7-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | Armv7-A FreeBSD
 [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float
 [`armv7-unknown-trusty`](platform-support/trusty.md) | ? |  |
 [`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ |  | Armv7-A for VxWorks
@@ -300,8 +300,8 @@ target | std | host | notes
 `bpfel-unknown-none` | * |  | BPF (little endian)
 `csky-unknown-linux-gnuabiv2` | ✓ |  | C-SKY abiv2 Linux (little endian)
 `csky-unknown-linux-gnuabiv2hf` | ✓ |  | C-SKY abiv2 Linux, hardfloat (little endian)
-[`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | | Bare Hexagon (v60+, HVX)
 [`hexagon-unknown-linux-musl`](platform-support/hexagon-unknown-linux-musl.md) | ✓ | | Hexagon Linux with musl 1.2.3
+[`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | | Bare Hexagon (v60+, HVX)
 [`i386-apple-ios`](platform-support/apple-ios.md) | ✓ |  | 32-bit x86 iOS [^x86_32-floats-return-ABI]
 [`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * |  | 32-bit x86 QNX Neutrino 7.0 RTOS  [^x86_32-floats-return-ABI]
 [`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ |  | 32-bit x86, restricted to Pentium
@@ -325,48 +325,56 @@ target | std | host | notes
 `mips64-unknown-linux-muslabi64` | ✓ |  | MIPS64 Linux, N64 ABI, musl 1.2.3
 `mips64el-unknown-linux-gnuabi64` | ✓ | ✓ | MIPS64 (little endian) Linux, N64 ABI (kernel 4.4, glibc 2.23)
 `mips64el-unknown-linux-muslabi64` | ✓ |  | MIPS64 (little endian) Linux, N64 ABI, musl 1.2.3
-`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (little endian) Linux (kernel 4.4, glibc 2.23)
-`mipsel-unknown-linux-musl` | ✓ |  | MIPS (little endian) Linux with musl 1.2.3
-[`mipsel-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | 32-bit MIPS (LE), requires mips32 cpu support
 `mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
 [`mipsel-sony-psx`](platform-support/mipsel-sony-psx.md) | * |  | MIPS (LE) Sony PlayStation 1 (PSX)
+`mipsel-unknown-linux-gnu` | ✓ | ✓ | MIPS (little endian) Linux (kernel 4.4, glibc 2.23)
+`mipsel-unknown-linux-musl` | ✓ |  | MIPS (little endian) Linux with musl 1.2.3
 `mipsel-unknown-linux-uclibc` | ✓ |  | MIPS (LE) Linux with uClibc
+[`mipsel-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | 32-bit MIPS (LE), requires mips32 cpu support
 `mipsel-unknown-none` | * |  | Bare MIPS (LE) softfloat
 [`mipsisa32r6-unknown-linux-gnu`](platform-support/mips-release-6.md) | ? |  | 32-bit MIPS Release 6 Big Endian
 [`mipsisa32r6el-unknown-linux-gnu`](platform-support/mips-release-6.md) | ? |  | 32-bit MIPS Release 6 Little Endian
 [`mipsisa64r6-unknown-linux-gnuabi64`](platform-support/mips-release-6.md) | ? |  | 64-bit MIPS Release 6 Big Endian
 [`mipsisa64r6el-unknown-linux-gnuabi64`](platform-support/mips-release-6.md) | ✓ | ✓ | 64-bit MIPS Release 6 Little Endian
 `msp430-none-elf` | * |  | 16-bit MSP430 microcontrollers
+[`powerpc-unknown-freebsd`](platform-support/freebsd.md) | ? |   | PowerPC FreeBSD
 `powerpc-unknown-linux-gnuspe` | ✓ |  | PowerPC SPE Linux
 `powerpc-unknown-linux-musl` | ? |  | PowerPC Linux with musl 1.2.3
 [`powerpc-unknown-linux-muslspe`](platform-support/powerpc-unknown-linux-muslspe.md) | ? |  | PowerPC SPE Linux
 [`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems
 [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * |  |
-[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ |  |
 [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
+[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ |  |
+[`powerpc64-ibm-aix`](platform-support/aix.md) | ? |  | 64-bit AIX (7.2 and newer)
 [`powerpc64-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64 FreeBSD (ELFv2)
-[`powerpc64le-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64LE FreeBSD
-[`powerpc-unknown-freebsd`](platform-support/freebsd.md) | ? |   | PowerPC FreeBSD
 `powerpc64-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3
-[`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 [`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64
-[`powerpc64-ibm-aix`](platform-support/aix.md) | ? |  | 64-bit AIX (7.2 and newer)
+[`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
+[`powerpc64le-unknown-freebsd`](platform-support/freebsd.md) | ✓ | ✓ | PPC64LE FreeBSD
+[`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
+[`riscv32e-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32E ISA)
+[`riscv32em-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EM ISA)
+[`riscv32emc-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EMC ISA)
 `riscv32gc-unknown-linux-gnu` | ✓ |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` | ? |   | RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches)
 [`riscv32im-risc0-zkvm-elf`](platform-support/riscv32im-risc0-zkvm-elf.md) | ? |  | RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA)
 [`riscv32ima-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32IMA ISA)
-[`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? |  | RISC-V Xous (RV32IMAC ISA)
-[`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
 [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
+[`riscv32imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
+[`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? |  | RISC-V Xous (RV32IMAC ISA)
 [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
-[`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
-[`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ |   | RISC-V Hermit
+[`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
+[`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
+[`riscv32imc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
+[`riscv64-linux-android`](platform-support/android.md) | ? |   | RISC-V 64-bit Android
+[`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 `riscv64gc-unknown-freebsd` | ? |   | RISC-V FreeBSD
 `riscv64gc-unknown-fuchsia` | ? |   | RISC-V Fuchsia
+[`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ |   | RISC-V Hermit
 [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
+[`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
-[`riscv64-linux-android`](platform-support/android.md) | ? |   | RISC-V 64-bit Android
-[`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
+[`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
 [`s390x-unknown-linux-musl`](platform-support/s390x-unknown-linux-musl.md) | ✓ |  | S390x Linux (kernel 3.2, musl 1.2.3)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * |  | Bare 32-bit SPARC V7+
@@ -374,9 +382,16 @@ target | std | host | notes
 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
 [`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * |  | Thumb-mode Bare Armv4T
 [`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Thumb-mode Bare Armv5TE
+[`thumbv6m-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv6M with NuttX
 `thumbv7a-pc-windows-msvc` | ✓ |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
+[`thumbv7em-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7EM with NuttX
+[`thumbv7em-nuttx-eabihf`](platform-support/nuttx.md) | * |  | ARMv7EM with NuttX, hardfloat
+[`thumbv7m-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7M with NuttX
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode Armv7-A Linux with NEON, musl 1.2.3
+[`thumbv8m.base-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv8M Baseline with NuttX
+[`thumbv8m.main-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv8M Mainline with NuttX
+[`thumbv8m.main-nuttx-eabihf`](platform-support/nuttx.md) | * |  | ARMv8M Mainline with NuttX, hardfloat
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ |  | x86 64-bit tvOS
 [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | x86 64-bit Apple WatchOS simulator
@@ -384,9 +399,10 @@ target | std | host | notes
 [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ |   | 64-bit Unikraft with musl 1.2.3
 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
 `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
-[`x86_64-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 64-bit GNU/Hurd
 [`x86_64-unknown-hermit`](platform-support/hermit.md) | ✓ |  | x86_64 Hermit
+[`x86_64-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 64-bit GNU/Hurd
 `x86_64-unknown-l4re-uclibc` | ? |  |
+[`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * |  | 64-bit Linux with no libc
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
 [`x86_64-unknown-trusty`](platform-support/trusty.md) | ? |  |
 `x86_64-uwp-windows-gnu` | ✓ |  |
@@ -394,27 +410,11 @@ target | std | host | notes
 [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 64-bit Windows 7 support
 [`x86_64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell)
-[`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * |  | 64-bit Linux with no libc
-[`xtensa-esp32-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32
 [`xtensa-esp32-espidf`](platform-support/esp-idf.md) | ✓ |  | Xtensa ESP32
-[`xtensa-esp32s2-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32-S2
+[`xtensa-esp32-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32
 [`xtensa-esp32s2-espidf`](platform-support/esp-idf.md) | ✓ |  | Xtensa ESP32-S2
-[`xtensa-esp32s3-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32-S3
+[`xtensa-esp32s2-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32-S2
 [`xtensa-esp32s3-espidf`](platform-support/esp-idf.md) | ✓ |  | Xtensa ESP32-S3
-[`thumbv6m-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv6M with NuttX
-[`thumbv7m-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7M with NuttX
-[`thumbv7em-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv7EM with NuttX
-[`thumbv7em-nuttx-eabihf`](platform-support/nuttx.md) | * |  | ARMv7EM with NuttX, hardfloat
-[`thumbv8m.base-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv8M Baseline with NuttX
-[`thumbv8m.main-nuttx-eabi`](platform-support/nuttx.md) | * |  | ARMv8M Mainline with NuttX
-[`thumbv8m.main-nuttx-eabihf`](platform-support/nuttx.md) | * |  | ARMv8M Mainline with NuttX, hardfloat
-[`riscv32imc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
-[`riscv32imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
-[`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
-[`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
-[`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
-[`riscv32e-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32E ISA)
-[`riscv32em-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EM ISA)
-[`riscv32emc-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EMC ISA)
+[`xtensa-esp32s3-none-elf`](platform-support/xtensa.md) | * |  | Xtensa ESP32-S3
 
 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/rustc/src/platform-support/android.md b/src/doc/rustc/src/platform-support/android.md
index 96499b0d801..54e7ddca32a 100644
--- a/src/doc/rustc/src/platform-support/android.md
+++ b/src/doc/rustc/src/platform-support/android.md
@@ -65,4 +65,4 @@ Currently the `riscv64-linux-android` target requires the following architecture
 ### aarch64-linux-android on Nightly compilers
 
 As soon as `-Zfixed-x18` compiler flag is supplied, the [`ShadowCallStack` sanitizer](https://releases.llvm.org/7.0.1/tools/clang/docs/ShadowCallStack.html)
-instrumentation is also made avaiable by supplying the second compiler flag `-Zsanitizer=shadow-call-stack`.
+instrumentation is also made available by supplying the second compiler flag `-Zsanitizer=shadow-call-stack`.
diff --git a/src/doc/rustc/src/platform-support/illumos.md b/src/doc/rustc/src/platform-support/illumos.md
new file mode 100644
index 00000000000..dd2ae90f674
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/illumos.md
@@ -0,0 +1,42 @@
+# `aarch64-unknown-illumos` and `x86_64-unknown-illumos`
+
+**Tier: 2/3**
+
+[illumos](https://www.illumos.org/), is a Unix operating system which provides next-generation features for downstream distributions,
+including advanced system debugging, next generation filesystem, networking, and virtualization options.
+
+## Target maintainers
+
+- Joshua M. Clulow ([@jclulow](https://github.com/jclulow))
+- Patrick Mooney ([@pfmooney](https://github.com/pfmooney))
+
+## Requirements
+
+The target supports host tools.
+
+The illumos target supports `std` and uses the standard ELF file format.
+
+`x86_64-unknown-illumos` is a tier 2 target with host tools.
+`aarch64-unknown-illumos` is a tier 3 target.
+
+## Building the target
+
+These targets can be built by adding `aarch64-unknown-illumos` and
+`x86_64-unknown-illumos` as targets in the rustc list.
+
+## Building Rust programs
+
+Rust ships pre-compiled artifacts for the `x86_64-unknown-illumos` target.
+Rust does not ship pre-compiled artifacts for `aarch64-unknown-illumos`,
+it requires building the target either as shown above or using `-Zbuild-std`.
+
+## Testing
+
+Tests can be run in the same way as a regular binary.
+
+## Cross-compilation toolchains and C code
+
+The target supports C code.
+
+The illumos project makes available [prebuilt sysroot artefacts](https://github.com/illumos/sysroot) which can be used for cross compilation.
+The official Rust binaries are cross-compiled using these artefacts.
diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md
index 1acc0584be9..b57083980d2 100644
--- a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md
+++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md
@@ -122,7 +122,7 @@ limactl shell riscv
 
 Using [Docker (with BuildKit)](https://docs.docker.com/build/buildkit/) the
 [`riscv64/ubuntu`](https://hub.docker.com/r/riscv64/ubuntu) image can be used
-to buiild or run `riscv64gc-unknown-linux-gnu` binaries.
+to build or run `riscv64gc-unknown-linux-gnu` binaries.
 
 ```bash
 docker run --platform linux/riscv64 -ti --rm --mount "type=bind,src=$(pwd),dst=/checkout" riscv64/ubuntu bash
diff --git a/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
index 5608b5cb778..965d6aea931 100644
--- a/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
+++ b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
@@ -14,6 +14,11 @@ This target is cross compiled and can be built from any host.
 
 This target has no support for host tools, std, or alloc.
 
+One of the primary motivations of the target is to write a dynamic linker and libc in Rust.
+For that, the target defaults to position-independent code and position-independent executables (PIE) by default.
+PIE binaries need relocation at runtime. This is usually done by the dynamic linker or libc.
+You can use `-Crelocation-model=static` to create a position-dependent binary that does not need relocation at runtime.
+
 ## Building the target
 
 The target can be built by enabling it for a `rustc` build:
diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md
index a332d24c9f1..6c1494186a4 100644
--- a/src/doc/rustc/src/targets/custom.md
+++ b/src/doc/rustc/src/targets/custom.md
@@ -21,10 +21,10 @@ To use a custom target, see the (unstable) [`build-std` feature](../../cargo/ref
 When `rustc` is given an option `--target=TARGET` (where `TARGET` is any string), it uses the following logic:
 1. if `TARGET` is the name of a built-in target, use that
 2. if `TARGET` is a path to a file, read that file as a json target
-3. otherwise, search the colon-seperated list of directories found
+3. otherwise, search the colon-separated list of directories found
    in the `RUST_TARGET_PATH` environment variable from left to right
    for a file named `TARGET.json`.
 
-These steps are tried in order, so if there are multple potentially valid
+These steps are tried in order, so if there are multiple potentially valid
 interpretations for a target, whichever is found first will take priority.
 If none of these methods find a target, an error is thrown.
diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
index e02c26bd42b..b921f677857 100644
--- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md
+++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
@@ -412,7 +412,7 @@ In some cases, doctests cannot be merged. For example, if you have:
 ```
 
 The problem with this code is that, if you change any other doctests, it'll likely break when
-runing `rustdoc --test`, making it tricky to maintain.
+running `rustdoc --test`, making it tricky to maintain.
 
 This is where the `standalone_crate` attribute comes in: it tells `rustdoc` that a doctest
 should not be merged with the others. So the previous code should use it:
diff --git a/src/doc/unstable-book/src/language-features/rustc-private.md b/src/doc/unstable-book/src/language-features/rustc-private.md
index 97fce5980e4..3b83a3cf4df 100644
--- a/src/doc/unstable-book/src/language-features/rustc-private.md
+++ b/src/doc/unstable-book/src/language-features/rustc-private.md
@@ -6,6 +6,9 @@ The tracking issue for this feature is: [#27812]
 
 ------------------------
 
-This feature allows access to unstable internal compiler crates.
+This feature allows access to unstable internal compiler crates such as `rustc_driver`.
 
-Additionally it changes the linking behavior of crates which have this feature enabled. It will prevent linking to a dylib if there's a static variant of it already statically linked into another dylib dependency. This is required to successfully link to `rustc_driver`.
+The presence of this feature changes the way the linkage format for dylibs is calculated in a way
+that is necessary for linking against dylibs that statically link `std` (such as `rustc_driver`).
+This makes this feature "viral" in linkage; its use in a given crate makes its use required in
+dependent crates which link to it (including integration tests, which are built as separate crates).
diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish
index f0927183c07..49fe10a4ea2 100644
--- a/src/etc/completions/x.fish
+++ b/src/etc/completions/x.fish
@@ -319,6 +319,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l bless -d 'whether to automa
 complete -c x -n "__fish_x_using_subcommand test" -l force-rerun -d 'rerun tests even if the inputs are unchanged'
 complete -c x -n "__fish_x_using_subcommand test" -l only-modified -d 'only run tests that result has been changed'
 complete -c x -n "__fish_x_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`'
+complete -c x -n "__fish_x_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests'
 complete -c x -n "__fish_x_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x -n "__fish_x_using_subcommand test" -s i -l incremental -d 'use incremental compilation'
 complete -c x -n "__fish_x_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones'
diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1
index 7cbf0f0d13c..fa833b6876a 100644
--- a/src/etc/completions/x.ps1
+++ b/src/etc/completions/x.ps1
@@ -366,6 +366,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--force-rerun', '--force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged')
             [CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed')
             [CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`')
+            [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests')
             [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index df31b0d644e..07144ad22d1 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -319,6 +319,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l bless -d 'whether to
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l force-rerun -d 'rerun tests even if the inputs are unchanged'
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l only-modified -d 'only run tests that result has been changed'
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`'
+complete -c x.py -n "__fish_x.py_using_subcommand test" -l no-capture -d 'don\'t capture stdout/stderr of tests'
 complete -c x.py -n "__fish_x.py_using_subcommand test" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
 complete -c x.py -n "__fish_x.py_using_subcommand test" -s i -l incremental -d 'use incremental compilation'
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l include-default-paths -d 'include default paths in addition to the provided ones'
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index afbfb055abd..7d5bd3c9632 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -366,6 +366,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--force-rerun', '--force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged')
             [CompletionResult]::new('--only-modified', '--only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed')
             [CompletionResult]::new('--rustfix-coverage', '--rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`')
+            [CompletionResult]::new('--no-capture', '--no-capture', [CompletionResultType]::ParameterName, 'don''t capture stdout/stderr of tests')
             [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
             [CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh
index ba7f2c9fb5d..5c5e4ef0c15 100644
--- a/src/etc/completions/x.py.sh
+++ b/src/etc/completions/x.py.sh
@@ -3119,7 +3119,7 @@ _x.py() {
             return 0
             ;;
         x.py__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index 415fe09718c..dd71ec00edf 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -365,6 +365,7 @@ _arguments "${_arguments_options[@]}" : \
 '--force-rerun[rerun tests even if the inputs are unchanged]' \
 '--only-modified[only run tests that result has been changed]' \
 '--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`/<build_base>/rustfix_missing_coverage.txt\`]' \
+'--no-capture[don'\''t capture stdout/stderr of tests]' \
 '*-v[use verbose output (-vv for very verbose)]' \
 '*--verbose[use verbose output (-vv for very verbose)]' \
 '-i[use incremental compilation]' \
diff --git a/src/etc/completions/x.sh b/src/etc/completions/x.sh
index a4cf80acc30..057af1ffc6d 100644
--- a/src/etc/completions/x.sh
+++ b/src/etc/completions/x.sh
@@ -3119,7 +3119,7 @@ _x() {
             return 0
             ;;
         x__test)
-            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
+            opts="-v -i -j -h --no-fail-fast --test-args --compiletest-rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --no-capture --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --help [PATHS]... [ARGS]..."
             if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
                 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
                 return 0
diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh
index ee6f504f93e..6215f9af833 100644
--- a/src/etc/completions/x.zsh
+++ b/src/etc/completions/x.zsh
@@ -365,6 +365,7 @@ _arguments "${_arguments_options[@]}" : \
 '--force-rerun[rerun tests even if the inputs are unchanged]' \
 '--only-modified[only run tests that result has been changed]' \
 '--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`/<build_base>/rustfix_missing_coverage.txt\`]' \
+'--no-capture[don'\''t capture stdout/stderr of tests]' \
 '*-v[use verbose output (-vv for very verbose)]' \
 '*--verbose[use verbose output (-vv for very verbose)]' \
 '-i[use incremental compilation]' \
diff --git a/src/etc/test-float-parse/README.md b/src/etc/test-float-parse/README.md
index 21b20d0a072..5e2c43d1cad 100644
--- a/src/etc/test-float-parse/README.md
+++ b/src/etc/test-float-parse/README.md
@@ -3,7 +3,7 @@
 These are tests designed to test decimal to float conversions (`dec2flt`) used
 by the standard library.
 
-It consistes of a collection of test generators that each generate a set of
+It consists of a collection of test generators that each generate a set of
 patterns intended to test a specific property. In addition, there are exhaustive
 tests (for <= `f32`) and fuzzers (for anything that can't be run exhaustively).
 
diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs
index 71b1aa06671..3c71b0dc32e 100644
--- a/src/etc/test-float-parse/src/lib.rs
+++ b/src/etc/test-float-parse/src/lib.rs
@@ -35,7 +35,7 @@ const DEFAULT_MAX_FAILURES: u64 = 20;
 /// Register exhaustive tests only for <= 32 bits. No more because it would take years.
 const MAX_BITS_FOR_EXHAUUSTIVE: u32 = 32;
 
-/// If there are more tests than this threashold, the test will be defered until after all
+/// If there are more tests than this threshold, the test will be deferred until after all
 /// others run (so as to avoid thread pool starvation). They also can be excluded with
 /// `--skip-huge`.
 const HUGE_TEST_CUTOFF: u64 = 5_000_000;
@@ -109,7 +109,7 @@ pub fn run(cfg: Config, include: &[String], exclude: &[String]) -> ExitCode {
     ui::finish(&tests, elapsed, &cfg)
 }
 
-/// Enumerate tests to run but don't actaully run them.
+/// Enumerate tests to run but don't actually run them.
 pub fn register_tests(cfg: &Config) -> Vec<TestInfo> {
     let mut tests = Vec::new();
 
@@ -120,7 +120,7 @@ pub fn register_tests(cfg: &Config) -> Vec<TestInfo> {
     tests.sort_unstable_by_key(|t| (t.float_name, t.gen_name));
     for i in 0..(tests.len() - 1) {
         if tests[i].gen_name == tests[i + 1].gen_name {
-            panic!("dupliate test name {}", tests[i].gen_name);
+            panic!("duplicate test name {}", tests[i].gen_name);
         }
     }
 
@@ -295,7 +295,7 @@ enum Update {
         fail: CheckFailure,
         /// String for which parsing was attempted.
         input: Box<str>,
-        /// The parsed & decomposed `FloatRes`, aleady stringified so we don't need generics here.
+        /// The parsed & decomposed `FloatRes`, already stringified so we don't need generics here.
         float_res: Box<str>,
     },
     /// Exited with an unexpected condition.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4d46f0e75c8..3c9e0914b59 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -268,7 +268,7 @@ fn clean_poly_trait_ref_with_constraints<'tcx>(
     )
 }
 
-fn clean_lifetime(lifetime: &hir::Lifetime, cx: &mut DocContext<'_>) -> Lifetime {
+fn clean_lifetime(lifetime: &hir::Lifetime, cx: &DocContext<'_>) -> Lifetime {
     if let Some(
         rbv::ResolvedArg::EarlyBound(did)
         | rbv::ResolvedArg::LateBound(_, _, did)
@@ -362,9 +362,9 @@ pub(crate) fn clean_predicate<'tcx>(
     let bound_predicate = predicate.kind();
     match bound_predicate.skip_binder() {
         ty::ClauseKind::Trait(pred) => clean_poly_trait_predicate(bound_predicate.rebind(pred), cx),
-        ty::ClauseKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
+        ty::ClauseKind::RegionOutlives(pred) => Some(clean_region_outlives_predicate(pred)),
         ty::ClauseKind::TypeOutlives(pred) => {
-            clean_type_outlives_predicate(bound_predicate.rebind(pred), cx)
+            Some(clean_type_outlives_predicate(bound_predicate.rebind(pred), cx))
         }
         ty::ClauseKind::Projection(pred) => {
             Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
@@ -396,32 +396,30 @@ fn clean_poly_trait_predicate<'tcx>(
     })
 }
 
-fn clean_region_outlives_predicate(
-    pred: ty::RegionOutlivesPredicate<'_>,
-) -> Option<WherePredicate> {
+fn clean_region_outlives_predicate(pred: ty::RegionOutlivesPredicate<'_>) -> WherePredicate {
     let ty::OutlivesPredicate(a, b) = pred;
 
-    Some(WherePredicate::RegionPredicate {
+    WherePredicate::RegionPredicate {
         lifetime: clean_middle_region(a).expect("failed to clean lifetime"),
         bounds: vec![GenericBound::Outlives(
             clean_middle_region(b).expect("failed to clean bounds"),
         )],
-    })
+    }
 }
 
 fn clean_type_outlives_predicate<'tcx>(
     pred: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
     cx: &mut DocContext<'tcx>,
-) -> Option<WherePredicate> {
+) -> WherePredicate {
     let ty::OutlivesPredicate(ty, lt) = pred.skip_binder();
 
-    Some(WherePredicate::BoundPredicate {
+    WherePredicate::BoundPredicate {
         ty: clean_middle_ty(pred.rebind(ty), cx, None, None),
         bounds: vec![GenericBound::Outlives(
             clean_middle_region(lt).expect("failed to clean lifetimes"),
         )],
         bound_params: Vec::new(),
-    })
+    }
 }
 
 fn clean_middle_term<'tcx>(
@@ -894,7 +892,7 @@ fn clean_ty_generics<'tcx>(
 
         // Add back a `Sized` bound if there are no *trait* bounds remaining (incl. `?Sized`).
         // Since all potential trait bounds are at the front we can just check the first bound.
-        if bounds.first().map_or(true, |b| !b.is_trait_bound()) {
+        if bounds.first().is_none_or(|b| !b.is_trait_bound()) {
             bounds.insert(0, GenericBound::sized(cx));
         }
 
@@ -1811,7 +1809,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
         }
         TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
         TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()),
-        TyKind::Array(ty, ref const_arg) => {
+        TyKind::Array(ty, const_arg) => {
             // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
             // as we currently do not supply the parent generics to anonymous constants
             // but do allow `ConstKind::Param`.
@@ -1860,7 +1858,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
 
 /// Returns `None` if the type could not be normalized
 fn normalize<'tcx>(
-    cx: &mut DocContext<'tcx>,
+    cx: &DocContext<'tcx>,
     ty: ty::Binder<'tcx, Ty<'tcx>>,
 ) -> Option<ty::Binder<'tcx, Ty<'tcx>>> {
     // HACK: low-churn fix for #79459 while we wait for a trait normalization fix
@@ -2337,7 +2335,7 @@ fn clean_middle_opaque_bounds<'tcx>(
 
     // Add back a `Sized` bound if there are no *trait* bounds remaining (incl. `?Sized`).
     // Since all potential trait bounds are at the front we can just check the first bound.
-    if bounds.first().map_or(true, |b| !b.is_trait_bound()) {
+    if bounds.first().is_none_or(|b| !b.is_trait_bound()) {
         bounds.insert(0, GenericBound::sized(cx));
     }
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index e6e5123d0bb..009e9662933 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -220,7 +220,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
     } = interface::run_compiler(config, |compiler| {
         let krate = rustc_interface::passes::parse(&compiler.sess);
 
-        let collector = rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| {
+        let collector = rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
             let crate_name = tcx.crate_name(LOCAL_CRATE).to_string();
             let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
             let opts = scrape_test_config(crate_name, crate_attrs, args_path);
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index a188bc8ebd9..7bcb9465948 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -538,7 +538,7 @@ fn handle_attr(mod_attr_pending: &mut String, source_info: &mut SourceInfo, edit
         // If it's complete, then we can clear the pending content.
         mod_attr_pending.clear();
     } else {
-        mod_attr_pending.push_str("\n");
+        mod_attr_pending.push('\n');
     }
 }
 
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index b63122565c4..e64baca974d 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -305,6 +305,7 @@ impl DocFolder for CacheBuilder<'_, '_> {
             | clean::MacroItem(..)
             | clean::ProcMacroItem(..)
             | clean::VariantItem(..) => {
+                use rustc_data_structures::fx::IndexEntry as Entry;
                 if !self.cache.stripped_mod {
                     // Re-exported items mean that the same id can show up twice
                     // in the rustdoc ast that we're looking at. We know,
@@ -313,15 +314,15 @@ impl DocFolder for CacheBuilder<'_, '_> {
                     // paths map if there was already an entry present and we're
                     // not a public item.
                     let item_def_id = item.item_id.expect_def_id();
-                    if !self.cache.paths.contains_key(&item_def_id)
-                        || self
-                            .cache
-                            .effective_visibilities
-                            .is_directly_public(self.tcx, item_def_id)
-                    {
-                        self.cache
-                            .paths
-                            .insert(item_def_id, (self.cache.stack.clone(), item.type_()));
+                    match self.cache.paths.entry(item_def_id) {
+                        Entry::Vacant(entry) => {
+                            entry.insert((self.cache.stack.clone(), item.type_()));
+                        }
+                        Entry::Occupied(mut entry) => {
+                            if entry.get().0.len() > self.cache.stack.len() {
+                                entry.insert((self.cache.stack.clone(), item.type_()));
+                            }
+                        }
                     }
                 }
             }
@@ -413,7 +414,7 @@ impl DocFolder for CacheBuilder<'_, '_> {
             let impl_item = Impl { impl_item: item };
             let impl_did = impl_item.def_id();
             let trait_did = impl_item.trait_did();
-            if trait_did.map_or(true, |d| self.cache.traits.contains_key(&d)) {
+            if trait_did.is_none_or(|d| self.cache.traits.contains_key(&d)) {
                 for did in dids {
                     if self.impl_ids.entry(did).or_default().insert(impl_did) {
                         self.cache.impls.entry(did).or_default().push(impl_item.clone());
diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs
index 48771571f8f..88654ed32da 100644
--- a/src/librustdoc/html/escape.rs
+++ b/src/librustdoc/html/escape.rs
@@ -104,10 +104,9 @@ impl fmt::Display for EscapeBodyTextWithWbr<'_> {
                 continue;
             }
             let is_uppercase = || s.chars().any(|c| c.is_uppercase());
-            let next_is_uppercase =
-                || pk.map_or(true, |(_, t)| t.chars().any(|c| c.is_uppercase()));
-            let next_is_underscore = || pk.map_or(true, |(_, t)| t.contains('_'));
-            let next_is_colon = || pk.map_or(true, |(_, t)| t.contains(':'));
+            let next_is_uppercase = || pk.is_none_or(|(_, t)| t.chars().any(|c| c.is_uppercase()));
+            let next_is_underscore = || pk.is_none_or(|(_, t)| t.contains('_'));
+            let next_is_colon = || pk.is_none_or(|(_, t)| t.contains(':'));
             // Check for CamelCase.
             //
             // `i - last > 3` avoids turning FmRadio into Fm<wbr>Radio, which is technically
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index aa8fdaaee4c..7e835585b73 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -480,7 +480,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for SpannedLinkReplacer<
     type Item = SpannedEvent<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
-        let Some((mut event, range)) = self.iter.next() else { return None };
+        let (mut event, range) = self.iter.next()?;
         self.inner.handle_event(&mut event);
         // Yield the modified event
         Some((event, range))
@@ -2039,7 +2039,7 @@ impl IdMap {
                 let candidate = candidate.to_string();
                 if is_default_id(&candidate) {
                     let id = format!("{}-{}", candidate, 1);
-                    self.map.insert(candidate.into(), 2);
+                    self.map.insert(candidate, 2);
                     id
                 } else {
                     candidate
@@ -2052,7 +2052,7 @@ impl IdMap {
             }
         };
 
-        self.map.insert(id.clone().into(), 1);
+        self.map.insert(id.clone(), 1);
         id
     }
 
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 2d5df75e7dc..5d96dbc0ee6 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -748,7 +748,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                 &shared.layout,
                 &page,
                 "",
-                scrape_examples_help(&shared),
+                scrape_examples_help(shared),
                 &shared.style_files,
             );
             shared.fs.write(scrape_examples_help_file, v)?;
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index dfdf2cd6ec3..9a9ce31caaa 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1974,7 +1974,7 @@ fn render_impl(
             .opt_doc_value()
             .map(|dox| {
                 Markdown {
-                    content: &*dox,
+                    content: &dox,
                     links: &i.impl_item.links(cx),
                     ids: &mut cx.id_map.borrow_mut(),
                     error_codes: cx.shared.codes,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 0fb77d38f16..e8230e63c0f 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1420,7 +1420,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             ty: &'a clean::Type,
         ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
             display_fn(move |f| {
-                let v = ty.print(&self.cx);
+                let v = ty.print(self.cx);
                 write!(f, "{v}")
             })
         }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 583d0214a46..7f072aa7e2f 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -312,15 +312,15 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
         StructFieldItem(f) => ItemEnum::StructField(f.into_json(renderer)),
         EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)),
         VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)),
-        FunctionItem(f) => ItemEnum::Function(from_function(f, true, header.unwrap(), renderer)),
+        FunctionItem(f) => ItemEnum::Function(from_function(*f, true, header.unwrap(), renderer)),
         ForeignFunctionItem(f, _) => {
-            ItemEnum::Function(from_function(f, false, header.unwrap(), renderer))
+            ItemEnum::Function(from_function(*f, false, header.unwrap(), renderer))
         }
         TraitItem(t) => ItemEnum::Trait((*t).into_json(renderer)),
         TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)),
-        MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)),
+        MethodItem(m, _) => ItemEnum::Function(from_function(*m, true, header.unwrap(), renderer)),
         RequiredMethodItem(m) => {
-            ItemEnum::Function(from_function(m, false, header.unwrap(), renderer))
+            ItemEnum::Function(from_function(*m, false, header.unwrap(), renderer))
         }
         ImplItem(i) => ItemEnum::Impl((*i).into_json(renderer)),
         StaticItem(s) => ItemEnum::Static(convert_static(s, rustc_hir::Safety::Safe, renderer)),
@@ -730,12 +730,11 @@ impl FromClean<clean::Impl> for Impl {
 }
 
 pub(crate) fn from_function(
-    function: Box<clean::Function>,
+    clean::Function { decl, generics }: clean::Function,
     has_body: bool,
     header: rustc_hir::FnHeader,
     renderer: &JsonRenderer<'_>,
 ) -> Function {
-    let clean::Function { decl, generics } = *function;
     Function {
         sig: decl.into_json(renderer),
         generics: generics.into_json(renderer),
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ff1c9c61720..d74dcc98cb0 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -869,7 +869,7 @@ fn main_args(
             sess.dcx().fatal("Compilation failed, aborting rustdoc");
         }
 
-        rustc_interface::create_and_enter_global_ctxt(&compiler, krate, |tcx| {
+        rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| {
             let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
                 core::run_global_ctxt(tcx, show_coverage, render_options, output_format)
             });
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 3c1d0c35bef..a777b45b807 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1977,7 +1977,7 @@ fn resolution_failure(
                         }
 
                         if !path_str.contains("::") {
-                            if disambiguator.map_or(true, |d| d.ns() == MacroNS)
+                            if disambiguator.is_none_or(|d| d.ns() == MacroNS)
                                 && collector
                                     .cx
                                     .tcx
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 5638d471890..01068af3e8c 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -160,10 +160,10 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "needs-xray",
     "no-auto-check-cfg",
     "no-prefer-dynamic",
+    "normalize-stderr",
     "normalize-stderr-32bit",
     "normalize-stderr-64bit",
-    "normalize-stderr-test",
-    "normalize-stdout-test",
+    "normalize-stdout",
     "only-16bit",
     "only-32bit",
     "only-64bit",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 91558d0c898..48149e3b897 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -12,7 +12,6 @@ use tracing::*;
 use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
 use crate::debuggers::{extract_cdb_version, extract_gdb_version};
 use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
-use crate::header::cfg::{MatchOutcome, parse_cfg_name_directive};
 use crate::header::needs::CachedNeedsConditions;
 use crate::util::static_regex;
 
@@ -472,11 +471,24 @@ impl TestProps {
 
                     config.set_name_directive(ln, IGNORE_PASS, &mut self.ignore_pass);
 
-                    if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") {
-                        self.normalize_stdout.push(rule);
-                    }
-                    if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") {
-                        self.normalize_stderr.push(rule);
+                    if let Some(NormalizeRule { kind, regex, replacement }) =
+                        config.parse_custom_normalization(ln)
+                    {
+                        let rule_tuple = (regex, replacement);
+                        match kind {
+                            NormalizeKind::Stdout => self.normalize_stdout.push(rule_tuple),
+                            NormalizeKind::Stderr => self.normalize_stderr.push(rule_tuple),
+                            NormalizeKind::Stderr32bit => {
+                                if config.target_cfg().pointer_width == 32 {
+                                    self.normalize_stderr.push(rule_tuple);
+                                }
+                            }
+                            NormalizeKind::Stderr64bit => {
+                                if config.target_cfg().pointer_width == 64 {
+                                    self.normalize_stderr.push(rule_tuple);
+                                }
+                            }
+                        }
                     }
 
                     if let Some(code) = config
@@ -966,20 +978,26 @@ impl Config {
         }
     }
 
-    fn parse_custom_normalization(&self, line: &str, prefix: &str) -> Option<(String, String)> {
-        let parsed = parse_cfg_name_directive(self, line, prefix);
-        if parsed.outcome != MatchOutcome::Match {
-            return None;
-        }
-        let name = parsed.name.expect("successful match always has a name");
+    fn parse_custom_normalization(&self, raw_directive: &str) -> Option<NormalizeRule> {
+        // FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine`
+        // instead of doing it here.
+        let (directive_name, raw_value) = raw_directive.split_once(':')?;
+
+        let kind = match directive_name {
+            "normalize-stdout" => NormalizeKind::Stdout,
+            "normalize-stderr" => NormalizeKind::Stderr,
+            "normalize-stderr-32bit" => NormalizeKind::Stderr32bit,
+            "normalize-stderr-64bit" => NormalizeKind::Stderr64bit,
+            _ => return None,
+        };
 
-        let Some((regex, replacement)) = parse_normalize_rule(line) else {
+        let Some((regex, replacement)) = parse_normalize_rule(raw_value) else {
             panic!(
-                "couldn't parse custom normalization rule: `{line}`\n\
-                help: expected syntax is: `{prefix}-{name}: \"REGEX\" -> \"REPLACEMENT\"`"
+                "couldn't parse custom normalization rule: `{raw_directive}`\n\
+                help: expected syntax is: `{directive_name}: \"REGEX\" -> \"REPLACEMENT\"`"
             );
         };
-        Some((regex, replacement))
+        Some(NormalizeRule { kind, regex, replacement })
     }
 
     fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
@@ -1105,27 +1123,42 @@ fn expand_variables(mut value: String, config: &Config) -> String {
     value
 }
 
+struct NormalizeRule {
+    kind: NormalizeKind,
+    regex: String,
+    replacement: String,
+}
+
+enum NormalizeKind {
+    Stdout,
+    Stderr,
+    Stderr32bit,
+    Stderr64bit,
+}
+
 /// Parses the regex and replacement values of a `//@ normalize-*` header,
 /// in the format:
 /// ```text
-/// normalize-*: "REGEX" -> "REPLACEMENT"
+/// "REGEX" -> "REPLACEMENT"
 /// ```
-fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
+fn parse_normalize_rule(raw_value: &str) -> Option<(String, String)> {
     // FIXME: Support escaped double-quotes in strings.
     let captures = static_regex!(
         r#"(?x) # (verbose mode regex)
         ^
-        [^:\s]+:\s*             # (header name followed by colon)
+        \s*                     # (leading whitespace)
         "(?<regex>[^"]*)"       # "REGEX"
         \s+->\s+                # ->
         "(?<replacement>[^"]*)" # "REPLACEMENT"
         $
         "#
     )
-    .captures(header)?;
+    .captures(raw_value)?;
     let regex = captures["regex"].to_owned();
     let replacement = captures["replacement"].to_owned();
-    // FIXME: Support escaped new-line in strings.
+    // A `\n` sequence in the replacement becomes an actual newline.
+    // FIXME: Do unescaping in a less ad-hoc way, and perhaps support escaped
+    // backslashes and double-quotes.
     let replacement = replacement.replace("\\n", "\n");
     Some((regex, replacement))
 }
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index 3ab552903dc..3f7225195ce 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -40,8 +40,8 @@ pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
 }
 
 /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
-/// or `normalize-stderr-32bit`.
-pub(super) fn parse_cfg_name_directive<'a>(
+/// or `only-windows`.
+fn parse_cfg_name_directive<'a>(
     config: &Config,
     line: &'a str,
     prefix: &str,
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index cd7c6f8361e..618b66dfd4c 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -35,11 +35,14 @@ fn make_test_description<R: Read>(
 
 #[test]
 fn test_parse_normalize_rule() {
-    let good_data = &[(
-        r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)""#,
-        "something (32 bits)",
-        "something ($WORD bits)",
-    )];
+    let good_data = &[
+        (
+            r#""something (32 bits)" -> "something ($WORD bits)""#,
+            "something (32 bits)",
+            "something ($WORD bits)",
+        ),
+        (r#"  " with whitespace"   ->   "    replacement""#, " with whitespace", "    replacement"),
+    ];
 
     for &(input, expected_regex, expected_replacement) in good_data {
         let parsed = parse_normalize_rule(input);
@@ -49,15 +52,15 @@ fn test_parse_normalize_rule() {
     }
 
     let bad_data = &[
-        r#"normalize-stderr-32bit "something (32 bits)" -> "something ($WORD bits)""#,
-        r#"normalize-stderr-16bit: something (16 bits) -> something ($WORD bits)"#,
-        r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)"#,
-        r#"normalize-stderr-32bit: "something (32 bits) -> something ($WORD bits)"#,
-        r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)"#,
-        r#"normalize-stderr-32bit: "something (32 bits)" -> "something ($WORD bits)"."#,
+        r#"something (11 bits) -> something ($WORD bits)"#,
+        r#"something (12 bits) -> something ($WORD bits)"#,
+        r#""something (13 bits) -> something ($WORD bits)"#,
+        r#""something (14 bits)" -> "something ($WORD bits)"#,
+        r#""something (15 bits)" -> "something ($WORD bits)"."#,
     ];
 
     for &input in bad_data {
+        println!("- {input:?}");
         let parsed = parse_normalize_rule(input);
         assert_eq!(parsed, None);
     }
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 250ef0794ad..74d1f5637a8 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -159,7 +159,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
         .optflag("", "only-modified", "only run tests that result been modified")
+        // FIXME: Temporarily retained so we can point users to `--no-capture`
         .optflag("", "nocapture", "")
+        .optflag("", "no-capture", "don't capture stdout/stderr of tests")
         .optflag("", "profiler-runtime", "is the profiler runtime enabled for this target")
         .optflag("h", "help", "show this message")
         .reqopt("", "channel", "current Rust channel", "CHANNEL")
@@ -288,6 +290,10 @@ pub fn parse_config(args: Vec<String>) -> Config {
             );
         })
     });
+    if matches.opt_present("nocapture") {
+        panic!("`--nocapture` is deprecated; please use `--no-capture`");
+    }
+
     Config {
         bless: matches.opt_present("bless"),
         compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
@@ -385,7 +391,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         target_cfgs: OnceLock::new(),
         builtin_cfg_names: OnceLock::new(),
 
-        nocapture: matches.opt_present("nocapture"),
+        nocapture: matches.opt_present("no-capture"),
 
         git_repository: matches.opt_str("git-repository").unwrap(),
         nightly_branch: matches.opt_str("nightly-branch").unwrap(),
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 108fde1c899..7084c407a64 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -213,7 +213,7 @@ fn remove_and_create_dir_all(path: &Path) {
     fs::create_dir_all(path).unwrap();
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 struct TestCx<'test> {
     config: &'test Config,
     props: &'test TestProps,
@@ -2318,32 +2318,47 @@ impl<'test> TestCx<'test> {
         match output_kind {
             TestOutput::Compile => {
                 if !self.props.dont_check_compiler_stdout {
-                    errors += self.compare_output(
+                    if self
+                        .compare_output(
+                            stdout_kind,
+                            &normalized_stdout,
+                            &proc_res.stdout,
+                            &expected_stdout,
+                        )
+                        .should_error()
+                    {
+                        errors += 1;
+                    }
+                }
+                if !self.props.dont_check_compiler_stderr {
+                    if self
+                        .compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr)
+                        .should_error()
+                    {
+                        errors += 1;
+                    }
+                }
+            }
+            TestOutput::Run => {
+                if self
+                    .compare_output(
                         stdout_kind,
                         &normalized_stdout,
                         &proc_res.stdout,
                         &expected_stdout,
-                    );
+                    )
+                    .should_error()
+                {
+                    errors += 1;
                 }
-                if !self.props.dont_check_compiler_stderr {
-                    errors += self.compare_output(
-                        stderr_kind,
-                        &normalized_stderr,
-                        &stderr,
-                        &expected_stderr,
-                    );
+
+                if self
+                    .compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr)
+                    .should_error()
+                {
+                    errors += 1;
                 }
             }
-            TestOutput::Run => {
-                errors += self.compare_output(
-                    stdout_kind,
-                    &normalized_stdout,
-                    &proc_res.stdout,
-                    &expected_stdout,
-                );
-                errors +=
-                    self.compare_output(stderr_kind, &normalized_stderr, &stderr, &expected_stderr);
-            }
         }
         errors
     }
@@ -2576,7 +2591,14 @@ impl<'test> TestCx<'test> {
         actual: &str,
         actual_unnormalized: &str,
         expected: &str,
-    ) -> usize {
+    ) -> CompareOutcome {
+        let expected_path =
+            expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
+
+        if self.config.bless && actual.is_empty() && expected_path.exists() {
+            self.delete_file(&expected_path);
+        }
+
         let are_different = match (self.force_color_svg(), expected.find('\n'), actual.find('\n')) {
             // FIXME: We ignore the first line of SVG files
             // because the width parameter is non-deterministic.
@@ -2584,7 +2606,7 @@ impl<'test> TestCx<'test> {
             _ => expected != actual,
         };
         if !are_different {
-            return 0;
+            return CompareOutcome::Same;
         }
 
         // Wrapper tools set by `runner` might provide extra output on failure,
@@ -2600,7 +2622,7 @@ impl<'test> TestCx<'test> {
             used.retain(|line| actual_lines.contains(line));
             // check if `expected` contains a subset of the lines of `actual`
             if used.len() == expected_lines.len() && (expected.is_empty() == actual.is_empty()) {
-                return 0;
+                return CompareOutcome::Same;
             }
             if expected_lines.is_empty() {
                 // if we have no lines to check, force a full overwite
@@ -2626,9 +2648,6 @@ impl<'test> TestCx<'test> {
         }
         println!("Saved the actual {stream} to {actual_path:?}");
 
-        let expected_path =
-            expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
-
         if !self.config.bless {
             if expected.is_empty() {
                 println!("normalized {}:\n{}\n", stream, actual);
@@ -2651,15 +2670,17 @@ impl<'test> TestCx<'test> {
                 self.delete_file(&old);
             }
 
-            if let Err(err) = fs::write(&expected_path, &actual) {
-                self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
+            if !actual.is_empty() {
+                if let Err(err) = fs::write(&expected_path, &actual) {
+                    self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
+                }
+                println!("Blessing the {stream} of {test_name} in {expected_path:?}");
             }
-            println!("Blessing the {stream} of {test_name} in {expected_path:?}");
         }
 
         println!("\nThe actual {0} differed from the expected {0}.", stream);
 
-        if self.config.bless { 0 } else { 1 }
+        if self.config.bless { CompareOutcome::Blessed } else { CompareOutcome::Differed }
     }
 
     /// Returns whether to show the full stderr/stdout.
@@ -2885,3 +2906,21 @@ enum AuxType {
     Dylib,
     ProcMacro,
 }
+
+/// Outcome of comparing a stream to a blessed file,
+/// e.g. `.stderr` and `.fixed`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum CompareOutcome {
+    /// Expected and actual outputs are the same
+    Same,
+    /// Outputs differed but were blessed
+    Blessed,
+    /// Outputs differed and an error should be emitted
+    Differed,
+}
+
+impl CompareOutcome {
+    fn should_error(&self) -> bool {
+        matches!(self, CompareOutcome::Differed)
+    }
+}
diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs
index 030ca5ebb24..56fc5baf5f2 100644
--- a/src/tools/compiletest/src/runtest/coverage.rs
+++ b/src/tools/compiletest/src/runtest/coverage.rs
@@ -39,16 +39,16 @@ impl<'test> TestCx<'test> {
         let expected_coverage_dump = self.load_expected_output(kind);
         let actual_coverage_dump = self.normalize_output(&proc_res.stdout, &[]);
 
-        let coverage_dump_errors = self.compare_output(
+        let coverage_dump_compare_outcome = self.compare_output(
             kind,
             &actual_coverage_dump,
             &proc_res.stdout,
             &expected_coverage_dump,
         );
 
-        if coverage_dump_errors > 0 {
+        if coverage_dump_compare_outcome.should_error() {
             self.fatal_proc_rec(
-                &format!("{coverage_dump_errors} errors occurred comparing coverage output."),
+                &format!("an error occurred comparing coverage output."),
                 &proc_res,
             );
         }
@@ -139,16 +139,16 @@ impl<'test> TestCx<'test> {
                 self.fatal_proc_rec(&err, &proc_res);
             });
 
-        let coverage_errors = self.compare_output(
+        let coverage_dump_compare_outcome = self.compare_output(
             kind,
             &normalized_actual_coverage,
             &proc_res.stdout,
             &expected_coverage,
         );
 
-        if coverage_errors > 0 {
+        if coverage_dump_compare_outcome.should_error() {
             self.fatal_proc_rec(
-                &format!("{} errors occurred comparing coverage output.", coverage_errors),
+                &format!("an error occurred comparing coverage output."),
                 &proc_res,
             );
         }
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index c15422fb6f6..d9e5c3fa0d8 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -19,15 +19,9 @@ pub(super) struct DebuggerCommands {
 }
 
 impl DebuggerCommands {
-    pub fn parse_from(
-        file: &Path,
-        config: &Config,
-        debugger_prefixes: &[&str],
-    ) -> Result<Self, String> {
-        let directives = debugger_prefixes
-            .iter()
-            .map(|prefix| (format!("{prefix}-command"), format!("{prefix}-check")))
-            .collect::<Vec<_>>();
+    pub fn parse_from(file: &Path, config: &Config, debugger_prefix: &str) -> Result<Self, String> {
+        let command_directive = format!("{debugger_prefix}-command");
+        let check_directive = format!("{debugger_prefix}-check");
 
         let mut breakpoint_lines = vec![];
         let mut commands = vec![];
@@ -48,14 +42,11 @@ impl DebuggerCommands {
                 continue;
             };
 
-            for &(ref command_directive, ref check_directive) in &directives {
-                config
-                    .parse_name_value_directive(&line, command_directive)
-                    .map(|cmd| commands.push(cmd));
-
-                config
-                    .parse_name_value_directive(&line, check_directive)
-                    .map(|cmd| check_lines.push((line_no, cmd)));
+            if let Some(command) = config.parse_name_value_directive(&line, &command_directive) {
+                commands.push(command);
+            }
+            if let Some(pattern) = config.parse_name_value_directive(&line, &check_directive) {
+                check_lines.push((line_no, pattern));
             }
         }
 
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index c621c22ac99..b236b067569 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -59,14 +59,8 @@ impl TestCx<'_> {
             return;
         }
 
-        let prefixes = {
-            static PREFIXES: &[&str] = &["cdb", "cdbg"];
-            // No "native rust support" variation for CDB yet.
-            PREFIXES
-        };
-
         // Parse debugger commands etc from test files
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes)
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "cdb")
             .unwrap_or_else(|e| self.fatal(&e));
 
         // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
@@ -137,7 +131,7 @@ impl TestCx<'_> {
     }
 
     fn run_debuginfo_gdb_test_no_opt(&self) {
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["gdb"])
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "gdb")
             .unwrap_or_else(|e| self.fatal(&e));
         let mut cmds = dbg_cmds.commands.join("\n");
 
@@ -403,7 +397,7 @@ impl TestCx<'_> {
         }
 
         // Parse debugger commands etc from test files
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["lldb"])
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "lldb")
             .unwrap_or_else(|e| self.fatal(&e));
 
         // Write debugger script:
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index 10528de427d..0c6d46188e6 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -100,7 +100,12 @@ impl TestCx<'_> {
                 )
             });
 
-            errors += self.compare_output("fixed", &fixed_code, &fixed_code, &expected_fixed);
+            if self
+                .compare_output("fixed", &fixed_code, &fixed_code, &expected_fixed)
+                .should_error()
+            {
+                errors += 1;
+            }
         } else if !expected_fixed.is_empty() {
             panic!(
                 "the `//@ run-rustfix` directive wasn't found but a `*.fixed` \
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 833e41df537..570b2c374c0 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -8,7 +8,7 @@
 //!
 //! Currently uses a combination of HTML parsing to
 //! extract the `href` and `id` attributes,
-//! and regex search on the orignal markdown to handle intra-doc links.
+//! and regex search on the original markdown to handle intra-doc links.
 //!
 //! These values are then translated to file URLs if possible and then the
 //! destination is asserted to exist.
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
index 89fdd2a01eb..de154d771a0 100644
--- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
@@ -1,7 +1,7 @@
 #![feature(core_intrinsics)]
 #![feature(rustc_attrs)]
 
-use std::intrinsics::typed_swap;
+use std::intrinsics::typed_swap_nonoverlapping;
 use std::ptr::addr_of_mut;
 
 fn invalid_array() {
@@ -10,7 +10,7 @@ fn invalid_array() {
     unsafe {
         let a = addr_of_mut!(a).cast::<[bool; 100]>();
         let b = addr_of_mut!(b).cast::<[bool; 100]>();
-        typed_swap(a, b); //~ERROR: constructing invalid value
+        typed_swap_nonoverlapping(a, b); //~ERROR: constructing invalid value
     }
 }
 
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
index 20b20412e75..5884d13a2ad 100644
--- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: constructing invalid value at [0]: encountered 0x02, but expected a boolean
   --> tests/fail/intrinsics/typed-swap-invalid-array.rs:LL:CC
    |
-LL |         typed_swap(a, b);
-   |         ^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean
+LL |         typed_swap_nonoverlapping(a, b);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr
index 6062465f36a..9804233c7fa 100644
--- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.left.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean
   --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
    |
-LL |         typed_swap(a, b);
-   |         ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean
+LL |         typed_swap_nonoverlapping(a, b);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr
new file mode 100644
index 00000000000..54b21f155ca
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.right.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: constructing invalid value: encountered 0x03, but expected a boolean
+  --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
+   |
+LL |         typed_swap_nonoverlapping(a, b);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `invalid_scalar` at tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
+note: inside `main`
+  --> tests/fail/intrinsics/typed-swap-invalid-scalar.rs:LL:CC
+   |
+LL |     invalid_scalar();
+   |     ^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
index 9d014a523f8..f5f9c7efbe4 100644
--- a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
@@ -1,16 +1,18 @@
+//@revisions: left right
 #![feature(core_intrinsics)]
 #![feature(rustc_attrs)]
 
-use std::intrinsics::typed_swap;
+use std::intrinsics::typed_swap_nonoverlapping;
 use std::ptr::addr_of_mut;
 
 fn invalid_scalar() {
-    let mut a = 1_u8;
-    let mut b = 2_u8;
+    // We run the test twice, with either the left or the right side being invalid.
+    let mut a = if cfg!(left) { 2_u8 } else { 1_u8 };
+    let mut b = if cfg!(right) { 3_u8 } else { 1_u8 };
     unsafe {
         let a = addr_of_mut!(a).cast::<bool>();
         let b = addr_of_mut!(b).cast::<bool>();
-        typed_swap(a, b); //~ERROR: constructing invalid value
+        typed_swap_nonoverlapping(a, b); //~ERROR: constructing invalid value
     }
 }
 
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs
new file mode 100644
index 00000000000..e643091a02a
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.rs
@@ -0,0 +1,13 @@
+#![feature(core_intrinsics)]
+#![feature(rustc_attrs)]
+
+use std::intrinsics::typed_swap_nonoverlapping;
+use std::ptr::addr_of_mut;
+
+fn main() {
+    let mut a = 0_u8;
+    unsafe {
+        let a = addr_of_mut!(a);
+        typed_swap_nonoverlapping(a, a); //~ERROR: called on overlapping ranges
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.stderr
new file mode 100644
index 00000000000..6d578841fe5
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-overlap.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges
+  --> tests/fail/intrinsics/typed-swap-overlap.rs:LL:CC
+   |
+LL |         typed_swap_nonoverlapping(a, a);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/typed-swap-overlap.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/nix-dev-shell/envrc-flake b/src/tools/nix-dev-shell/envrc-flake
index 849ed1f4fc5..f3e5442b86b 100644
--- a/src/tools/nix-dev-shell/envrc-flake
+++ b/src/tools/nix-dev-shell/envrc-flake
@@ -1,4 +1,4 @@
-# If you want to use this as an .envrc file to create a shell with necessery components 
+# If you want to use this as an .envrc file to create a shell with necessary components 
 # to develop rustc, use the following command in the root of the rusr checkout:
 #	
 # ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && nix flake update --flake ./src/tools/nix-dev-shell
diff --git a/src/tools/nix-dev-shell/envrc-shell b/src/tools/nix-dev-shell/envrc-shell
index d8f900fe86a..4080d7d5384 100644
--- a/src/tools/nix-dev-shell/envrc-shell
+++ b/src/tools/nix-dev-shell/envrc-shell
@@ -1,4 +1,4 @@
-# If you want to use this as an .envrc file to create a shell with necessery components 
+# If you want to use this as an .envrc file to create a shell with necessary components 
 # to develop rustc, use the following command in the root of the rusr checkout:
 #	
 # ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 68fb9895ecd..1f98e820840 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -96,9 +96,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.94"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
+checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
 
 [[package]]
 name = "autocfg"
@@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.2.5"
+version = "1.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
+checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
 dependencies = [
  "shlex",
 ]
@@ -1209,9 +1209,9 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.37"
+version = "1.0.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
 dependencies = [
  "proc-macro2",
 ]
@@ -1338,18 +1338,18 @@ checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
 
 [[package]]
 name = "serde"
-version = "1.0.216"
+version = "1.0.217"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
+checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.216"
+version = "1.0.217"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
+checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1446,9 +1446,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.90"
+version = "2.0.93"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
+checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1639,9 +1639,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
 
 [[package]]
 name = "unicase"
-version = "2.8.0"
+version = "2.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
+checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
 
 [[package]]
 name = "unicode-ident"
diff --git a/src/tools/rustc-perf-wrapper/src/main.rs b/src/tools/rustc-perf-wrapper/src/main.rs
index 0b4c894e29d..e6c885e23de 100644
--- a/src/tools/rustc-perf-wrapper/src/main.rs
+++ b/src/tools/rustc-perf-wrapper/src/main.rs
@@ -1,5 +1,5 @@
 use std::fs::create_dir_all;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::process::Command;
 
 use clap::Parser;
@@ -169,7 +169,7 @@ fn execute_benchmark(cmd: &mut Command, compiler: &Path) {
 
     const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
 
-    let rustc_perf_dir = PathBuf::from(MANIFEST_DIR).join("../rustc-perf");
+    let rustc_perf_dir = Path::new(MANIFEST_DIR).join("../rustc-perf");
 
     // We need to set the working directory to `src/tools/perf`, so that it can find the directory
     // with compile-time benchmarks.
diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs
index b216138cf9a..d363d583b54 100644
--- a/src/tools/suggest-tests/src/static_suggestions.rs
+++ b/src/tools/suggest-tests/src/static_suggestions.rs
@@ -2,7 +2,7 @@ use std::sync::OnceLock;
 
 use crate::{Suggestion, sug};
 
-// FIXME: perhaps this could use `std::lazy` when it is stablizied
+// FIXME: perhaps this could use `std::lazy` when it is stabilized
 macro_rules! static_suggestions {
     ($( [ $( $glob:expr ),* $(,)? ] => [ $( $suggestion:expr ),* $(,)? ] ),* $(,)? ) => {
         pub(crate) fn static_suggestions() -> &'static [(Vec<&'static str>, Vec<Suggestion>)]
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index bc75787fb1a..2f424a482b5 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -6,7 +6,7 @@ autobins = false
 
 [dependencies]
 build_helper = { path = "../../build_helper" }
-cargo_metadata = "0.18"
+cargo_metadata = "0.19"
 regex = "1"
 miropt-test-tools = { path = "../miropt-test-tools" }
 walkdir = "2"
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 0e156b9d1ac..b20d8678d0e 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,9 +1,6 @@
-run-make/branch-protection-check-IBT/Makefile
 run-make/cat-and-grep-sanity-check/Makefile
 run-make/extern-fn-reachable/Makefile
-run-make/incr-add-rust-src-component/Makefile
 run-make/jobserver-error/Makefile
-run-make/libs-through-symlinks/Makefile
 run-make/split-debuginfo/Makefile
 run-make/symbol-mangling-hashed/Makefile
 run-make/translation/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index beeb33b46ff..1794d0fbca7 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -1,12 +1,16 @@
 //! Checks the licenses of third-party dependencies.
 
 use std::collections::HashSet;
-use std::fs::read_dir;
+use std::fs::{File, read_dir};
+use std::io::Write;
 use std::path::Path;
 
 use build_helper::ci::CiEnv;
 use cargo_metadata::{Metadata, Package, PackageId};
 
+#[path = "../../../bootstrap/src/utils/proc_macro_deps.rs"]
+mod proc_macro_deps;
+
 /// These are licenses that are allowed for all crates, including the runtime,
 /// rustc, tools, etc.
 #[rustfmt::skip]
@@ -564,9 +568,11 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
 ///
 /// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
 /// to the cargo executable.
-pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
+pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
     let mut checked_runtime_licenses = false;
 
+    check_proc_macro_dep_list(root, cargo, bless, bad);
+
     for &(workspace, exceptions, permitted_deps, submodules) in WORKSPACES {
         if has_missing_submodule(root, submodules) {
             continue;
@@ -600,6 +606,71 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
     assert!(checked_runtime_licenses);
 }
 
+/// Ensure the list of proc-macro crate transitive dependencies is up to date
+fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) {
+    let mut cmd = cargo_metadata::MetadataCommand::new();
+    cmd.cargo_path(cargo)
+        .manifest_path(root.join("Cargo.toml"))
+        .features(cargo_metadata::CargoOpt::AllFeatures)
+        .other_options(vec!["--locked".to_owned()]);
+    let metadata = t!(cmd.exec());
+    let is_proc_macro_pkg = |pkg: &Package| pkg.targets.iter().any(|target| target.is_proc_macro());
+
+    let mut proc_macro_deps = HashSet::new();
+    for pkg in metadata.packages.iter().filter(|pkg| is_proc_macro_pkg(*pkg)) {
+        deps_of(&metadata, &pkg.id, &mut proc_macro_deps);
+    }
+    // Remove the proc-macro crates themselves
+    proc_macro_deps.retain(|pkg| !is_proc_macro_pkg(&metadata[pkg]));
+    let proc_macro_deps_iter = proc_macro_deps.into_iter().map(|dep| metadata[dep].name.clone());
+
+    if bless {
+        let mut proc_macro_deps: Vec<_> = proc_macro_deps_iter.collect();
+        proc_macro_deps.sort();
+        proc_macro_deps.dedup();
+        let mut file = File::create(root.join("src/bootstrap/src/utils/proc_macro_deps.rs"))
+            .expect("`proc_macro_deps` should exist");
+        writeln!(
+            &mut file,
+            "/// Do not update manually - use `./x.py test tidy --bless`
+/// Holds all direct and indirect dependencies of proc-macro crates in tree.
+/// See <https://github.com/rust-lang/rust/issues/134863>
+pub static CRATES: &[&str] = &[
+    // tidy-alphabetical-start"
+        )
+        .unwrap();
+        for dep in proc_macro_deps {
+            writeln!(&mut file, "    {dep:?},").unwrap();
+        }
+        writeln!(
+            &mut file,
+            "    // tidy-alphabetical-end
+];"
+        )
+        .unwrap();
+    } else {
+        let proc_macro_deps: HashSet<_> = proc_macro_deps_iter.collect();
+        let expected =
+            proc_macro_deps::CRATES.iter().map(|s| s.to_string()).collect::<HashSet<_>>();
+        let old_bad = *bad;
+        for missing in proc_macro_deps.difference(&expected) {
+            tidy_error!(
+                bad,
+                "proc-macro crate dependency `{missing}` is not registered in `src/bootstrap/src/utils/proc_macro_deps.rs`",
+            );
+        }
+        for extra in expected.difference(&proc_macro_deps) {
+            tidy_error!(
+                bad,
+                "`{extra}` is not registered in `src/bootstrap/src/utils/proc_macro_deps.rs`, but is not a proc-macro crate dependency",
+            );
+        }
+        if *bad != old_bad {
+            eprintln!("Run `./x.py test tidy --bless` to regenerate the list");
+        }
+    }
+}
+
 /// Used to skip a check if a submodule is not checked out, and not in a CI environment.
 ///
 /// This helps prevent enforcing developers to fetch submodules for tidy.
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 40608952c0b..13a558fea48 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -95,7 +95,7 @@ fn main() {
         check!(target_specific_tests, &tests_path);
 
         // Checks that are done on the cargo workspace.
-        check!(deps, &root_path, &cargo);
+        check!(deps, &root_path, &cargo, bless);
         check!(extdeps, &root_path);
 
         // Checks over tests.
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 35cda17e168..aefcd2bb0cc 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -69,8 +69,7 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[
     "// gdb",
     "// lldb",
     "// cdb",
-    "// normalize-stderr-test",
-    "//@ normalize-stderr-test",
+    "//@ normalize-stderr",
 ];
 
 fn generate_problems<'a>(
@@ -198,8 +197,8 @@ fn should_ignore(line: &str) -> bool {
 
     // For `ui_test`-style UI test directives, also ignore
     // - `//@[rev] compile-flags`
-    // - `//@[rev] normalize-stderr-test`
-        || static_regex!("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr-test|error-pattern).*")
+    // - `//@[rev] normalize-stderr`
+        || static_regex!("\\s*//@(\\[.*\\]) (compile-flags|normalize-stderr|error-pattern).*")
             .is_match(line)
         // Matching for rustdoc tests commands.
         // It allows to prevent them emitting warnings like `line longer than 100 chars`.