about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2024-08-03 05:11:07 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2024-08-03 05:11:07 +0000
commit62e2800ee477919dd72e0a25239fed35671dcf7e (patch)
tree164330542b8a706f8fc8d3d05703eb2fd67a97d3 /src/tools
parent6aab319def5d2861a2ba87c002d453d4ae8df38e (diff)
parent9d0eaa2ad78ca2995d4f2c4edb61f762ba79846b (diff)
downloadrust-62e2800ee477919dd72e0a25239fed35671dcf7e.tar.gz
rust-62e2800ee477919dd72e0a25239fed35671dcf7e.zip
Merge from rustc
Diffstat (limited to 'src/tools')
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_wraps.stderr8
-rw-r--r--src/tools/compiletest/src/command-list.rs2
-rw-r--r--src/tools/compiletest/src/header.rs13
-rw-r--r--src/tools/compiletest/src/runtest.rs92
-rw-r--r--src/tools/compiletest/src/runtest/coverage.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.rs10
-rw-r--r--src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.stderr15
-rw-r--r--src/tools/opt-dist/Cargo.toml2
-rw-r--r--src/tools/run-make-support/src/external_deps/c_build.rs24
-rw-r--r--src/tools/run-make-support/src/external_deps/clang.rs5
-rw-r--r--src/tools/run-make-support/src/external_deps/llvm.rs42
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs59
-rw-r--r--src/tools/run-make-support/src/lib.rs6
-rw-r--r--src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs9
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs9
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt8
19 files changed, 214 insertions, 100 deletions
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 257b72b8adfb1f2aa9916cefca67285c2166627
+Subproject fa646583675d7c140482bd906145c71b7fb4fc2
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index e4e7f7d06e7..080efe983c2 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -145,7 +145,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
                 (
                     "this function's return value is unnecessary".to_string(),
                     "remove the return type...".to_string(),
-                    snippet(cx, fn_decl.output.span(), "..").to_string(),
+                    // FIXME: we should instead get the span including the `->` and suggest an
+                    // empty string for this case.
+                    "()".to_string(),
                     "...and then remove returned values",
                 )
             } else {
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
index 15708090361..37ee9195fce 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
@@ -63,7 +63,7 @@ LL |     let _val = None::<()>.expect("this always happens");
 help: remove the `None` and `expect()`
    |
 LL |     let _val = panic!("this always happens");
-   |                ~~~~~~~                     ~
+   |                ~~~~~~~
 
 error: used `unwrap_or_default()` on `None` value
   --> tests/ui/unnecessary_literal_unwrap.rs:22:24
@@ -134,7 +134,7 @@ LL |     None::<()>.expect("this always happens");
 help: remove the `None` and `expect()`
    |
 LL |     panic!("this always happens");
-   |     ~~~~~~~                     ~
+   |     ~~~~~~~
 
 error: used `unwrap_or_default()` on `None` value
   --> tests/ui/unnecessary_literal_unwrap.rs:30:5
diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
index a55a23d449f..59986d895b3 100644
--- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
@@ -118,8 +118,8 @@ LL | | }
    |
 help: remove the return type...
    |
-LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> {
-   |                                      ~~~~~~~~~~
+LL | fn issue_6640_1(a: bool, b: bool) -> () {
+   |                                      ~~
 help: ...and then remove returned values
    |
 LL ~         return ;
@@ -145,8 +145,8 @@ LL | | }
    |
 help: remove the return type...
    |
-LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> {
-   |                                      ~~~~~~~~~~~~~~~
+LL | fn issue_6640_2(a: bool, b: bool) -> () {
+   |                                      ~~
 help: ...and then remove returned values
    |
 LL ~         return ;
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs
index 288f90ea123..0706f3bee05 100644
--- a/src/tools/compiletest/src/command-list.rs
+++ b/src/tools/compiletest/src/command-list.rs
@@ -18,6 +18,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "check-test-line-numbers-match",
     "compare-output-lines-by-subset",
     "compile-flags",
+    "doc-flags",
     "dont-check-compiler-stderr",
     "dont-check-compiler-stdout",
     "dont-check-failure-status",
@@ -226,6 +227,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "should-ice",
     "stderr-per-bitwidth",
     "test-mir-pass",
+    "unique-doc-out-dir",
     "unset-exec-env",
     "unset-rustc-env",
     // Used by the tidy check `unknown_revision`.
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index cde3e3295c6..1fc24301c85 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -95,6 +95,8 @@ pub struct TestProps {
     pub compile_flags: Vec<String>,
     // Extra flags to pass when the compiled code is run (such as --bench)
     pub run_flags: Vec<String>,
+    /// Extra flags to pass to rustdoc but not the compiler.
+    pub doc_flags: Vec<String>,
     // If present, the name of a file that this test should match when
     // pretty-printed
     pub pp_exact: Option<PathBuf>,
@@ -122,6 +124,9 @@ pub struct TestProps {
     pub unset_exec_env: Vec<String>,
     // Build documentation for all specified aux-builds as well
     pub build_aux_docs: bool,
+    /// Build the documentation for each crate in a unique output directory.
+    /// Uses <root output directory>/docs/<test name>/doc
+    pub unique_doc_out_dir: bool,
     // Flag to force a crate to be built with the host architecture
     pub force_host: bool,
     // Check stdout for error-pattern output as well as stderr
@@ -220,8 +225,10 @@ mod directives {
     pub const REGEX_ERROR_PATTERN: &'static str = "regex-error-pattern";
     pub const COMPILE_FLAGS: &'static str = "compile-flags";
     pub const RUN_FLAGS: &'static str = "run-flags";
+    pub const DOC_FLAGS: &'static str = "doc-flags";
     pub const SHOULD_ICE: &'static str = "should-ice";
     pub const BUILD_AUX_DOCS: &'static str = "build-aux-docs";
+    pub const UNIQUE_DOC_OUT_DIR: &'static str = "unique-doc-out-dir";
     pub const FORCE_HOST: &'static str = "force-host";
     pub const CHECK_STDOUT: &'static str = "check-stdout";
     pub const CHECK_RUN_RESULTS: &'static str = "check-run-results";
@@ -267,6 +274,7 @@ impl TestProps {
             regex_error_patterns: vec![],
             compile_flags: vec![],
             run_flags: vec![],
+            doc_flags: vec![],
             pp_exact: None,
             aux_builds: vec![],
             aux_bins: vec![],
@@ -281,6 +289,7 @@ impl TestProps {
             exec_env: vec![],
             unset_exec_env: vec![],
             build_aux_docs: false,
+            unique_doc_out_dir: false,
             force_host: false,
             check_stdout: false,
             check_run_results: false,
@@ -378,6 +387,8 @@ impl TestProps {
                         |r| r,
                     );
 
+                    config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r);
+
                     fn split_flags(flags: &str) -> Vec<String> {
                         // Individual flags can be single-quoted to preserve spaces; see
                         // <https://github.com/rust-lang/rust/pull/115948/commits/957c5db6>.
@@ -415,6 +426,8 @@ impl TestProps {
 
                     config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
                     config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs);
+                    config.set_name_directive(ln, UNIQUE_DOC_OUT_DIR, &mut self.unique_doc_out_dir);
+
                     config.set_name_directive(ln, FORCE_HOST, &mut self.force_host);
                     config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout);
                     config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results);
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 1f15605d8be..b1b6d6fc8eb 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1,5 +1,6 @@
 // ignore-tidy-filelength
 
+use std::borrow::Cow;
 use std::collections::{HashMap, HashSet};
 use std::ffi::{OsStr, OsString};
 use std::fs::{self, create_dir_all, File, OpenOptions};
@@ -723,7 +724,7 @@ impl<'test> TestCx<'test> {
         self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
         rustc.args(&self.props.compile_flags);
 
-        self.compose_and_run_compiler(rustc, Some(src))
+        self.compose_and_run_compiler(rustc, Some(src), self.testpaths)
     }
 
     fn run_debuginfo_test(&self) {
@@ -1579,13 +1580,15 @@ impl<'test> TestCx<'test> {
             passes,
         );
 
-        self.compose_and_run_compiler(rustc, None)
+        self.compose_and_run_compiler(rustc, None, self.testpaths)
     }
 
-    fn document(&self, out_dir: &Path) -> ProcRes {
+    /// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run.
+    /// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths.
+    fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
         if self.props.build_aux_docs {
             for rel_ab in &self.props.aux_builds {
-                let aux_testpaths = self.compute_aux_test_paths(&self.testpaths, rel_ab);
+                let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab);
                 let aux_props =
                     self.props.from_aux_file(&aux_testpaths.file, self.revision, self.config);
                 let aux_cx = TestCx {
@@ -1596,7 +1599,9 @@ impl<'test> TestCx<'test> {
                 };
                 // Create the directory for the stdout/stderr files.
                 create_dir_all(aux_cx.output_base_dir()).unwrap();
-                let auxres = aux_cx.document(out_dir);
+                // use root_testpaths here, because aux-builds should have the
+                // same --out-dir and auxiliary directory.
+                let auxres = aux_cx.document(&root_out_dir, root_testpaths);
                 if !auxres.status.success() {
                     return auxres;
                 }
@@ -1606,21 +1611,40 @@ impl<'test> TestCx<'test> {
         let aux_dir = self.aux_output_dir_name();
 
         let rustdoc_path = self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed");
-        let mut rustdoc = Command::new(rustdoc_path);
 
+        // actual --out-dir given to the auxiliary or test, as opposed to the root out dir for the entire
+        // test
+        let out_dir: Cow<'_, Path> = if self.props.unique_doc_out_dir {
+            let file_name = self.testpaths.file.file_stem().expect("file name should not be empty");
+            let out_dir = PathBuf::from_iter([
+                root_out_dir,
+                Path::new("docs"),
+                Path::new(file_name),
+                Path::new("doc"),
+            ]);
+            create_dir_all(&out_dir).unwrap();
+            Cow::Owned(out_dir)
+        } else {
+            Cow::Borrowed(root_out_dir)
+        };
+
+        let mut rustdoc = Command::new(rustdoc_path);
+        let current_dir = output_base_dir(self.config, root_testpaths, self.safe_revision());
+        rustdoc.current_dir(current_dir);
         rustdoc
             .arg("-L")
             .arg(self.config.run_lib_path.to_str().unwrap())
             .arg("-L")
             .arg(aux_dir)
             .arg("-o")
-            .arg(out_dir)
+            .arg(out_dir.as_ref())
             .arg("--deny")
             .arg("warnings")
             .arg(&self.testpaths.file)
             .arg("-A")
             .arg("internal_features")
-            .args(&self.props.compile_flags);
+            .args(&self.props.compile_flags)
+            .args(&self.props.doc_flags);
 
         if self.config.mode == RustdocJson {
             rustdoc.arg("--output-format").arg("json").arg("-Zunstable-options");
@@ -1630,7 +1654,7 @@ impl<'test> TestCx<'test> {
             rustdoc.arg(format!("-Clinker={}", linker));
         }
 
-        self.compose_and_run_compiler(rustdoc, None)
+        self.compose_and_run_compiler(rustdoc, None, root_testpaths)
     }
 
     fn exec_compiled_test(&self) -> ProcRes {
@@ -1828,9 +1852,16 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes {
+    /// `root_testpaths` refers to the path of the original test.
+    /// the auxiliary and the test with an aux-build have the same `root_testpaths`.
+    fn compose_and_run_compiler(
+        &self,
+        mut rustc: Command,
+        input: Option<String>,
+        root_testpaths: &TestPaths,
+    ) -> ProcRes {
         let aux_dir = self.aux_output_dir();
-        self.build_all_auxiliary(&self.testpaths, &aux_dir, &mut rustc);
+        self.build_all_auxiliary(root_testpaths, &aux_dir, &mut rustc);
 
         rustc.envs(self.props.rustc_env.clone());
         self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove);
@@ -2545,7 +2576,7 @@ impl<'test> TestCx<'test> {
             Vec::new(),
         );
 
-        let proc_res = self.compose_and_run_compiler(rustc, None);
+        let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
         let output_path = self.get_filecheck_file("ll");
         (proc_res, output_path)
     }
@@ -2581,7 +2612,7 @@ impl<'test> TestCx<'test> {
             Vec::new(),
         );
 
-        let proc_res = self.compose_and_run_compiler(rustc, None);
+        let proc_res = self.compose_and_run_compiler(rustc, None, self.testpaths);
         let output_path = self.get_filecheck_file("s");
         (proc_res, output_path)
     }
@@ -2664,7 +2695,7 @@ impl<'test> TestCx<'test> {
         let out_dir = self.output_base_dir();
         remove_and_create_dir_all(&out_dir);
 
-        let proc_res = self.document(&out_dir);
+        let proc_res = self.document(&out_dir, &self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc failed!", &proc_res);
         }
@@ -2723,7 +2754,7 @@ impl<'test> TestCx<'test> {
         let aux_dir = new_rustdoc.aux_output_dir();
         new_rustdoc.build_all_auxiliary(&new_rustdoc.testpaths, &aux_dir, &mut rustc);
 
-        let proc_res = new_rustdoc.document(&compare_dir);
+        let proc_res = new_rustdoc.document(&compare_dir, &new_rustdoc.testpaths);
         if !proc_res.status.success() {
             eprintln!("failed to run nightly rustdoc");
             return;
@@ -2847,7 +2878,7 @@ impl<'test> TestCx<'test> {
         let out_dir = self.output_base_dir();
         remove_and_create_dir_all(&out_dir);
 
-        let proc_res = self.document(&out_dir);
+        let proc_res = self.document(&out_dir, &self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc failed!", &proc_res);
         }
@@ -2923,31 +2954,24 @@ impl<'test> TestCx<'test> {
     fn check_rustdoc_test_option(&self, res: ProcRes) {
         let mut other_files = Vec::new();
         let mut files: HashMap<String, Vec<usize>> = HashMap::new();
-        let cwd = env::current_dir().unwrap();
-        files.insert(
-            self.testpaths
-                .file
-                .strip_prefix(&cwd)
-                .unwrap_or(&self.testpaths.file)
-                .to_str()
-                .unwrap()
-                .replace('\\', "/"),
-            self.get_lines(&self.testpaths.file, Some(&mut other_files)),
-        );
+        let normalized = fs::canonicalize(&self.testpaths.file).expect("failed to canonicalize");
+        let normalized = normalized.to_str().unwrap().replace('\\', "/");
+        files.insert(normalized, self.get_lines(&self.testpaths.file, Some(&mut other_files)));
         for other_file in other_files {
             let mut path = self.testpaths.file.clone();
             path.set_file_name(&format!("{}.rs", other_file));
-            files.insert(
-                path.strip_prefix(&cwd).unwrap_or(&path).to_str().unwrap().replace('\\', "/"),
-                self.get_lines(&path, None),
-            );
+            let path = fs::canonicalize(path).expect("failed to canonicalize");
+            let normalized = path.to_str().unwrap().replace('\\', "/");
+            files.insert(normalized, self.get_lines(&path, None));
         }
 
         let mut tested = 0;
         for _ in res.stdout.split('\n').filter(|s| s.starts_with("test ")).inspect(|s| {
             if let Some((left, right)) = s.split_once(" - ") {
                 let path = left.rsplit("test ").next().unwrap();
-                if let Some(ref mut v) = files.get_mut(&path.replace('\\', "/")) {
+                let path = fs::canonicalize(&path).expect("failed to canonicalize");
+                let path = path.to_str().unwrap().replace('\\', "/");
+                if let Some(ref mut v) = files.get_mut(&path) {
                     tested += 1;
                     let mut iter = right.split("(line ");
                     iter.next();
@@ -3779,7 +3803,7 @@ impl<'test> TestCx<'test> {
         if let Some(nodejs) = &self.config.nodejs {
             let out_dir = self.output_base_dir();
 
-            self.document(&out_dir);
+            self.document(&out_dir, &self.testpaths);
 
             let root = self.config.find_rust_src_root().unwrap();
             let file_stem =
@@ -4095,7 +4119,7 @@ impl<'test> TestCx<'test> {
                 rustc.arg(crate_name);
             }
 
-            let res = self.compose_and_run_compiler(rustc, None);
+            let res = self.compose_and_run_compiler(rustc, None, self.testpaths);
             if !res.status.success() {
                 self.fatal_proc_rec("failed to compile fixed code", &res);
             }
diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs
index 6ee147da5a9..05191a15980 100644
--- a/src/tools/compiletest/src/runtest/coverage.rs
+++ b/src/tools/compiletest/src/runtest/coverage.rs
@@ -191,7 +191,7 @@ impl<'test> TestCx<'test> {
 
         rustdoc_cmd.arg(&self.testpaths.file);
 
-        let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None);
+        let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None, self.testpaths);
         if !proc_res.status.success() {
             self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
         }
diff --git a/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.rs b/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.rs
deleted file mode 100644
index c14f86147db..00000000000
--- a/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(intrinsics)]
-
-extern "rust-intrinsic" {
-    fn raw_eq<T>(a: &T, b: &T) -> bool;
-}
-
-fn main() {
-    let x = &0;
-    unsafe { raw_eq(&x, &x) }; //~ERROR: `raw_eq` on bytes with provenance
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.stderr
deleted file mode 100644
index 83f81fa726e..00000000000
--- a/src/tools/miri/tests/fail/intrinsics/raw_eq_on_ptr.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: `raw_eq` on bytes with provenance
-  --> $DIR/raw_eq_on_ptr.rs:LL:CC
-   |
-LL |     unsafe { raw_eq(&x, &x) };
-   |              ^^^^^^^^^^^^^^ `raw_eq` on bytes with provenance
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index 88e8640d56a..d34f8ad0520 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -10,7 +10,7 @@ log = "0.4"
 anyhow = { version = "1", features = ["backtrace"] }
 humantime = "2"
 humansize = "2"
-sysinfo = { version = "0.30", default-features = false }
+sysinfo = { version = "0.31.2", default-features = false, features = ["disk"] }
 fs_extra = "1"
 camino = "1"
 tar = "0.4"
diff --git a/src/tools/run-make-support/src/external_deps/c_build.rs b/src/tools/run-make-support/src/external_deps/c_build.rs
index 86c9c081831..15e02d04393 100644
--- a/src/tools/run-make-support/src/external_deps/c_build.rs
+++ b/src/tools/run-make-support/src/external_deps/c_build.rs
@@ -2,7 +2,7 @@ use std::path::PathBuf;
 
 use super::cygpath::get_windows_path;
 use crate::artifact_names::{dynamic_lib_name, static_lib_name};
-use crate::external_deps::cc::cc;
+use crate::external_deps::cc::{cc, cxx};
 use crate::external_deps::llvm::llvm_ar;
 use crate::path_helpers::path;
 use crate::targets::{is_darwin, is_msvc, is_windows};
@@ -10,6 +10,7 @@ use crate::targets::{is_darwin, is_msvc, is_windows};
 // FIXME(Oneirical): These native build functions should take a Path-based generic.
 
 /// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
+/// Built from a C file.
 #[track_caller]
 pub fn build_native_static_lib(lib_name: &str) -> PathBuf {
     let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
@@ -58,3 +59,24 @@ pub fn build_native_dynamic_lib(lib_name: &str) -> PathBuf {
     }
     path(lib_path)
 }
+
+/// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
+/// Built from a C++ file.
+#[track_caller]
+pub fn build_native_static_lib_cxx(lib_name: &str) -> PathBuf {
+    let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
+    let src = format!("{lib_name}.cpp");
+    let lib_path = static_lib_name(lib_name);
+    if is_msvc() {
+        cxx().arg("-EHs").arg("-c").out_exe(&obj_file).input(src).run();
+    } else {
+        cxx().arg("-c").out_exe(&obj_file).input(src).run();
+    };
+    let obj_file = if is_msvc() {
+        PathBuf::from(format!("{lib_name}.obj"))
+    } else {
+        PathBuf::from(format!("{lib_name}.o"))
+    };
+    llvm_ar().obj_to_ar().output_input(&lib_path, &obj_file).run();
+    path(lib_path)
+}
diff --git a/src/tools/run-make-support/src/external_deps/clang.rs b/src/tools/run-make-support/src/external_deps/clang.rs
index 2b0712541cd..2d110c6825e 100644
--- a/src/tools/run-make-support/src/external_deps/clang.rs
+++ b/src/tools/run-make-support/src/external_deps/clang.rs
@@ -1,7 +1,7 @@
 use std::path::Path;
 
 use crate::command::Command;
-use crate::{bin_name, env_var};
+use crate::{bin_name, cwd, env_var};
 
 /// Construct a new `clang` invocation. `clang` is not always available for all targets.
 #[track_caller]
@@ -23,7 +23,8 @@ impl Clang {
     #[track_caller]
     pub fn new() -> Self {
         let clang = env_var("CLANG");
-        let cmd = Command::new(clang);
+        let mut cmd = Command::new(clang);
+        cmd.arg("-L").arg(cwd());
         Self { cmd }
     }
 
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index 259bb615946..56021cec269 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -42,6 +42,12 @@ pub fn llvm_nm() -> LlvmNm {
     LlvmNm::new()
 }
 
+/// Construct a new `llvm-bcanalyzer` invocation. This assumes that `llvm-bcanalyzer` is available
+/// at `$LLVM_BIN_DIR/llvm-bcanalyzer`.
+pub fn llvm_bcanalyzer() -> LlvmBcanalyzer {
+    LlvmBcanalyzer::new()
+}
+
 /// A `llvm-readobj` invocation builder.
 #[derive(Debug)]
 #[must_use]
@@ -84,12 +90,20 @@ pub struct LlvmNm {
     cmd: Command,
 }
 
+/// A `llvm-bcanalyzer` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmBcanalyzer {
+    cmd: Command,
+}
+
 crate::macros::impl_common_helpers!(LlvmReadobj);
 crate::macros::impl_common_helpers!(LlvmProfdata);
 crate::macros::impl_common_helpers!(LlvmFilecheck);
 crate::macros::impl_common_helpers!(LlvmObjdump);
 crate::macros::impl_common_helpers!(LlvmAr);
 crate::macros::impl_common_helpers!(LlvmNm);
+crate::macros::impl_common_helpers!(LlvmBcanalyzer);
 
 /// Generate the path to the bin directory of LLVM.
 #[must_use]
@@ -232,6 +246,12 @@ impl LlvmObjdump {
         self.cmd.arg(path.as_ref());
         self
     }
+
+    /// Disassemble all executable sections found in the input files.
+    pub fn disassemble(&mut self) -> &mut Self {
+        self.cmd.arg("-d");
+        self
+    }
 }
 
 impl LlvmAr {
@@ -250,6 +270,12 @@ impl LlvmAr {
         self
     }
 
+    /// Extract archive members back to files.
+    pub fn extract(&mut self) -> &mut Self {
+        self.cmd.arg("x");
+        self
+    }
+
     /// Provide an output, then an input file. Bundled in one function, as llvm-ar has
     /// no "--output"-style flag.
     pub fn output_input(&mut self, out: impl AsRef<Path>, input: impl AsRef<Path>) -> &mut Self {
@@ -274,3 +300,19 @@ impl LlvmNm {
         self
     }
 }
+
+impl LlvmBcanalyzer {
+    /// Construct a new `llvm-bcanalyzer` invocation. This assumes that `llvm-bcanalyzer` is available
+    /// at `$LLVM_BIN_DIR/llvm-bcanalyzer`.
+    pub fn new() -> Self {
+        let llvm_bcanalyzer = llvm_bin_dir().join("llvm-bcanalyzer");
+        let cmd = Command::new(llvm_bcanalyzer);
+        Self { cmd }
+    }
+
+    /// Provide an input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+}
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index 71d28dd9675..cece58d2956 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -5,6 +5,7 @@ use crate::command::Command;
 use crate::env::env_var;
 use crate::path_helpers::cwd;
 use crate::util::set_host_rpath;
+use crate::{is_darwin, is_msvc, is_windows, uname};
 
 /// Construct a new `rustc` invocation. This will automatically set the library
 /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this.
@@ -314,4 +315,62 @@ impl Rustc {
         self.cmd.arg(format!("-Clinker-flavor={linker_flavor}"));
         self
     }
+
+    /// `EXTRARSCXXFLAGS`
+    pub fn extra_rs_cxx_flags(&mut self) -> &mut Self {
+        // Adapted from tools.mk (trimmed):
+        //
+        // ```makefile
+        // ifdef IS_WINDOWS
+        //     ifdef IS_MSVC
+        //     else
+        //         EXTRARSCXXFLAGS := -lstatic:-bundle=stdc++
+        //     endif
+        // else
+        //     ifeq ($(UNAME),Darwin)
+        //         EXTRARSCXXFLAGS := -lc++
+        //     else
+        //         ifeq ($(UNAME),FreeBSD)
+        //         else
+        //             ifeq ($(UNAME),SunOS)
+        //             else
+        //                 ifeq ($(UNAME),OpenBSD)
+        //                 else
+        //                     EXTRARSCXXFLAGS := -lstdc++
+        //                 endif
+        //             endif
+        //         endif
+        //     endif
+        // endif
+        // ```
+        let flag = if is_windows() {
+            // So this is a bit hacky: we can't use the DLL version of libstdc++ because
+            // it pulls in the DLL version of libgcc, which means that we end up with 2
+            // instances of the DW2 unwinding implementation. This is a problem on
+            // i686-pc-windows-gnu because each module (DLL/EXE) needs to register its
+            // unwind information with the unwinding implementation, and libstdc++'s
+            // __cxa_throw won't see the unwinding info we registered with our statically
+            // linked libgcc.
+            //
+            // Now, simply statically linking libstdc++ would fix this problem, except
+            // that it is compiled with the expectation that pthreads is dynamically
+            // linked as a DLL and will fail to link with a statically linked libpthread.
+            //
+            // So we end up with the following hack: we link use static:-bundle to only
+            // link the parts of libstdc++ that we actually use, which doesn't include
+            // the dependency on the pthreads DLL.
+            if is_msvc() { None } else { Some("-lstatic:-bundle=stdc++") }
+        } else if is_darwin() {
+            Some("-lc++")
+        } else {
+            match &uname()[..] {
+                "FreeBSD" | "SunOS" | "OpenBSD" => None,
+                _ => Some("-lstdc++"),
+            }
+        };
+        if let Some(flag) = flag {
+            self.cmd.arg(flag);
+        }
+        self
+    }
 }
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 9ccc37b25d7..63c4c4d8863 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -44,13 +44,13 @@ pub use wasmparser;
 pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc};
 
 // These rely on external dependencies.
-pub use c_build::{build_native_dynamic_lib, build_native_static_lib};
 pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
+pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx};
 pub use clang::{clang, Clang};
 pub use htmldocck::htmldocck;
 pub use llvm::{
-    llvm_ar, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr,
-    LlvmFilecheck, LlvmNm, LlvmObjdump, LlvmProfdata, LlvmReadobj,
+    llvm_ar, llvm_bcanalyzer, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata, llvm_readobj,
+    LlvmAr, LlvmBcanalyzer, LlvmFilecheck, LlvmNm, LlvmObjdump, LlvmProfdata, LlvmReadobj,
 };
 pub use python::python_command;
 pub use rustc::{aux_build, bare_rustc, rustc, Rustc};
diff --git a/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs b/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
index 9257b8a4be6..b9adc67221a 100644
--- a/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
+++ b/src/tools/rustfmt/tests/source/cfg_if/detect/os/x86.rs
@@ -34,15 +34,6 @@ pub fn check_for(x: Feature) -> bool {
 fn detect_features() -> cache::Initializer {
     let mut value = cache::Initializer::default();
 
-    // If the x86 CPU does not support the CPUID instruction then it is too
-    // old to support any of the currently-detectable features.
-    if !has_cpuid() {
-        return value;
-    }
-
-    // Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU
-    // has `cpuid` support.
-
     // 0. EAX = 0: Basic Information:
     // - EAX returns the "Highest Function Parameter", that is, the maximum
     // leaf value for subsequent calls of `cpuinfo` in range [0,
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
index 2e228aa3745..944b51615f8 100644
--- a/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/x86.rs
@@ -34,15 +34,6 @@ pub fn check_for(x: Feature) -> bool {
 fn detect_features() -> cache::Initializer {
     let mut value = cache::Initializer::default();
 
-    // If the x86 CPU does not support the CPUID instruction then it is too
-    // old to support any of the currently-detectable features.
-    if !has_cpuid() {
-        return value;
-    }
-
-    // Calling `__cpuid`/`__cpuid_count` from here on is safe because the CPU
-    // has `cpuid` support.
-
     // 0. EAX = 0: Basic Information:
     // - EAX returns the "Highest Function Parameter", that is, the maximum
     // leaf value for subsequent calls of `cpuinfo` in range [0,
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index d52ffe6e9f5..a04e239abb0 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,27 +1,19 @@
 run-make/branch-protection-check-IBT/Makefile
 run-make/cat-and-grep-sanity-check/Makefile
 run-make/cdylib-dylib-linkage/Makefile
-run-make/cross-lang-lto-clang/Makefile
-run-make/cross-lang-lto-pgo-smoketest/Makefile
 run-make/cross-lang-lto-upstream-rlibs/Makefile
-run-make/cross-lang-lto/Makefile
 run-make/dep-info-doesnt-run-much/Makefile
 run-make/dep-info-spaces/Makefile
 run-make/dep-info/Makefile
 run-make/emit-to-stdout/Makefile
 run-make/extern-fn-reachable/Makefile
-run-make/foreign-double-unwind/Makefile
-run-make/foreign-exceptions/Makefile
 run-make/incr-add-rust-src-component/Makefile
-run-make/issue-36710/Makefile
 run-make/issue-84395-lto-embed-bitcode/Makefile
-run-make/issue-88756-default-output/Makefile
 run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/libtest-json/Makefile
 run-make/libtest-junit/Makefile
 run-make/libtest-thread-limit/Makefile
-run-make/link-cfg/Makefile
 run-make/long-linker-command-lines-cmd-exe/Makefile
 run-make/long-linker-command-lines/Makefile
 run-make/macos-deployment-target/Makefile