about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorThe rustc-dev-guide Cronjob Bot <github-actions@github.com>2025-04-28 04:02:54 +0000
committerThe rustc-dev-guide Cronjob Bot <github-actions@github.com>2025-04-28 04:02:54 +0000
commitaa15830ee2defbac8e784db5510bb914e6e4c820 (patch)
tree87e76fd223f1937ee26537e1028d44e7f6b65544 /src
parentde491f9b7827961c9a786a562cd996db68bd3b5d (diff)
parentdeb947971c8748f5c6203548ce4af9022f21eaf0 (diff)
Merge from rustc
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs23
-rw-r--r--src/bootstrap/src/core/build_steps/suggest.rs1
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs1
-rw-r--r--src/bootstrap/src/core/builder/tests.rs32
-rw-r--r--src/bootstrap/src/core/config/config.rs1
-rw-r--r--src/bootstrap/src/utils/tests/git.rs1
-rw-r--r--src/build_helper/src/git.rs1
-rw-r--r--src/build_helper/src/stage0_parser.rs2
-rw-r--r--src/ci/citool/src/jobs.rs33
-rw-r--r--src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile2
-rwxr-xr-xsrc/ci/docker/run.sh2
-rw-r--r--src/ci/github-actions/jobs.yml11
-rwxr-xr-xsrc/ci/scripts/free-disk-space.sh43
-rw-r--r--src/doc/rustc-dev-guide/src/tests/minicore.md26
-rw-r--r--src/doc/rustc/src/platform-support.md12
-rw-r--r--src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md5
-rw-r--r--src/doc/rustdoc/src/command-line-arguments.md22
-rw-r--r--src/doc/rustdoc/src/read-documentation/search.md2
-rw-r--r--src/doc/rustdoc/src/unstable-features.md54
-rw-r--r--src/doc/rustdoc/src/write-documentation/documentation-tests.md37
-rw-r--r--src/doc/unstable-book/src/library-features/concat-idents.md3
m---------src/gcc0
-rw-r--r--src/librustdoc/config.rs23
-rw-r--r--src/librustdoc/doctest.rs6
-rw-r--r--src/librustdoc/doctest/markdown.rs8
-rw-r--r--src/librustdoc/doctest/runner.rs17
-rw-r--r--src/librustdoc/doctest/rust.rs6
-rw-r--r--src/librustdoc/html/markdown.rs30
-rw-r--r--src/librustdoc/html/markdown/tests.rs4
-rw-r--r--src/librustdoc/html/render/mod.rs26
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css5
-rw-r--r--src/librustdoc/lib.rs18
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs2
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs2
-rw-r--r--src/stage01
-rw-r--r--src/tools/bump-stage0/src/main.rs2
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.fixed8
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.rs8
-rw-r--r--src/tools/clippy/tests/ui/blocks_in_conditions.stderr6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-1782.rs2
-rw-r--r--src/tools/clippy/tests/ui/transmute.rs1
-rw-r--r--src/tools/clippy/tests/ui/transmute.stderr108
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.fixed2
-rw-r--r--src/tools/clippy/tests/ui/transmute_float_to_int.rs2
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char.fixed2
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char.rs2
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed2
-rw-r--r--src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs2
-rw-r--r--src/tools/compiletest/Cargo.toml1
-rw-r--r--src/tools/compiletest/src/common.rs2
-rw-r--r--src/tools/compiletest/src/header/tests.rs1
-rw-r--r--src/tools/compiletest/src/lib.rs99
-rw-r--r--src/tools/compiletest/src/runtest.rs8
-rw-r--r--src/tools/lint-docs/src/lib.rs22
-rw-r--r--src/tools/miri/cargo-miri/src/main.rs2
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs10
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs26
-rw-r--r--src/tools/miri/tests/fail/validity/invalid_bool.rs1
-rw-r--r--src/tools/miri/tests/fail/validity/invalid_bool_op.rs1
-rw-r--r--src/tools/miri/tests/fail/validity/invalid_char.rs1
-rw-r--r--src/tools/miri/tests/fail/validity/invalid_char_op.rs1
-rw-r--r--src/tools/miri/tests/pass/float.rs1
-rw-r--r--src/tools/miri/tests/pass/issues/issue-miri-184.rs1
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs1
-rw-r--r--src/tools/suggest-tests/src/main.rs1
-rw-r--r--src/tools/tidy/src/gcc_submodule.rs47
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs1
-rw-r--r--src/tools/wasm-component-ld/Cargo.toml2
71 files changed, 502 insertions, 339 deletions
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index ed90ede7936..3c412683b94 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -421,13 +421,13 @@ impl Step for Rustc {
                 builder.install(&rustdoc, &image.join("bin"), FileType::Executable);
             }
 
+            let ra_proc_macro_srv_compiler =
+                builder.compiler_for(compiler.stage, builder.config.build, compiler.host);
+            builder.ensure(compile::Rustc::new(ra_proc_macro_srv_compiler, compiler.host));
+
             if let Some(ra_proc_macro_srv) = builder.ensure_if_default(
                 tool::RustAnalyzerProcMacroSrv {
-                    compiler: builder.compiler_for(
-                        compiler.stage,
-                        builder.config.build,
-                        compiler.host,
-                    ),
+                    compiler: ra_proc_macro_srv_compiler,
                     target: compiler.host,
                 },
                 builder.kind,
@@ -1178,6 +1178,8 @@ impl Step for Cargo {
         let compiler = self.compiler;
         let target = self.target;
 
+        builder.ensure(compile::Rustc::new(compiler, target));
+
         let cargo = builder.ensure(tool::Cargo { compiler, target });
         let src = builder.src.join("src/tools/cargo");
         let etc = src.join("src/etc");
@@ -1232,6 +1234,8 @@ impl Step for RustAnalyzer {
         let compiler = self.compiler;
         let target = self.target;
 
+        builder.ensure(compile::Rustc::new(compiler, target));
+
         let rust_analyzer = builder.ensure(tool::RustAnalyzer { compiler, target });
 
         let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
@@ -1274,6 +1278,8 @@ impl Step for Clippy {
         let compiler = self.compiler;
         let target = self.target;
 
+        builder.ensure(compile::Rustc::new(compiler, target));
+
         // Prepare the image directory
         // We expect clippy to build, because we've exited this step above if tool
         // state for clippy isn't testing.
@@ -1324,9 +1330,12 @@ impl Step for Miri {
         if !builder.build.unstable_features() {
             return None;
         }
+
         let compiler = self.compiler;
         let target = self.target;
 
+        builder.ensure(compile::Rustc::new(compiler, target));
+
         let miri = builder.ensure(tool::Miri { compiler, target });
         let cargomiri = builder.ensure(tool::CargoMiri { compiler, target });
 
@@ -1463,6 +1472,8 @@ impl Step for Rustfmt {
         let compiler = self.compiler;
         let target = self.target;
 
+        builder.ensure(compile::Rustc::new(compiler, target));
+
         let rustfmt = builder.ensure(tool::Rustfmt { compiler, target });
         let cargofmt = builder.ensure(tool::Cargofmt { compiler, target });
         let mut tarball = Tarball::new(builder, "rustfmt", &target.triple);
@@ -2328,6 +2339,8 @@ impl Step for LlvmBitcodeLinker {
         let compiler = self.compiler;
         let target = self.target;
 
+        builder.ensure(compile::Rustc::new(compiler, target));
+
         let llbc_linker =
             builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] });
 
diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs
index 6a6731cafc5..fd4918961ad 100644
--- a/src/bootstrap/src/core/build_steps/suggest.rs
+++ b/src/bootstrap/src/core/build_steps/suggest.rs
@@ -13,7 +13,6 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
     let git_config = builder.config.git_config();
     let suggestions = builder
         .tool_cmd(Tool::SuggestTests)
-        .env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository)
         .env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
         .env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email)
         .run_capture_stdout(builder)
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 096f7de6597..d4fccc535a6 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2064,7 +2064,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         }
 
         let git_config = builder.config.git_config();
-        cmd.arg("--git-repository").arg(git_config.git_repository);
         cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
         cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
         cmd.force_coloring_in_ci();
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 8e2c6fc52cd..51852099dc3 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -449,6 +449,7 @@ mod dist {
     use pretty_assertions::assert_eq;
 
     use super::{Config, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, first, run_build};
+    use crate::Flags;
     use crate::core::builder::*;
 
     fn configure(host: &[&str], target: &[&str]) -> Config {
@@ -687,6 +688,37 @@ mod dist {
         );
     }
 
+    /// This also serves as an important regression test for <https://github.com/rust-lang/rust/issues/138123>
+    /// and <https://github.com/rust-lang/rust/issues/138004>.
+    #[test]
+    fn dist_all_cross() {
+        let cmd_args =
+            &["dist", "--stage", "2", "--dry-run", "--config=/does/not/exist"].map(str::to_owned);
+        let config_str = r#"
+            [rust]
+            channel = "nightly"
+
+            [build]
+            extended = true
+
+            build = "i686-unknown-haiku"
+            host = ["i686-unknown-netbsd"]
+            target = ["i686-unknown-netbsd"]
+        "#;
+        let config = Config::parse_inner(Flags::parse(cmd_args), |&_| toml::from_str(config_str));
+        let mut cache = run_build(&[], config);
+
+        // Stage 2 `compile::Rustc` should **NEVER** be cached here.
+        assert_eq!(
+            first(cache.all::<compile::Rustc>()),
+            &[
+                rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0),
+                rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1),
+                rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_3, stage = 1),
+            ]
+        );
+    }
+
     #[test]
     fn build_all() {
         let build = Build::new(configure(
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 419976c83b1..23b623d9bab 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -2963,7 +2963,6 @@ impl Config {
 
     pub fn git_config(&self) -> GitConfig<'_> {
         GitConfig {
-            git_repository: &self.stage0_metadata.config.git_repository,
             nightly_branch: &self.stage0_metadata.config.nightly_branch,
             git_merge_commit_email: &self.stage0_metadata.config.git_merge_commit_email,
         }
diff --git a/src/bootstrap/src/utils/tests/git.rs b/src/bootstrap/src/utils/tests/git.rs
index 99e0793af46..bd40f398c7b 100644
--- a/src/bootstrap/src/utils/tests/git.rs
+++ b/src/bootstrap/src/utils/tests/git.rs
@@ -135,7 +135,6 @@ impl GitCtx {
 
     fn git_config(&self) -> GitConfig<'_> {
         GitConfig {
-            git_repository: &self.git_repo,
             nightly_branch: &self.nightly_branch,
             git_merge_commit_email: &self.merge_bot_email,
         }
diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs
index 8d53a83ea31..438cd14389c 100644
--- a/src/build_helper/src/git.rs
+++ b/src/build_helper/src/git.rs
@@ -5,7 +5,6 @@ use crate::ci::CiEnv;
 
 #[derive(Debug)]
 pub struct GitConfig<'a> {
-    pub git_repository: &'a str,
     pub nightly_branch: &'a str,
     pub git_merge_commit_email: &'a str,
 }
diff --git a/src/build_helper/src/stage0_parser.rs b/src/build_helper/src/stage0_parser.rs
index 2a0c12a1c91..2723f4aa7b9 100644
--- a/src/build_helper/src/stage0_parser.rs
+++ b/src/build_helper/src/stage0_parser.rs
@@ -20,7 +20,6 @@ pub struct Stage0Config {
     pub artifacts_server: String,
     pub artifacts_with_llvm_assertions_server: String,
     pub git_merge_commit_email: String,
-    pub git_repository: String,
     pub nightly_branch: String,
 }
 
@@ -49,7 +48,6 @@ pub fn parse_stage0_file() -> Stage0 {
                 stage0.config.artifacts_with_llvm_assertions_server = value.to_owned()
             }
             "git_merge_commit_email" => stage0.config.git_merge_commit_email = value.to_owned(),
-            "git_repository" => stage0.config.git_repository = value.to_owned(),
             "nightly_branch" => stage0.config.nightly_branch = value.to_owned(),
 
             "compiler_date" => stage0.compiler.date = value.to_owned(),
diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs
index 13880ad466a..5600d7b4db5 100644
--- a/src/ci/citool/src/jobs.rs
+++ b/src/ci/citool/src/jobs.rs
@@ -3,12 +3,15 @@ mod tests;
 
 use std::collections::BTreeMap;
 
+use anyhow::Context as _;
 use serde_yaml::Value;
 
 use crate::GitHubContext;
+use crate::utils::load_env_var;
 
 /// Representation of a job loaded from the `src/ci/github-actions/jobs.yml` file.
 #[derive(serde::Deserialize, Debug, Clone)]
+#[serde(deny_unknown_fields)]
 pub struct Job {
     /// Name of the job, e.g. mingw-check
     pub name: String,
@@ -26,6 +29,8 @@ pub struct Job {
     pub free_disk: Option<bool>,
     /// Documentation link to a resource that could help people debug this CI job.
     pub doc_url: Option<String>,
+    /// Whether the job is executed on AWS CodeBuild.
+    pub codebuild: Option<bool>,
 }
 
 impl Job {
@@ -80,7 +85,7 @@ impl JobDatabase {
 }
 
 pub fn load_job_db(db: &str) -> anyhow::Result<JobDatabase> {
-    let mut db: Value = serde_yaml::from_str(&db)?;
+    let mut db: Value = serde_yaml::from_str(db)?;
 
     // We need to expand merge keys (<<), because serde_yaml can't deal with them
     // `apply_merge` only applies the merge once, so do it a few times to unwrap nested merges.
@@ -107,6 +112,29 @@ struct GithubActionsJob {
     free_disk: Option<bool>,
     #[serde(skip_serializing_if = "Option::is_none")]
     doc_url: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    codebuild: Option<bool>,
+}
+
+/// Replace GitHub context variables with environment variables in job configs.
+/// Used for codebuild jobs like
+/// `codebuild-ubuntu-22-8c-$github.run_id-$github.run_attempt`
+fn substitute_github_vars(jobs: Vec<Job>) -> anyhow::Result<Vec<Job>> {
+    let run_id = load_env_var("GITHUB_RUN_ID")?;
+    let run_attempt = load_env_var("GITHUB_RUN_ATTEMPT")?;
+
+    let jobs = jobs
+        .into_iter()
+        .map(|mut job| {
+            job.os = job
+                .os
+                .replace("$github.run_id", &run_id)
+                .replace("$github.run_attempt", &run_attempt);
+            job
+        })
+        .collect();
+
+    Ok(jobs)
 }
 
 /// Skip CI jobs that are not supposed to be executed on the given `channel`.
@@ -177,6 +205,8 @@ fn calculate_jobs(
         }
         RunType::AutoJob => (db.auto_jobs.clone(), "auto", &db.envs.auto_env),
     };
+    let jobs = substitute_github_vars(jobs.clone())
+        .context("Failed to substitute GitHub context variables in jobs")?;
     let jobs = skip_jobs(jobs, channel);
     let jobs = jobs
         .into_iter()
@@ -207,6 +237,7 @@ fn calculate_jobs(
                 continue_on_error: job.continue_on_error,
                 free_disk: job.free_disk,
                 doc_url: job.doc_url,
+                codebuild: job.codebuild,
             }
         })
         .collect();
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
index 420c42bc9d8..3795859f308 100644
--- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
@@ -1,4 +1,4 @@
-FROM ubuntu:22.04
+FROM ghcr.io/rust-lang/ubuntu:22.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 00d791eeb6b..36f7df2b069 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -288,7 +288,7 @@ args="$args --privileged"
 # `LOCAL_USER_ID` (recognized in `src/ci/run.sh`) to ensure that files are all
 # read/written as the same user as the bare-metal user.
 if [ -f /.dockerenv ]; then
-  docker create -v /checkout --name checkout alpine:3.4 /bin/true
+  docker create -v /checkout --name checkout ghcr.io/rust-lang/alpine:3.4 /bin/true
   docker cp . checkout:/checkout
   args="$args --volumes-from checkout"
 else
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 950a75721c4..88b29d2df56 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -56,6 +56,15 @@ runners:
   - &job-aarch64-linux-8c
     os: ubuntu-24.04-arm64-8core-32gb
     <<: *base-job
+
+  # Codebuild runners are provisioned in
+  # https://github.com/rust-lang/simpleinfra/blob/b7ddd5e6bec8a93ec30510cdddec02c5666fefe9/terragrunt/accounts/ci-prod/ci-runners/terragrunt.hcl#L2
+  - &job-linux-36c-codebuild
+    free_disk: true
+    codebuild: true
+    os: codebuild-ubuntu-22-36c-$github.run_id-$github.run_attempt
+    <<: *base-job
+
 envs:
   env-x86_64-apple-tests: &env-x86_64-apple-tests
     SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
@@ -151,7 +160,7 @@ auto:
     <<: *job-linux-4c
 
   - name: dist-arm-linux
-    <<: *job-linux-8c
+    <<: *job-linux-36c-codebuild
 
   - name: dist-armhf-linux
     <<: *job-linux-4c
diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh
index 055a6ac2211..ad7ee136e9c 100755
--- a/src/ci/scripts/free-disk-space.sh
+++ b/src/ci/scripts/free-disk-space.sh
@@ -14,6 +14,17 @@ isX86() {
     fi
 }
 
+# Check if we're on a GitHub hosted runner.
+# In aws codebuild, the variable RUNNER_ENVIRONMENT is "self-hosted".
+isGitHubRunner() {
+    # `:-` means "use the value of RUNNER_ENVIRONMENT if it exists, otherwise use an empty string".
+    if [[ "${RUNNER_ENVIRONMENT:-}" == "github-hosted" ]]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
 # print a line of the specified character
 printSeparationLine() {
     for ((i = 0; i < 80; i++)); do
@@ -32,7 +43,7 @@ getAvailableSpace() {
 # make Kb human readable (assume the input is Kb)
 # REF: https://unix.stackexchange.com/a/44087/60849
 formatByteCount() {
-    numfmt --to=iec-i --suffix=B --padding=7 "$1"'000'
+    numfmt --to=iec-i --suffix=B --padding=7 "${1}000"
 }
 
 # macro to output saved space
@@ -45,6 +56,11 @@ printSavedSpace() {
     after=$(getAvailableSpace)
     local saved=$((after - before))
 
+    if [ "$saved" -lt 0 ]; then
+        echo "::warning::Saved space is negative: $saved. Using '0' as saved space."
+        saved=0
+    fi
+
     echo ""
     printSeparationLine "*"
     if [ -n "${title}" ]; then
@@ -118,10 +134,14 @@ removeUnusedFilesAndDirs() {
         # Azure
         "/opt/az"
         "/usr/share/az_"*
+    )
 
+    if [ -n "${AGENT_TOOLSDIRECTORY:-}" ]; then
         # Environment variable set by GitHub Actions
-        "$AGENT_TOOLSDIRECTORY"
-    )
+        to_remove+=(
+            "${AGENT_TOOLSDIRECTORY}"
+        )
+    fi
 
     for element in "${to_remove[@]}"; do
         if [ ! -e "$element" ]; then
@@ -155,20 +175,25 @@ cleanPackages() {
         '^dotnet-.*'
         '^llvm-.*'
         '^mongodb-.*'
-        'azure-cli'
         'firefox'
         'libgl1-mesa-dri'
         'mono-devel'
         'php.*'
     )
 
-    if isX86; then
+    if isGitHubRunner; then
         packages+=(
-            'google-chrome-stable'
-            'google-cloud-cli'
-            'google-cloud-sdk'
-            'powershell'
+            azure-cli
         )
+
+        if isX86; then
+            packages+=(
+                'google-chrome-stable'
+                'google-cloud-cli'
+                'google-cloud-sdk'
+                'powershell'
+            )
+        fi
     fi
 
     sudo apt-get -qq remove -y --fix-missing "${packages[@]}"
diff --git a/src/doc/rustc-dev-guide/src/tests/minicore.md b/src/doc/rustc-dev-guide/src/tests/minicore.md
index e4853b6d40e..507b259e027 100644
--- a/src/doc/rustc-dev-guide/src/tests/minicore.md
+++ b/src/doc/rustc-dev-guide/src/tests/minicore.md
@@ -6,25 +6,37 @@
 ui/codegen/assembly test suites. It provides `core` stubs for tests that need to
 build for cross-compiled targets but do not need/want to run.
 
+<div class="warning">
+Please note that [`minicore`] is only intended for `core` items, and explicitly
+**not** `std` or `alloc` items because `core` items are applicable to a wider
+range of tests.
+</div>
+
 A test can use [`minicore`] by specifying the `//@ add-core-stubs` directive.
 Then, mark the test with `#![feature(no_core)]` + `#![no_std]` + `#![no_core]`.
 Due to Edition 2015 extern prelude rules, you will probably need to declare
 `minicore` as an extern crate.
 
+## Implied compiler flags
+
 Due to the `no_std` + `no_core` nature of these tests, `//@ add-core-stubs`
 implies and requires that the test will be built with `-C panic=abort`.
-Unwinding panics are not supported.
+**Unwinding panics are not supported.**
+
+Tests will also be built with `-C force-unwind-tables=yes` to preserve CFI
+directives in assembly tests.
+
+TL;DR: `//@ add-core-stubs` implies two compiler flags:
+
+1. `-C panic=abort`
+2. `-C force-unwind-tables=yes`
+
+## Adding more `core` stubs
 
 If you find a `core` item to be missing from the [`minicore`] stub, consider
 adding it to the test auxiliary if it's likely to be used or is already needed
 by more than one test.
 
-<div class="warning">
-Please note that [`minicore`] is only intended for `core` items, and explicitly
-**not** `std` or `alloc` items because `core` items are applicable to a wider
-range of tests.
-</div>
-
 ## Example codegen test that uses `minicore`
 
 ```rust,no_run
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 9870e5011eb..50c7ae3ef8d 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -34,7 +34,7 @@ target | notes
 -------|-------
 [`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-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
+`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
 [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
 [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+)
@@ -43,6 +43,8 @@ target | notes
 
 [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue].
 
+[^win32-msvc-alignment]: Due to non-standard behavior of MSVC, native C code on this target can cause types with an alignment of more than 4 bytes to be incorrectly aligned to only 4 bytes (this affects, e.g., `u64` and `i64`). Rust applies some mitigations to reduce the impact of this issue, but this can still cause unsoundness due to unsafe code that (correctly) assumes that references are always properly aligned. See [issue #112480](https://github.com/rust-lang/rust/issues/112480).
+
 [77071]: https://github.com/rust-lang/rust/issues/77071
 [x86-32-float-return-issue]: https://github.com/rust-lang/rust/issues/115567
 
@@ -95,7 +97,7 @@ target | notes
 [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony
 [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)
 [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5)
-[`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI]
+[`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
 `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
 [`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17)
@@ -169,7 +171,7 @@ target | std | notes
 [`i686-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI]
 [`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI]
-[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat)
+[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI (Pentium 4, softfloat) [^win32-msvc-alignment]
 [`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]
@@ -317,9 +319,9 @@ target | std | host | notes
 [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI]
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD (Pentium 4) [^x86_32-floats-return-ABI]
 `i686-uwp-windows-gnu` | ✓ |  | [^x86_32-floats-return-ABI]
-[`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ |  | [^x86_32-floats-return-ABI]
+[`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ |  | [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 [`i686-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ |   | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
-[`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 32-bit Windows 7 support [^x86_32-floats-return-ABI]
+[`i686-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 32-bit Windows 7 support [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 [`i686-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  | [^x86_32-floats-return-ABI]
 [`loongarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ |   | LoongArch64 OpenHarmony
 [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? |  | Motorola 680x0 Linux
diff --git a/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md b/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md
index 60aaa371bbc..e98aa996a6e 100644
--- a/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md
+++ b/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md
@@ -20,8 +20,9 @@ The `target_os` of the target is `cygwin`, and it is `unix`.
 
 ## Building the target
 
-For cross-compilation you want LLVM with [llvm/llvm-project#121439 (merged)](https://github.com/llvm/llvm-project/pull/121439) applied to fix the LLVM codegen on importing external global variables from DLLs.
-No native builds on Cygwin now. It should be possible theoretically though, but might need a lot of patches.
+For cross-compilation you want LLVM at least 20.1.0-rc1.
+No native builds on Cygwin now.
+The tracking issue for host tools on Cygwin is [#137819](https://github.com/rust-lang/rust/issues/137819).
 
 ## Building Rust programs
 
diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md
index 872592d669d..b55ddf6e0e1 100644
--- a/src/doc/rustdoc/src/command-line-arguments.md
+++ b/src/doc/rustdoc/src/command-line-arguments.md
@@ -222,6 +222,28 @@ For more, see [the chapter on documentation tests](write-documentation/documenta
 
 See also `--test`.
 
+## `--test-runtool`, `--test-runtool-arg`: program to run tests with; args to pass to it
+
+A doctest wrapper program can be specified with the `--test-runtool` flag.
+Rustdoc will execute that wrapper instead of the doctest executable when
+running tests. The first arguments to the wrapper will be any arguments
+specified with the `--test-runtool-arg` flag, followed by the path to the
+doctest executable to run.
+
+Using these options looks like this:
+
+```bash
+$ rustdoc src/lib.rs --test-runtool path/to/runner --test-runtool-arg --do-thing --test-runtool-arg --do-other-thing
+```
+
+For example, if you want to run your doctests under valgrind you might run:
+
+```bash
+$ rustdoc src/lib.rs --test-runtool valgrind
+```
+
+Another use case would be to run a test inside an emulator, or through a Virtual Machine.
+
 ## `--target`: generate documentation for the specified target triple
 
 Using this flag looks like this:
diff --git a/src/doc/rustdoc/src/read-documentation/search.md b/src/doc/rustdoc/src/read-documentation/search.md
index bace2f5f953..5635f68b1b3 100644
--- a/src/doc/rustdoc/src/read-documentation/search.md
+++ b/src/doc/rustdoc/src/read-documentation/search.md
@@ -89,7 +89,7 @@ the standard library and functions that are included in the results list:
 
 ### Non-functions in type-based search
 Certain items that are not functions are treated as though they
-were a semantically equivelent function.
+were a semantically equivalent function.
 
 For example, struct fields are treated as though they were getter methods.
 This means that a search for `CpuidResult -> u32` will show
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index d4ff69a9933..69e5a5adbec 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -631,60 +631,6 @@ The generated output (formatted) will look like this:
 `--output-format html` has no effect, as the default output is HTML. This is
 accepted on stable, even though the other options for this flag aren't.
 
-## `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
-
- * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
-
-Using this flag looks like this:
-
-```bash
-$ rustdoc src/lib.rs -Z unstable-options --enable-per-target-ignores
-```
-
-This flag allows you to tag doctests with compiletest style `ignore-foo` filters that prevent
-rustdoc from running that test if the target triple string contains foo. For example:
-
-```rust
-///```ignore-foo,ignore-bar
-///assert!(2 == 2);
-///```
-struct Foo;
-```
-
-This will not be run when the build target is `super-awesome-foo` or `less-bar-awesome`.
-If the flag is not enabled, then rustdoc will consume the filter, but do nothing with it, and
-the above example will be run for all targets.
-If you want to preserve backwards compatibility for older versions of rustdoc, you can use
-
-```rust
-///```ignore,ignore-foo
-///assert!(2 == 2);
-///```
-struct Foo;
-```
-
-In older versions, this will be ignored on all targets, but on newer versions `ignore-gnu` will
-override `ignore`.
-
-## `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it
-
- * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
-
-Using these options looks like this:
-
-```bash
-$ rustdoc src/lib.rs -Z unstable-options --runtool runner --runtool-arg --do-thing --runtool-arg --do-other-thing
-```
-
-These options can be used to run the doctest under a program, and also pass arguments to
-that program. For example, if you want to run your doctests under valgrind you might run
-
-```bash
-$ rustdoc src/lib.rs -Z unstable-options --runtool valgrind
-```
-
-Another use case would be to run a test inside an emulator, or through a Virtual Machine.
-
 ## `--with-examples`: include examples of uses of items as documentation
 
  * Tracking issue: [#88791](https://github.com/rust-lang/rust/issues/88791)
diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
index b921f677857..077b02d603d 100644
--- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md
+++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md
@@ -427,6 +427,43 @@ should not be merged with the others. So the previous code should use it:
 In this case, it means that the line information will not change if you add/remove other
 doctests.
 
+### Ignoring targets
+
+Attributes starting with `ignore-` can be used to ignore doctests for specific
+targets. For example, `ignore-x86_64` will avoid building doctests when the
+target name contains `x86_64`.
+
+```rust
+/// ```ignore-x86_64
+/// assert!(2 == 2);
+/// ```
+struct Foo;
+```
+
+This doctest will not be built for targets such as `x86_64-unknown-linux-gnu`.
+
+Multiple ignore attributes can be specified to ignore multiple targets:
+
+```rust
+/// ```ignore-x86_64,ignore-windows
+/// assert!(2 == 2);
+/// ```
+struct Foo;
+```
+
+If you want to preserve backwards compatibility for older versions of rustdoc,
+you can specify both `ignore` and `ignore-`, such as:
+
+```rust
+/// ```ignore,ignore-x86_64
+/// assert!(2 == 2);
+/// ```
+struct Foo;
+```
+
+In older versions, this will be ignored on all targets, but starting with
+version CURRENT_RUSTC_VERSION, `ignore-x86_64` will override `ignore`.
+
 ### Custom CSS classes for code blocks
 
 ```rust
diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md
index 4366172fb99..8a38d155e3d 100644
--- a/src/doc/unstable-book/src/library-features/concat-idents.md
+++ b/src/doc/unstable-book/src/library-features/concat-idents.md
@@ -2,7 +2,10 @@
 
 The tracking issue for this feature is: [#29599]
 
+This feature is deprecated, to be replaced by [`macro_metavar_expr_concat`].
+
 [#29599]: https://github.com/rust-lang/rust/issues/29599
+[`macro_metavar_expr_concat`]: https://github.com/rust-lang/rust/issues/124225
 
 ------------------------
 
diff --git a/src/gcc b/src/gcc
-Subproject 13cc8243226a9028bb08ab6c5e1c5fe6d533bcd
+Subproject 0ea98a1365b81f7488073512c850e8ee951a4af
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 23a2bcd9011..4ef73ff48ed 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -124,13 +124,9 @@ pub(crate) struct Options {
     /// temporary directory if not set.
     pub(crate) persist_doctests: Option<PathBuf>,
     /// Runtool to run doctests with
-    pub(crate) runtool: Option<String>,
+    pub(crate) test_runtool: Option<String>,
     /// Arguments to pass to the runtool
-    pub(crate) runtool_args: Vec<String>,
-    /// Whether to allow ignoring doctests on a per-target basis
-    /// For example, using ignore-foo to ignore running the doctest on any target that
-    /// contains "foo" as a substring
-    pub(crate) enable_per_target_ignores: bool,
+    pub(crate) test_runtool_args: Vec<String>,
     /// Do not run doctests, compile them if should_test is active.
     pub(crate) no_run: bool,
     /// What sources are being mapped.
@@ -215,9 +211,8 @@ impl fmt::Debug for Options {
             .field("persist_doctests", &self.persist_doctests)
             .field("show_coverage", &self.show_coverage)
             .field("crate_version", &self.crate_version)
-            .field("runtool", &self.runtool)
-            .field("runtool_args", &self.runtool_args)
-            .field("enable-per-target-ignores", &self.enable_per_target_ignores)
+            .field("test_runtool", &self.test_runtool)
+            .field("test_runtool_args", &self.test_runtool_args)
             .field("run_check", &self.run_check)
             .field("no_run", &self.no_run)
             .field("test_builder_wrappers", &self.test_builder_wrappers)
@@ -779,9 +774,8 @@ impl Options {
         let unstable_opts_strs = matches.opt_strs("Z");
         let lib_strs = matches.opt_strs("L");
         let extern_strs = matches.opt_strs("extern");
-        let runtool = matches.opt_str("runtool");
-        let runtool_args = matches.opt_strs("runtool-arg");
-        let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores");
+        let test_runtool = matches.opt_str("test-runtool");
+        let test_runtool_args = matches.opt_strs("test-runtool-arg");
         let document_private = matches.opt_present("document-private-items");
         let document_hidden = matches.opt_present("document-hidden-items");
         let run_check = matches.opt_present("check");
@@ -843,9 +837,8 @@ impl Options {
             crate_version,
             test_run_directory,
             persist_doctests,
-            runtool,
-            runtool_args,
-            enable_per_target_ignores,
+            test_runtool,
+            test_runtool_args,
             test_builder,
             run_check,
             no_run,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 88eaa52c6de..829a9ca6e7d 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -219,11 +219,9 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions
             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);
-            let enable_per_target_ignores = options.enable_per_target_ignores;
 
             let hir_collector = HirCollector::new(
                 ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()),
-                enable_per_target_ignores,
                 tcx,
             );
             let tests = hir_collector.collect_crate();
@@ -782,10 +780,10 @@ fn run_test(
     let mut cmd;
 
     let output_file = make_maybe_absolute_path(output_file);
-    if let Some(tool) = &rustdoc_options.runtool {
+    if let Some(tool) = &rustdoc_options.test_runtool {
         let tool = make_maybe_absolute_path(tool.into());
         cmd = Command::new(tool);
-        cmd.args(&rustdoc_options.runtool_args);
+        cmd.args(&rustdoc_options.test_runtool_args);
         cmd.arg(&output_file);
     } else {
         cmd = Command::new(&output_file);
diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs
index a0d39ce749d..497a8d7c4a7 100644
--- a/src/librustdoc/doctest/markdown.rs
+++ b/src/librustdoc/doctest/markdown.rs
@@ -104,13 +104,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> {
     };
     let codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
 
-    find_testable_code(
-        &input_str,
-        &mut md_collector,
-        codes,
-        options.enable_per_target_ignores,
-        None,
-    );
+    find_testable_code(&input_str, &mut md_collector, codes, None);
 
     let mut collector = CreateRunnableDocTests::new(options.clone(), opts);
     md_collector.tests.into_iter().for_each(|t| collector.add_test(t));
diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs
index 784d628805d..39a4f23560a 100644
--- a/src/librustdoc/doctest/runner.rs
+++ b/src/librustdoc/doctest/runner.rs
@@ -131,7 +131,22 @@ mod __doctest_mod {{
             .output()
             .expect(\"failed to run command\");
         if !out.status.success() {{
-            eprint!(\"{{}}\", String::from_utf8_lossy(&out.stderr));
+            if let Some(code) = out.status.code() {{
+                eprintln!(\"Test executable failed (exit status: {{code}}).\");
+            }} else {{
+                eprintln!(\"Test executable failed (terminated by signal).\");
+            }}
+            if !out.stdout.is_empty() || !out.stderr.is_empty() {{
+                eprintln!();
+            }}
+            if !out.stdout.is_empty() {{
+                eprintln!(\"stdout:\");
+                eprintln!(\"{{}}\", String::from_utf8_lossy(&out.stdout));
+            }}
+            if !out.stderr.is_empty() {{
+                eprintln!(\"stderr:\");
+                eprintln!(\"{{}}\", String::from_utf8_lossy(&out.stderr));
+            }}
             ExitCode::FAILURE
         }} else {{
             ExitCode::SUCCESS
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index be2dea641d7..43dcfab880b 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -63,19 +63,18 @@ impl DocTestVisitor for RustCollector {
 pub(super) struct HirCollector<'tcx> {
     codes: ErrorCodes,
     tcx: TyCtxt<'tcx>,
-    enable_per_target_ignores: bool,
     collector: RustCollector,
 }
 
 impl<'tcx> HirCollector<'tcx> {
-    pub fn new(codes: ErrorCodes, enable_per_target_ignores: bool, tcx: TyCtxt<'tcx>) -> Self {
+    pub fn new(codes: ErrorCodes, tcx: TyCtxt<'tcx>) -> Self {
         let collector = RustCollector {
             source_map: tcx.sess.psess.clone_source_map(),
             cur_path: vec![],
             position: DUMMY_SP,
             tests: vec![],
         };
-        Self { codes, enable_per_target_ignores, tcx, collector }
+        Self { codes, tcx, collector }
     }
 
     pub fn collect_crate(mut self) -> Vec<ScrapedDocTest> {
@@ -131,7 +130,6 @@ impl HirCollector<'_> {
                 &doc,
                 &mut self.collector,
                 self.codes,
-                self.enable_per_target_ignores,
                 Some(&crate::html::markdown::ExtraInfo::new(self.tcx, def_id, span)),
             );
         }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 44134bda5ea..fc46293e7ea 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -246,7 +246,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             match kind {
                 CodeBlockKind::Fenced(ref lang) => {
                     let parse_result =
-                        LangString::parse_without_check(lang, self.check_error_codes, false);
+                        LangString::parse_without_check(lang, self.check_error_codes);
                     if !parse_result.rust {
                         let added_classes = parse_result.added_classes;
                         let lang_string = if let Some(lang) = parse_result.unknown.first() {
@@ -707,17 +707,15 @@ pub(crate) fn find_testable_code<T: doctest::DocTestVisitor>(
     doc: &str,
     tests: &mut T,
     error_codes: ErrorCodes,
-    enable_per_target_ignores: bool,
     extra_info: Option<&ExtraInfo<'_>>,
 ) {
-    find_codes(doc, tests, error_codes, enable_per_target_ignores, extra_info, false)
+    find_codes(doc, tests, error_codes, extra_info, false)
 }
 
 pub(crate) fn find_codes<T: doctest::DocTestVisitor>(
     doc: &str,
     tests: &mut T,
     error_codes: ErrorCodes,
-    enable_per_target_ignores: bool,
     extra_info: Option<&ExtraInfo<'_>>,
     include_non_rust: bool,
 ) {
@@ -733,12 +731,7 @@ pub(crate) fn find_codes<T: doctest::DocTestVisitor>(
                         if lang.is_empty() {
                             Default::default()
                         } else {
-                            LangString::parse(
-                                lang,
-                                error_codes,
-                                enable_per_target_ignores,
-                                extra_info,
-                            )
+                            LangString::parse(lang, error_codes, extra_info)
                         }
                     }
                     CodeBlockKind::Indented => Default::default(),
@@ -1162,18 +1155,13 @@ impl Default for LangString {
 }
 
 impl LangString {
-    fn parse_without_check(
-        string: &str,
-        allow_error_code_check: ErrorCodes,
-        enable_per_target_ignores: bool,
-    ) -> Self {
-        Self::parse(string, allow_error_code_check, enable_per_target_ignores, None)
+    fn parse_without_check(string: &str, allow_error_code_check: ErrorCodes) -> Self {
+        Self::parse(string, allow_error_code_check, None)
     }
 
     fn parse(
         string: &str,
         allow_error_code_check: ErrorCodes,
-        enable_per_target_ignores: bool,
         extra: Option<&ExtraInfo<'_>>,
     ) -> Self {
         let allow_error_code_check = allow_error_code_check.as_bool();
@@ -1203,10 +1191,8 @@ impl LangString {
                     LangStringToken::LangToken(x)
                         if let Some(ignore) = x.strip_prefix("ignore-") =>
                     {
-                        if enable_per_target_ignores {
-                            ignores.push(ignore.to_owned());
-                            seen_rust_tags = !seen_other_tags;
-                        }
+                        ignores.push(ignore.to_owned());
+                        seen_rust_tags = !seen_other_tags;
                     }
                     LangStringToken::LangToken("rust") => {
                         data.rust = true;
@@ -1968,7 +1954,7 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<Rust
                     let lang_string = if syntax.is_empty() {
                         Default::default()
                     } else {
-                        LangString::parse(syntax, ErrorCodes::Yes, false, Some(extra_info))
+                        LangString::parse(syntax, ErrorCodes::Yes, Some(extra_info))
                     };
                     if !lang_string.rust {
                         continue;
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index bb42b877a2c..784d0c5d21e 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -49,7 +49,7 @@ fn test_unique_id() {
 fn test_lang_string_parse() {
     fn t(lg: LangString) {
         let s = &lg.original;
-        assert_eq!(LangString::parse(s, ErrorCodes::Yes, true, None), lg)
+        assert_eq!(LangString::parse(s, ErrorCodes::Yes, None), lg)
     }
 
     t(Default::default());
@@ -479,7 +479,7 @@ fn test_markdown_html_escape() {
 fn test_find_testable_code_line() {
     fn t(input: &str, expect: &[usize]) {
         let mut lines = Vec::<usize>::new();
-        find_testable_code(input, &mut lines, ErrorCodes::No, false, None);
+        find_testable_code(input, &mut lines, ErrorCodes::No, None);
         assert_eq!(lines, expect);
     }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 7e17f09aecd..beaa6497b8c 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2086,6 +2086,7 @@ fn render_impl(
                     .split_summary_and_content()
                 })
                 .unwrap_or((None, None));
+
             write!(
                 w,
                 "{}",
@@ -2097,24 +2098,19 @@ fn render_impl(
                     use_absolute,
                     aliases,
                     before_dox.as_deref(),
+                    trait_.is_none() && impl_.items.is_empty(),
                 )
             )?;
             if toggled {
                 w.write_str("</summary>")?;
             }
 
-            if before_dox.is_some() {
-                if trait_.is_none() && impl_.items.is_empty() {
-                    w.write_str(
-                        "<div class=\"item-info\">\
-                         <div class=\"stab empty-impl\">This impl block contains no items.</div>\
-                     </div>",
-                    )?;
-                }
-                if let Some(after_dox) = after_dox {
-                    write!(w, "<div class=\"docblock\">{after_dox}</div>")?;
-                }
+            if before_dox.is_some()
+                && let Some(after_dox) = after_dox
+            {
+                write!(w, "<div class=\"docblock\">{after_dox}</div>")?;
             }
+
             if !default_impl_items.is_empty() || !impl_items.is_empty() {
                 w.write_str("<div class=\"impl-items\">")?;
                 close_tags.push("</div>");
@@ -2182,6 +2178,7 @@ fn render_impl_summary(
     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
     aliases: &[String],
     doc: Option<&str>,
+    impl_is_empty: bool,
 ) -> impl fmt::Display {
     fmt::from_fn(move |w| {
         let inner_impl = i.inner_impl();
@@ -2237,6 +2234,13 @@ fn render_impl_summary(
         }
 
         if let Some(doc) = doc {
+            if impl_is_empty {
+                w.write_str(
+                    "<div class=\"item-info\">\
+                         <div class=\"stab empty-impl\">This impl block contains no items.</div>\
+                     </div>",
+                )?;
+            }
             write!(w, "<div class=\"docblock\">{doc}</div>")?;
         }
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index a6dd06b76ea..19ac24a5d6e 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -2319,7 +2319,10 @@ details.toggle > summary:not(.hideme)::before {
 	doc block while aligning it with the impl block items. */
 .implementors-toggle > .docblock,
 /* We indent trait items as well. */
-#main-content > .methods > :not(.item-info) {
+#main-content > .methods > :not(.item-info),
+.impl > .item-info,
+.impl > .docblock,
+.impl + .docblock {
 	margin-left: var(--impl-items-indent);
 }
 
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 4fe5e13c3af..44bd96a7e45 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -507,28 +507,20 @@ fn opts() -> Vec<RustcOptGroup> {
             "",
         ),
         opt(
-            Unstable,
-            FlagMulti,
-            "",
-            "enable-per-target-ignores",
-            "parse ignore-foo for ignoring doctests on a per-target basis",
-            "",
-        ),
-        opt(
-            Unstable,
+            Stable,
             Opt,
             "",
-            "runtool",
+            "test-runtool",
             "",
             "The tool to run tests with when building for a different target than host",
         ),
         opt(
-            Unstable,
+            Stable,
             Multi,
             "",
-            "runtool-arg",
+            "test-runtool-arg",
             "",
-            "One (of possibly many) arguments to pass to the runtool",
+            "One argument (of possibly many) to pass to the runtool",
         ),
         opt(
             Unstable,
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 761282bde7c..c9f0baaaa4c 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -212,7 +212,7 @@ impl DocVisitor<'_> for CoverageCalculator<'_, '_> {
                 let has_docs = !i.attrs.doc_strings.is_empty();
                 let mut tests = Tests { found_tests: 0 };
 
-                find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, false, None);
+                find_testable_code(&i.doc_value(), &mut tests, ErrorCodes::No, None);
 
                 let has_doc_example = tests.found_tests != 0;
                 let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap();
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 70dbb944d4c..8028afea363 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -122,7 +122,7 @@ pub(crate) fn look_for_tests(cx: &DocContext<'_>, dox: &str, item: &Item) {
 
     let mut tests = Tests { found_tests: 0 };
 
-    find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
+    find_testable_code(dox, &mut tests, ErrorCodes::No, None);
 
     if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples() {
         if should_have_doc_example(cx, item) {
diff --git a/src/stage0 b/src/stage0
index 6e86501a72a..06080e3a8c1 100644
--- a/src/stage0
+++ b/src/stage0
@@ -2,7 +2,6 @@ dist_server=https://static.rust-lang.org
 artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds
 artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt
 git_merge_commit_email=bors@rust-lang.org
-git_repository=rust-lang/rust
 nightly_branch=master
 
 # The configuration above this comment is editable, and can be changed
diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs
index d679084ae44..680437cce4f 100644
--- a/src/tools/bump-stage0/src/main.rs
+++ b/src/tools/bump-stage0/src/main.rs
@@ -61,7 +61,6 @@ impl Tool {
             artifacts_server,
             artifacts_with_llvm_assertions_server,
             git_merge_commit_email,
-            git_repository,
             nightly_branch,
         } = &self.config;
 
@@ -72,7 +71,6 @@ impl Tool {
             artifacts_with_llvm_assertions_server
         ));
         file_content.push_str(&format!("git_merge_commit_email={}\n", git_merge_commit_email));
-        file_content.push_str(&format!("git_repository={}\n", git_repository));
         file_content.push_str(&format!("nightly_branch={}\n", nightly_branch));
 
         file_content.push_str("\n");
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject d811228b14ae2707323f37346aee3f4147e247e
+Subproject 7918c7eb59614c39f1c4e27e99d557720976bdd
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
index c82276b358e..e696896538e 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
@@ -1,7 +1,13 @@
 //@aux-build:proc_macro_attr.rs
 
 #![warn(clippy::blocks_in_conditions)]
-#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)]
+#![allow(
+    unused,
+    unnecessary_transmutes,
+    clippy::let_and_return,
+    clippy::needless_if,
+    clippy::missing_transmute_annotations
+)]
 #![warn(clippy::nonminimal_bool)]
 
 macro_rules! blocky {
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
index 6a4a7c62106..8c8f3249b8a 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
@@ -1,7 +1,13 @@
 //@aux-build:proc_macro_attr.rs
 
 #![warn(clippy::blocks_in_conditions)]
-#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)]
+#![allow(
+    unused,
+    unnecessary_transmutes,
+    clippy::let_and_return,
+    clippy::needless_if,
+    clippy::missing_transmute_annotations
+)]
 #![warn(clippy::nonminimal_bool)]
 
 macro_rules! blocky {
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
index e57eca5dcee..41ff59c683e 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
@@ -1,5 +1,5 @@
 error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
-  --> tests/ui/blocks_in_conditions.rs:25:5
+  --> tests/ui/blocks_in_conditions.rs:31:5
    |
 LL | /     if {
 LL | |
@@ -20,13 +20,13 @@ LL ~     }; if res {
    |
 
 error: omit braces around single expression condition
-  --> tests/ui/blocks_in_conditions.rs:37:8
+  --> tests/ui/blocks_in_conditions.rs:43:8
    |
 LL |     if { true } { 6 } else { 10 }
    |        ^^^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> tests/ui/blocks_in_conditions.rs:43:8
+  --> tests/ui/blocks_in_conditions.rs:49:8
    |
 LL |     if true && x == 3 { 6 } else { 10 }
    |        ^^^^^^^^^^^^^^ help: try: `x == 3`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
index 4a1886c08af..776b0a93bf7 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1782.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
@@ -1,6 +1,6 @@
 //@ check-pass
 
-#![allow(dead_code, unused_variables, invalid_null_arguments)]
+#![allow(dead_code, unused_variables, invalid_null_arguments, unnecessary_transmutes)]
 #![allow(clippy::unnecessary_cast, clippy::missing_transmute_annotations)]
 
 /// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs
index 8c8674ac356..2b8b6c539ad 100644
--- a/src/tools/clippy/tests/ui/transmute.rs
+++ b/src/tools/clippy/tests/ui/transmute.rs
@@ -3,6 +3,7 @@
 #![allow(
     dead_code,
     clippy::borrow_as_ptr,
+    unnecessary_transmutes,
     clippy::needless_lifetimes,
     clippy::missing_transmute_annotations
 )]
diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr
index 4219e09d2ab..1bb70151965 100644
--- a/src/tools/clippy/tests/ui/transmute.stderr
+++ b/src/tools/clippy/tests/ui/transmute.stderr
@@ -1,5 +1,5 @@
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:32:27
+  --> tests/ui/transmute.rs:33:27
    |
 LL |         let _: *const T = core::mem::transmute(t);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
@@ -8,61 +8,61 @@ LL |         let _: *const T = core::mem::transmute(t);
    = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]`
 
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:35:25
+  --> tests/ui/transmute.rs:36:25
    |
 LL |         let _: *mut T = core::mem::transmute(t);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 
 error: transmute from a reference to a pointer
-  --> tests/ui/transmute.rs:38:27
+  --> tests/ui/transmute.rs:39:27
    |
 LL |         let _: *const U = core::mem::transmute(t);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:46:27
+  --> tests/ui/transmute.rs:47:27
    |
 LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:49:27
+  --> tests/ui/transmute.rs:50:27
    |
 LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:52:27
+  --> tests/ui/transmute.rs:53:27
    |
 LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:55:27
+  --> tests/ui/transmute.rs:56:27
    |
 LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> tests/ui/transmute.rs:58:27
+  --> tests/ui/transmute.rs:59:27
    |
 LL |         let _: Vec<i32> = my_transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from an integer to a pointer
-  --> tests/ui/transmute.rs:61:31
+  --> tests/ui/transmute.rs:62:31
    |
 LL |         let _: *const usize = std::mem::transmute(5_isize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
 
 error: transmute from an integer to a pointer
-  --> tests/ui/transmute.rs:66:31
+  --> tests/ui/transmute.rs:67:31
    |
 LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
 
 error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
-  --> tests/ui/transmute.rs:98:24
+  --> tests/ui/transmute.rs:99:24
    |
 LL |         let _: Usize = core::mem::transmute(int_const_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,25 +71,25 @@ LL |         let _: Usize = core::mem::transmute(int_const_ptr);
    = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]`
 
 error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
-  --> tests/ui/transmute.rs:101:24
+  --> tests/ui/transmute.rs:102:24
    |
 LL |         let _: Usize = core::mem::transmute(int_mut_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
-  --> tests/ui/transmute.rs:104:31
+  --> tests/ui/transmute.rs:105:31
    |
 LL |         let _: *const Usize = core::mem::transmute(my_int());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
-  --> tests/ui/transmute.rs:107:29
+  --> tests/ui/transmute.rs:108:29
    |
 LL |         let _: *mut Usize = core::mem::transmute(my_int());
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a `u8` to a `bool`
-  --> tests/ui/transmute.rs:114:28
+  --> tests/ui/transmute.rs:115:28
    |
 LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
@@ -98,7 +98,7 @@ LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]`
 
 error: transmute from a `u16` to a `f16`
-  --> tests/ui/transmute.rs:121:31
+  --> tests/ui/transmute.rs:122:31
    |
 LL |         let _: f16 = unsafe { std::mem::transmute(0_u16) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
@@ -107,97 +107,97 @@ LL |         let _: f16 = unsafe { std::mem::transmute(0_u16) };
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]`
 
 error: transmute from a `i16` to a `f16`
-  --> tests/ui/transmute.rs:124:31
+  --> tests/ui/transmute.rs:125:31
    |
 LL |         let _: f16 = unsafe { std::mem::transmute(0_i16) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)`
 
 error: transmute from a `u32` to a `f32`
-  --> tests/ui/transmute.rs:127:31
+  --> tests/ui/transmute.rs:128:31
    |
 LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
 
 error: transmute from a `i32` to a `f32`
-  --> tests/ui/transmute.rs:130:31
+  --> tests/ui/transmute.rs:131:31
    |
 LL |         let _: f32 = unsafe { std::mem::transmute(0_i32) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
 
 error: transmute from a `u64` to a `f64`
-  --> tests/ui/transmute.rs:133:31
+  --> tests/ui/transmute.rs:134:31
    |
 LL |         let _: f64 = unsafe { std::mem::transmute(0_u64) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
 
 error: transmute from a `i64` to a `f64`
-  --> tests/ui/transmute.rs:136:31
+  --> tests/ui/transmute.rs:137:31
    |
 LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 
 error: transmute from a `u128` to a `f128`
-  --> tests/ui/transmute.rs:139:32
+  --> tests/ui/transmute.rs:140:32
    |
 LL |         let _: f128 = unsafe { std::mem::transmute(0_u128) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)`
 
 error: transmute from a `i128` to a `f128`
-  --> tests/ui/transmute.rs:142:32
+  --> tests/ui/transmute.rs:143:32
    |
 LL |         let _: f128 = unsafe { std::mem::transmute(0_i128) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
 
 error: transmute from a `u16` to a `f16`
-  --> tests/ui/transmute.rs:147:39
+  --> tests/ui/transmute.rs:148:39
    |
 LL |         const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
 
 error: transmute from a `u32` to a `f32`
-  --> tests/ui/transmute.rs:150:39
+  --> tests/ui/transmute.rs:151:39
    |
 LL |         const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
 
 error: transmute from a `i64` to a `f64`
-  --> tests/ui/transmute.rs:153:39
+  --> tests/ui/transmute.rs:154:39
    |
 LL |         const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 
 error: transmute from a `i128` to a `f128`
-  --> tests/ui/transmute.rs:156:41
+  --> tests/ui/transmute.rs:157:41
    |
 LL |         const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
 
 error: transmute from a `i16` to a `f16`
-  --> tests/ui/transmute.rs:160:22
+  --> tests/ui/transmute.rs:161:22
    |
 LL |             unsafe { std::mem::transmute(v) }
    |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)`
 
 error: transmute from a `i32` to a `f32`
-  --> tests/ui/transmute.rs:165:22
+  --> tests/ui/transmute.rs:166:22
    |
 LL |             unsafe { std::mem::transmute(v) }
    |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)`
 
 error: transmute from a `u64` to a `f64`
-  --> tests/ui/transmute.rs:170:22
+  --> tests/ui/transmute.rs:171:22
    |
 LL |             unsafe { std::mem::transmute(v) }
    |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)`
 
 error: transmute from a `u128` to a `f128`
-  --> tests/ui/transmute.rs:175:22
+  --> tests/ui/transmute.rs:176:22
    |
 LL |             unsafe { std::mem::transmute(v) }
    |                      ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)`
 
 error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:184:30
+  --> tests/ui/transmute.rs:185:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
@@ -206,121 +206,121 @@ LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    = help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]`
 
 error: transmute from a `u32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:187:30
+  --> tests/ui/transmute.rs:188:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0u32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
 
 error: transmute from a `u128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:190:31
+  --> tests/ui/transmute.rs:191:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0u128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
 
 error: transmute from a `i8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:193:30
+  --> tests/ui/transmute.rs:194:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0i8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
 
 error: transmute from a `i32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:196:30
+  --> tests/ui/transmute.rs:197:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0i32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
 
 error: transmute from a `i128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:199:31
+  --> tests/ui/transmute.rs:200:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0i128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 
 error: transmute from a `f16` to a `[u8; 2]`
-  --> tests/ui/transmute.rs:202:30
+  --> tests/ui/transmute.rs:203:30
    |
 LL |             let _: [u8; 2] = std::mem::transmute(0.0f16);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
 
 error: transmute from a `f32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:205:30
+  --> tests/ui/transmute.rs:206:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
 
 error: transmute from a `f64` to a `[u8; 8]`
-  --> tests/ui/transmute.rs:208:30
+  --> tests/ui/transmute.rs:209:30
    |
 LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
 
 error: transmute from a `f128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:211:31
+  --> tests/ui/transmute.rs:212:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0.0f128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
 
 error: transmute from a `u8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:217:30
+  --> tests/ui/transmute.rs:218:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
 
 error: transmute from a `u32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:220:30
+  --> tests/ui/transmute.rs:221:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0u32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
 
 error: transmute from a `u128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:223:31
+  --> tests/ui/transmute.rs:224:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0u128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
 
 error: transmute from a `i8` to a `[u8; 1]`
-  --> tests/ui/transmute.rs:226:30
+  --> tests/ui/transmute.rs:227:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0i8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
 
 error: transmute from a `i32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:229:30
+  --> tests/ui/transmute.rs:230:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0i32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
 
 error: transmute from a `i128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:232:31
+  --> tests/ui/transmute.rs:233:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0i128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 
 error: transmute from a `f16` to a `[u8; 2]`
-  --> tests/ui/transmute.rs:235:30
+  --> tests/ui/transmute.rs:236:30
    |
 LL |             let _: [u8; 2] = std::mem::transmute(0.0f16);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
 
 error: transmute from a `f32` to a `[u8; 4]`
-  --> tests/ui/transmute.rs:238:30
+  --> tests/ui/transmute.rs:239:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
 
 error: transmute from a `f64` to a `[u8; 8]`
-  --> tests/ui/transmute.rs:241:30
+  --> tests/ui/transmute.rs:242:30
    |
 LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
 
 error: transmute from a `f128` to a `[u8; 16]`
-  --> tests/ui/transmute.rs:244:31
+  --> tests/ui/transmute.rs:245:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0.0f128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:253:28
+  --> tests/ui/transmute.rs:254:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(B) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@@ -329,13 +329,13 @@ LL |     let _: &str = unsafe { std::mem::transmute(B) };
    = help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-  --> tests/ui/transmute.rs:256:32
+  --> tests/ui/transmute.rs:257:32
    |
 LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> tests/ui/transmute.rs:259:30
+  --> tests/ui/transmute.rs:260:30
    |
 LL |     const _: &str = unsafe { std::mem::transmute(B) };
    |                              ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
index 1f97b997eaa..844445907d7 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::transmute_float_to_int)]
-#![allow(clippy::missing_transmute_annotations)]
+#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
 #![feature(f128)]
 #![feature(f16)]
 
diff --git a/src/tools/clippy/tests/ui/transmute_float_to_int.rs b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
index 788a7e1026c..a1f3b15bbfe 100644
--- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs
+++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::transmute_float_to_int)]
-#![allow(clippy::missing_transmute_annotations)]
+#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
 #![feature(f128)]
 #![feature(f16)]
 
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed
index b5425a2e9e8..28644aa9ebb 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations)]
+#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
 
 fn int_to_char() {
     let _: char = unsafe { std::char::from_u32(0_u32).unwrap() };
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char.rs b/src/tools/clippy/tests/ui/transmute_int_to_char.rs
index b24bb177c9f..8c83ecc8914 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char.rs
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations)]
+#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
 
 fn int_to_char() {
     let _: char = unsafe { std::mem::transmute(0_u32) };
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed
index e525751e306..e6e09a2be4b 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.fixed
@@ -1,7 +1,7 @@
 #![no_std]
 #![feature(lang_items)]
 #![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations)]
+#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
 
 use core::panic::PanicInfo;
 
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
index 7cb508ceaf3..0f2106df00e 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
+++ b/src/tools/clippy/tests/ui/transmute_int_to_char_no_std.rs
@@ -1,7 +1,7 @@
 #![no_std]
 #![feature(lang_items)]
 #![warn(clippy::transmute_int_to_char)]
-#![allow(clippy::missing_transmute_annotations)]
+#![allow(clippy::missing_transmute_annotations, unnecessary_transmutes)]
 
 use core::panic::PanicInfo;
 
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index ba1b8f25658..93f7b1cb7cf 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -18,6 +18,7 @@ glob = "0.3.0"
 home = "0.5.5"
 indexmap = "2.0.0"
 miropt-test-tools = { path = "../miropt-test-tools" }
+rayon = "1.10.0"
 regex = "1.0"
 rustfix = "0.8.1"
 semver = { version = "1.0.23", features = ["serde"] }
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index de93e2b99ee..e0132056d6c 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -399,7 +399,6 @@ pub struct Config {
     pub nocapture: bool,
 
     // Needed both to construct build_helper::git::GitConfig
-    pub git_repository: String,
     pub nightly_branch: String,
     pub git_merge_commit_email: String,
 
@@ -514,7 +513,6 @@ impl Config {
 
     pub fn git_config(&self) -> GitConfig<'_> {
         GitConfig {
-            git_repository: &self.git_repository,
             nightly_branch: &self.nightly_branch,
             git_merge_commit_email: &self.git_merge_commit_email,
         }
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 2525e0adc83..e7e5ff0ab00 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -175,7 +175,6 @@ impl ConfigBuilder {
             self.host.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
             "--target",
             self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
-            "--git-repository=",
             "--nightly-branch=",
             "--git-merge-commit-email=",
             "--minicore-path=",
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 7948a273c1e..788bafaa724 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -33,6 +33,7 @@ use std::{env, fs, vec};
 use build_helper::git::{get_git_modified_files, get_git_untracked_files};
 use camino::{Utf8Path, Utf8PathBuf};
 use getopts::Options;
+use rayon::iter::{ParallelBridge, ParallelIterator};
 use tracing::*;
 use walkdir::WalkDir;
 
@@ -188,7 +189,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "run tests which rely on commit version being compiled into the binaries",
         )
         .optopt("", "edition", "default Rust edition", "EDITION")
-        .reqopt("", "git-repository", "name of the git repository", "ORG/REPO")
         .reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH")
         .reqopt(
             "",
@@ -440,7 +440,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
 
         nocapture: matches.opt_present("no-capture"),
 
-        git_repository: matches.opt_str("git-repository").unwrap(),
         nightly_branch: matches.opt_str("nightly-branch").unwrap(),
         git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
 
@@ -641,6 +640,18 @@ struct TestCollector {
     poisoned: bool,
 }
 
+impl TestCollector {
+    fn new() -> Self {
+        TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false }
+    }
+
+    fn merge(&mut self, mut other: Self) {
+        self.tests.append(&mut other.tests);
+        self.found_path_stems.extend(other.found_path_stems);
+        self.poisoned |= other.poisoned;
+    }
+}
+
 /// Creates test structures for every test/revision in the test suite directory.
 ///
 /// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests),
@@ -659,10 +670,7 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest>
     let cache = HeadersCache::load(&config);
 
     let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests };
-    let mut collector =
-        TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false };
-
-    collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Utf8Path::new(""))
+    let collector = collect_tests_from_dir(&cx, &cx.config.src_test_suite_root, Utf8Path::new(""))
         .unwrap_or_else(|reason| {
             panic!("Could not read tests from {}: {reason}", cx.config.src_test_suite_root)
         });
@@ -768,25 +776,25 @@ fn modified_tests(config: &Config, dir: &Utf8Path) -> Result<Vec<Utf8PathBuf>, S
 /// that will be handed over to libtest.
 fn collect_tests_from_dir(
     cx: &TestCollectorCx,
-    collector: &mut TestCollector,
     dir: &Utf8Path,
     relative_dir_path: &Utf8Path,
-) -> io::Result<()> {
+) -> io::Result<TestCollector> {
     // Ignore directories that contain a file named `compiletest-ignore-dir`.
     if dir.join("compiletest-ignore-dir").exists() {
-        return Ok(());
+        return Ok(TestCollector::new());
     }
 
     // For run-make tests, a "test file" is actually a directory that contains an `rmake.rs`.
     if cx.config.mode == Mode::RunMake {
+        let mut collector = TestCollector::new();
         if dir.join("rmake.rs").exists() {
             let paths = TestPaths {
                 file: dir.to_path_buf(),
                 relative_dir: relative_dir_path.parent().unwrap().to_path_buf(),
             };
-            make_test(cx, collector, &paths);
+            make_test(cx, &mut collector, &paths);
             // This directory is a test, so don't try to find other tests inside it.
-            return Ok(());
+            return Ok(collector);
         }
     }
 
@@ -803,36 +811,47 @@ fn collect_tests_from_dir(
     // subdirectories we find, except for `auxiliary` directories.
     // FIXME: this walks full tests tree, even if we have something to ignore
     // use walkdir/ignore like in tidy?
-    for file in fs::read_dir(dir.as_std_path())? {
-        let file = file?;
-        let file_path = Utf8PathBuf::try_from(file.path()).unwrap();
-        let file_name = file_path.file_name().unwrap();
-
-        if is_test(file_name)
-            && (!cx.config.only_modified || cx.modified_tests.contains(&file_path))
-        {
-            // We found a test file, so create the corresponding libtest structures.
-            debug!(%file_path, "found test file");
-
-            // Record the stem of the test file, to check for overlaps later.
-            let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap());
-            collector.found_path_stems.insert(rel_test_path);
-
-            let paths =
-                TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() };
-            make_test(cx, collector, &paths);
-        } else if file_path.is_dir() {
-            // Recurse to find more tests in a subdirectory.
-            let relative_file_path = relative_dir_path.join(file_name);
-            if file_name != "auxiliary" {
-                debug!(%file_path, "found directory");
-                collect_tests_from_dir(cx, collector, &file_path, &relative_file_path)?;
+    fs::read_dir(dir.as_std_path())?
+        .par_bridge()
+        .map(|file| {
+            let mut collector = TestCollector::new();
+            let file = file?;
+            let file_path = Utf8PathBuf::try_from(file.path()).unwrap();
+            let file_name = file_path.file_name().unwrap();
+
+            if is_test(file_name)
+                && (!cx.config.only_modified || cx.modified_tests.contains(&file_path))
+            {
+                // We found a test file, so create the corresponding libtest structures.
+                debug!(%file_path, "found test file");
+
+                // Record the stem of the test file, to check for overlaps later.
+                let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap());
+                collector.found_path_stems.insert(rel_test_path);
+
+                let paths =
+                    TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() };
+                make_test(cx, &mut collector, &paths);
+            } else if file_path.is_dir() {
+                // Recurse to find more tests in a subdirectory.
+                let relative_file_path = relative_dir_path.join(file_name);
+                if file_name != "auxiliary" {
+                    debug!(%file_path, "found directory");
+                    collector.merge(collect_tests_from_dir(cx, &file_path, &relative_file_path)?);
+                }
+            } else {
+                debug!(%file_path, "found other file/directory");
             }
-        } else {
-            debug!(%file_path, "found other file/directory");
-        }
-    }
-    Ok(())
+            Ok(collector)
+        })
+        .reduce(
+            || Ok(TestCollector::new()),
+            |a, b| {
+                let mut a = a?;
+                a.merge(b?);
+                Ok(a)
+            },
+        )
 }
 
 /// Returns true if `file_name` looks like a proper test file name.
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index cc09463c358..fe23cce81e9 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1710,12 +1710,16 @@ impl<'test> TestCx<'test> {
         rustc.args(&self.props.compile_flags);
 
         // FIXME(jieyouxu): we should report a fatal error or warning if user wrote `-Cpanic=` with
-        // something that's not `abort`, however, by moving this last we should override previous
-        // `-Cpanic=`s
+        // something that's not `abort` and `-Cforce-unwind-tables` with a value that is not `yes`,
+        // however, by moving this last we should override previous `-Cpanic`s and
+        // `-Cforce-unwind-tables`s. Note that checking here is very fragile, because we'd have to
+        // account for all possible compile flag splittings (they have some... intricacies and are
+        // not yet normalized).
         //
         // `minicore` requires `#![no_std]` and `#![no_core]`, which means no unwinding panics.
         if self.props.add_core_stubs {
             rustc.arg("-Cpanic=abort");
+            rustc.arg("-Cforce-unwind-tables=yes");
         }
 
         rustc
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 9fd33e23204..d6c69d39e17 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -444,21 +444,15 @@ impl<'a> LintExtractor<'a> {
         fs::write(&tempfile, source)
             .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
         let mut cmd = Command::new(self.rustc_path);
-        if options.contains(&"edition2024") {
-            cmd.arg("--edition=2024");
-            cmd.arg("-Zunstable-options");
-        } else if options.contains(&"edition2021") {
-            cmd.arg("--edition=2021");
-        } else if options.contains(&"edition2018") {
-            cmd.arg("--edition=2018");
-        } else if options.contains(&"edition2015") {
-            cmd.arg("--edition=2015");
-        } else if options.contains(&"edition") {
-            panic!("lint-docs: unknown edition");
-        } else {
+        let edition = options
+            .iter()
+            .filter_map(|opt| opt.strip_prefix("edition"))
+            .next()
             // defaults to latest edition
-            cmd.arg("--edition=2021");
-        }
+            .unwrap_or("2024");
+        cmd.arg(format!("--edition={edition}"));
+        // Just in case this is an unstable edition.
+        cmd.arg("-Zunstable-options");
         cmd.arg("--error-format=json");
         cmd.arg("--target").arg(self.rustc_target);
         if let Some(target_linker) = self.rustc_linker {
diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs
index 7d9f77f3752..322ef0a6c2a 100644
--- a/src/tools/miri/cargo-miri/src/main.rs
+++ b/src/tools/miri/cargo-miri/src/main.rs
@@ -53,7 +53,7 @@ fn main() {
     //     with `RustcPhase::Rustdoc`. There we perform a check-build (needed to get the expected
     //     build failures for `compile_fail` doctests) and then store a JSON file with the
     //     information needed to run this test.
-    //   - We also set `--runtool` to ourselves, which ends up in `phase_runner` with
+    //   - We also set `--test-runtool` to ourselves, which ends up in `phase_runner` with
     //     `RunnerPhase::Rustdoc`. There we parse the JSON file written in `phase_rustc` and invoke
     //     the Miri driver for interpretation.
 
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 71ea07f3463..cb62e12413c 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -666,8 +666,8 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
         if arg == "--extern" {
             // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
             forward_patched_extern_arg(&mut args, &mut cmd);
-        } else if arg == "--runtool" {
-            // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support.
+        } else if arg == "--test-runtool" {
+            // An existing --test-runtool flag indicates cargo is running in cross-target mode, which we don't support.
             // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag;
             // otherwise, we won't be called as rustdoc at all.
             show_error!("cross-interpreting doctests is not currently supported by Miri.");
@@ -693,8 +693,8 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
     // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag:
     cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1");
 
-    // The `--test-builder` and `--runtool` arguments are unstable rustdoc features,
-    // which are disabled by default. We first need to enable them explicitly:
+    // The `--test-builder` is an unstable rustdoc features,
+    // which is disabled by default. We first need to enable them explicitly:
     cmd.arg("-Zunstable-options");
 
     // rustdoc needs to know the right sysroot.
@@ -705,7 +705,7 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
     // Make rustdoc call us back.
     let cargo_miri_path = env::current_exe().expect("current executable path invalid");
     cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments
-    cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument
+    cmd.arg("--test-runtool").arg(&cargo_miri_path); // invoked with just a single path argument
 
     debug_cmd("[cargo-miri rustdoc]", verbose, &cmd);
     exec(cmd)
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index a3525dcc77a..7d60a7e5c48 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -392,32 +392,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             #[rustfmt::skip]
-            | "fadd_algebraic"
-            | "fsub_algebraic"
-            | "fmul_algebraic"
-            | "fdiv_algebraic"
-            | "frem_algebraic"
-            => {
-                let [a, b] = check_intrinsic_arg_count(args)?;
-                let a = this.read_immediate(a)?;
-                let b = this.read_immediate(b)?;
-                let op = match intrinsic_name {
-                    "fadd_algebraic" => mir::BinOp::Add,
-                    "fsub_algebraic" => mir::BinOp::Sub,
-                    "fmul_algebraic" => mir::BinOp::Mul,
-                    "fdiv_algebraic" => mir::BinOp::Div,
-                    "frem_algebraic" => mir::BinOp::Rem,
-                    _ => bug!(),
-                };
-                let res = this.binary_op(op, &a, &b)?;
-                // `binary_op` already called `generate_nan` if needed.
-                // Apply a relative error of 4ULP to simulate non-deterministic precision loss
-                // due to optimizations.
-                let res = apply_random_float_error_to_imm(this, res, 2 /* log2(4) */)?;
-                this.write_immediate(*res, dest)?;
-            }
-
-            #[rustfmt::skip]
             | "fadd_fast"
             | "fsub_fast"
             | "fmul_fast"
diff --git a/src/tools/miri/tests/fail/validity/invalid_bool.rs b/src/tools/miri/tests/fail/validity/invalid_bool.rs
index 4f11bb2629f..bd448af834d 100644
--- a/src/tools/miri/tests/fail/validity/invalid_bool.rs
+++ b/src/tools/miri/tests/fail/validity/invalid_bool.rs
@@ -1,3 +1,4 @@
+#![allow(unnecessary_transmutes)]
 fn main() {
     let _b = unsafe { std::mem::transmute::<u8, bool>(2) }; //~ ERROR: expected a boolean
 }
diff --git a/src/tools/miri/tests/fail/validity/invalid_bool_op.rs b/src/tools/miri/tests/fail/validity/invalid_bool_op.rs
index fe9bb3bed7f..0cbe2d76dc6 100644
--- a/src/tools/miri/tests/fail/validity/invalid_bool_op.rs
+++ b/src/tools/miri/tests/fail/validity/invalid_bool_op.rs
@@ -2,6 +2,7 @@
 // Make sure we find these even with many checks disabled.
 //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
 
+#![allow(unnecessary_transmutes)]
 fn main() {
     let b = unsafe { std::mem::transmute::<u8, bool>(2) };
     let _x = b == std::hint::black_box(true); //~ ERROR: interpreting an invalid 8-bit value as a bool
diff --git a/src/tools/miri/tests/fail/validity/invalid_char.rs b/src/tools/miri/tests/fail/validity/invalid_char.rs
index 568892e5910..d57c933dac1 100644
--- a/src/tools/miri/tests/fail/validity/invalid_char.rs
+++ b/src/tools/miri/tests/fail/validity/invalid_char.rs
@@ -1,3 +1,4 @@
+#![allow(unnecessary_transmutes)]
 fn main() {
     assert!(std::char::from_u32(-1_i32 as u32).is_none());
     let _val = match unsafe { std::mem::transmute::<i32, char>(-1) } {
diff --git a/src/tools/miri/tests/fail/validity/invalid_char_op.rs b/src/tools/miri/tests/fail/validity/invalid_char_op.rs
index 69924822944..e3a5f837e18 100644
--- a/src/tools/miri/tests/fail/validity/invalid_char_op.rs
+++ b/src/tools/miri/tests/fail/validity/invalid_char_op.rs
@@ -2,6 +2,7 @@
 // Make sure we find these even with many checks disabled.
 //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
 
+#![allow(unnecessary_transmutes)]
 fn main() {
     let c = 0xFFFFFFu32;
     assert!(std::char::from_u32(c).is_none());
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index cd60b6bd563..575d70579a4 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -6,6 +6,7 @@
 #![feature(f16)]
 #![allow(arithmetic_overflow)]
 #![allow(internal_features)]
+#![allow(unnecessary_transmutes)]
 
 use std::any::type_name;
 use std::cmp::min;
diff --git a/src/tools/miri/tests/pass/issues/issue-miri-184.rs b/src/tools/miri/tests/pass/issues/issue-miri-184.rs
index 39c841403ef..964d850298f 100644
--- a/src/tools/miri/tests/pass/issues/issue-miri-184.rs
+++ b/src/tools/miri/tests/pass/issues/issue-miri-184.rs
@@ -1,3 +1,4 @@
+#![allow(unnecessary_transmutes)]
 pub fn main() {
     let bytes: [u8; 8] = unsafe { ::std::mem::transmute(0u64) };
     let _val: &[u8] = &bytes;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
index a629e2acfe9..882b5e3f795 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
@@ -368,7 +368,7 @@ unsafe fn load_m256i_word<T>(data: &[T], word_index: usize) -> __m256i {
 #[target_feature(enable = "avx512f")]
 unsafe fn load_m512i_word<T>(data: &[T], word_index: usize) -> __m512i {
     let byte_offset = word_index * 64 / size_of::<T>();
-    let pointer = data.as_ptr().add(byte_offset) as *const i32;
+    let pointer = data.as_ptr().add(byte_offset) as *const __m512i;
     _mm512_loadu_si512(black_box(pointer))
 }
 
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs
index 6f7ab3b3c9f..be3f961e10f 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-sse.rs
@@ -1,5 +1,6 @@
 // We're testing x86 target specific features
 //@only-target: x86_64 i686
+#![allow(unnecessary_transmutes)]
 
 #[cfg(target_arch = "x86")]
 use std::arch::x86::*;
diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs
index ee212af3626..d84f8e9fa1b 100644
--- a/src/tools/suggest-tests/src/main.rs
+++ b/src/tools/suggest-tests/src/main.rs
@@ -6,7 +6,6 @@ use suggest_tests::get_suggestions;
 fn main() -> ExitCode {
     let modified_files = get_git_modified_files(
         &GitConfig {
-            git_repository: &env("SUGGEST_TESTS_GIT_REPOSITORY"),
             nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"),
             git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"),
         },
diff --git a/src/tools/tidy/src/gcc_submodule.rs b/src/tools/tidy/src/gcc_submodule.rs
new file mode 100644
index 00000000000..952ebe9e0cf
--- /dev/null
+++ b/src/tools/tidy/src/gcc_submodule.rs
@@ -0,0 +1,47 @@
+//! Tidy check to ensure that the commit SHA of the `src/gcc` submodule is the same as the
+//! required GCC version of the GCC codegen backend.
+
+use std::path::Path;
+use std::process::Command;
+
+pub fn check(root_path: &Path, compiler_path: &Path, bad: &mut bool) {
+    let cg_gcc_version_path = compiler_path.join("rustc_codegen_gcc/libgccjit.version");
+    let cg_gcc_version = std::fs::read_to_string(&cg_gcc_version_path)
+        .expect(&format!("Cannot read GCC version from {}", cg_gcc_version_path.display()))
+        .trim()
+        .to_string();
+
+    let git_output = Command::new("git")
+        .current_dir(root_path)
+        .arg("submodule")
+        .arg("status")
+        // --cached asks for the version that is actually committed in the repository, not the one
+        // that is currently checked out.
+        .arg("--cached")
+        .arg("src/gcc")
+        .output()
+        .expect("Cannot determine git SHA of the src/gcc checkout");
+
+    // This can return e.g.
+    // -e607be166673a8de9fc07f6f02c60426e556c5f2 src/gcc
+    //  e607be166673a8de9fc07f6f02c60426e556c5f2 src/gcc (master-e607be166673a8de9fc07f6f02c60426e556c5f2.e607be)
+    // +e607be166673a8de9fc07f6f02c60426e556c5f2 src/gcc (master-e607be166673a8de9fc07f6f02c60426e556c5f2.e607be)
+    let git_output = String::from_utf8_lossy(&git_output.stdout)
+        .trim()
+        .split_whitespace()
+        .next()
+        .unwrap_or_default()
+        .to_string();
+
+    // The SHA can start with + if the submodule is modified or - if it is not checked out.
+    let gcc_submodule_sha = git_output.trim_start_matches(&['+', '-']);
+    if gcc_submodule_sha != cg_gcc_version {
+        *bad = true;
+        eprintln!(
+            r#"Commit SHA of the src/gcc submodule (`{gcc_submodule_sha}`) does not match the required GCC version of the GCC codegen backend (`{cg_gcc_version}`).
+Make sure to set the src/gcc submodule to commit {cg_gcc_version}.
+The GCC codegen backend commit is configured at {}."#,
+            cg_gcc_version_path.display(),
+        );
+    }
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 66856f5247b..ca45f8bb84b 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -75,6 +75,7 @@ pub mod features;
 pub mod fluent_alphabetical;
 pub mod fluent_period;
 mod fluent_used;
+pub mod gcc_submodule;
 pub(crate) mod iter_header;
 pub mod known_bug;
 pub mod mir_opt_tests;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 4078d462f55..48122129b01 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -116,6 +116,7 @@ fn main() {
         check!(fluent_alphabetical, &compiler_path, bless);
         check!(fluent_period, &compiler_path);
         check!(target_policy, &root_path);
+        check!(gcc_submodule, &root_path, &compiler_path);
 
         // Checks that only make sense for the std libs.
         check!(pal, &library_path);
diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml
index f8ae91f9e6f..642d48b9952 100644
--- a/src/tools/wasm-component-ld/Cargo.toml
+++ b/src/tools/wasm-component-ld/Cargo.toml
@@ -10,4 +10,4 @@ name = "wasm-component-ld"
 path = "src/main.rs"
 
 [dependencies]
-wasm-component-ld = "0.5.12"
+wasm-component-ld = "0.5.13"