about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2025-07-15 05:07:09 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2025-07-15 05:07:09 +0000
commitf7da0212af0b00b77b43e2e8c62607df43946dcf (patch)
treedc3ad3a58d9b6d278b9270804c50f9da6c11acff /src
parenta9a5b33c2d7d5d1ada0efd23f97cc1f3b774dbda (diff)
parent7f2065a4bae1faed5bab928c670964eafbf43b55 (diff)
downloadrust-f7da0212af0b00b77b43e2e8c62607df43946dcf.tar.gz
rust-f7da0212af0b00b77b43e2e8c62607df43946dcf.zip
Merge from rustc
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs41
-rw-r--r--src/bootstrap/src/core/builder/mod.rs3
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md3
-rwxr-xr-xsrc/etc/htmldocck.py55
-rw-r--r--src/librustdoc/clean/types.rs3
-rw-r--r--src/librustdoc/html/render/mod.rs4
m---------src/llvm-project0
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs2
-rw-r--r--src/tools/clippy/clippy_test_deps/Cargo.lock505
-rw-r--r--src/tools/clippy/clippy_test_deps/Cargo.toml3
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
-rw-r--r--src/tools/compiletest/src/common.rs41
-rw-r--r--src/tools/compiletest/src/directive-list.rs260
-rw-r--r--src/tools/compiletest/src/directives.rs304
-rw-r--r--src/tools/compiletest/src/directives/tests.rs2
-rw-r--r--src/tools/compiletest/src/lib.rs2
-rw-r--r--src/tools/compiletest/src/runtest.rs11
-rw-r--r--src/tools/compiletest/src/runtest/coverage.rs4
-rw-r--r--src/tools/compiletest/src/runtest/rustdoc.rs2
-rw-r--r--src/tools/compiletest/src/runtest/rustdoc_json.rs2
-rw-r--r--src/tools/jsondocck/src/directive.rs15
-rw-r--r--src/tools/jsondocck/src/main.rs16
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml1
-rw-r--r--src/tools/miri/tests/pass/shims/random.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs4
-rw-r--r--src/tools/tidy/Cargo.toml2
-rw-r--r--src/tools/tidy/src/alphabetical.rs2
-rw-r--r--src/tools/tidy/src/bins.rs11
-rw-r--r--src/tools/tidy/src/deps.rs2
-rw-r--r--src/tools/tidy/src/error_codes.rs20
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs16
-rw-r--r--src/tools/tidy/src/extdeps.rs2
-rw-r--r--src/tools/tidy/src/features.rs21
-rw-r--r--src/tools/tidy/src/features/version.rs2
-rw-r--r--src/tools/tidy/src/features/version/tests.rs4
-rw-r--r--src/tools/tidy/src/fluent_alphabetical.rs8
-rw-r--r--src/tools/tidy/src/fluent_period.rs4
-rw-r--r--src/tools/tidy/src/fluent_used.rs4
-rw-r--r--src/tools/tidy/src/gcc_submodule.rs7
-rw-r--r--src/tools/tidy/src/main.rs9
-rw-r--r--src/tools/tidy/src/mir_opt_tests.rs2
-rw-r--r--src/tools/tidy/src/pal.rs2
-rw-r--r--src/tools/tidy/src/rustdoc_gui_tests.rs2
-rw-r--r--src/tools/tidy/src/rustdoc_js.rs2
-rw-r--r--src/tools/tidy/src/rustdoc_json.rs2
-rw-r--r--src/tools/tidy/src/rustdoc_templates.rs4
-rw-r--r--src/tools/tidy/src/style.rs15
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs11
-rw-r--r--src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs12
-rw-r--r--src/tools/tidy/src/ui_tests.rs15
-rw-r--r--src/tools/tidy/src/unstable_book.rs4
-rw-r--r--src/tools/tidy/src/walk.rs4
-rw-r--r--src/tools/tidy/src/x_version.rs10
-rw-r--r--src/tools/tier-check/Cargo.toml2
-rw-r--r--src/tools/tier-check/src/main.rs14
58 files changed, 991 insertions, 527 deletions
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 1282a89a5e4..09bb2e35bda 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -2400,10 +2400,10 @@ pub fn run_cargo(
                 keep = true;
             } else if rlib_only_metadata {
                 if filename.contains("jemalloc_sys")
-                    || filename.contains("rustc_smir")
-                    || filename.contains("stable_mir")
+                    || filename.contains("rustc_public_bridge")
+                    || filename.contains("rustc_public")
                 {
-                    // jemalloc_sys and rustc_smir are not linked into librustc_driver.so,
+                    // jemalloc_sys and rustc_public_bridge are not linked into librustc_driver.so,
                     // so we need to distribute them as rlib to be able to use them.
                     keep |= filename.ends_with(".rlib");
                 } else {
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 5de1b472d79..814a44b9a13 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -9,6 +9,7 @@
 //! Each Rust tool **MUST** utilize `ToolBuild` inside their `Step` logic,
 //! return `ToolBuildResult` and should never prepare `cargo` invocations manually.
 
+use std::ffi::OsStr;
 use std::path::PathBuf;
 use std::{env, fs};
 
@@ -136,19 +137,6 @@ impl Step for ToolBuild {
             _ => panic!("unexpected Mode for tool build"),
         }
 
-        // build.tool.TOOL_NAME.features in bootstrap.toml allows specifying which features to
-        // enable for a specific tool. `extra_features` instead is not controlled by the toml and
-        // provides features that are always enabled for a specific tool (e.g. "in-rust-tree" for
-        // rust-analyzer). Finally, `prepare_tool_cargo` might add more features to adapt the build
-        // to the chosen flags (e.g. "all-static" for cargo if `cargo_native_static` is true).
-        let mut features = builder
-            .config
-            .tool
-            .get(self.tool)
-            .and_then(|tool| tool.features.clone())
-            .unwrap_or_default();
-        features.extend(self.extra_features.clone());
-
         let mut cargo = prepare_tool_cargo(
             builder,
             self.compiler,
@@ -157,7 +145,7 @@ impl Step for ToolBuild {
             Kind::Build,
             path,
             self.source_type,
-            &features,
+            &self.extra_features,
         );
 
         // The stage0 compiler changes infrequently and does not directly depend on code
@@ -244,7 +232,8 @@ pub fn prepare_tool_cargo(
 ) -> CargoCommand {
     let mut cargo = builder::Cargo::new(builder, compiler, mode, source_type, target, cmd_kind);
 
-    let dir = builder.src.join(path);
+    let path = PathBuf::from(path);
+    let dir = builder.src.join(&path);
     cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
 
     let mut features = extra_features.to_vec();
@@ -261,6 +250,18 @@ pub fn prepare_tool_cargo(
         }
     }
 
+    // build.tool.TOOL_NAME.features in bootstrap.toml allows specifying which features to enable
+    // for a specific tool. `extra_features` instead is not controlled by the toml and provides
+    // features that are always enabled for a specific tool (e.g. "in-rust-tree" for rust-analyzer).
+    // Finally, `prepare_tool_cargo` above here might add more features to adapt the build
+    // to the chosen flags (e.g. "all-static" for cargo if `cargo_native_static` is true).
+    builder
+        .config
+        .tool
+        .iter()
+        .filter(|(tool_name, _)| path.file_name().and_then(OsStr::to_str) == Some(tool_name))
+        .for_each(|(_, tool)| features.extend(tool.features.clone().unwrap_or_default()));
+
     // clippy tests need to know about the stage sysroot. Set them consistently while building to
     // avoid rebuilding when running tests.
     cargo.env("SYSROOT", builder.sysroot(compiler));
@@ -1140,6 +1141,7 @@ macro_rules! tool_extended {
             stable: $stable:expr
             $( , add_bins_to_sysroot: $add_bins_to_sysroot:expr )?
             $( , add_features: $add_features:expr )?
+            $( , cargo_args: $cargo_args:expr )?
             $( , )?
         }
     ) => {
@@ -1180,6 +1182,7 @@ macro_rules! tool_extended {
                     $path,
                     None $( .or(Some(&$add_bins_to_sysroot)) )?,
                     None $( .or(Some($add_features)) )?,
+                    None $( .or(Some($cargo_args)) )?,
                 )
             }
 
@@ -1219,6 +1222,7 @@ fn should_run_tool_build_step<'a>(
     )
 }
 
+#[expect(clippy::too_many_arguments)] // silence overeager clippy lint
 fn run_tool_build_step(
     builder: &Builder<'_>,
     compiler: Compiler,
@@ -1227,6 +1231,7 @@ fn run_tool_build_step(
     path: &'static str,
     add_bins_to_sysroot: Option<&[&str]>,
     add_features: Option<fn(&Builder<'_>, TargetSelection, &mut Vec<String>)>,
+    cargo_args: Option<&[&'static str]>,
 ) -> ToolBuildResult {
     let mut extra_features = Vec::new();
     if let Some(func) = add_features {
@@ -1243,7 +1248,7 @@ fn run_tool_build_step(
             extra_features,
             source_type: SourceType::InTree,
             allow_features: "",
-            cargo_args: vec![],
+            cargo_args: cargo_args.unwrap_or_default().iter().map(|s| String::from(*s)).collect(),
             artifact_kind: ToolArtifactKind::Binary,
         });
 
@@ -1294,7 +1299,9 @@ tool_extended!(Miri {
     path: "src/tools/miri",
     tool_name: "miri",
     stable: false,
-    add_bins_to_sysroot: ["miri"]
+    add_bins_to_sysroot: ["miri"],
+    // Always compile also tests when building miri. Otherwise feature unification can cause rebuilds between building and testing miri.
+    cargo_args: &["--all-targets"],
 });
 tool_extended!(CargoMiri {
     path: "src/tools/miri/cargo-miri",
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 4d606953d99..7115c5a1cbe 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -1044,6 +1044,7 @@ impl<'a> Builder<'a> {
             Kind::Test => describe!(
                 crate::core::build_steps::toolstate::ToolStateCheck,
                 test::Tidy,
+                test::Bootstrap,
                 test::Ui,
                 test::Crashes,
                 test::Coverage,
@@ -1098,8 +1099,6 @@ impl<'a> Builder<'a> {
                 test::RustInstaller,
                 test::TestFloatParse,
                 test::CollectLicenseMetadata,
-                // Run bootstrap close to the end as it's unlikely to fail
-                test::Bootstrap,
                 // Run run-make last, since these won't pass without make on Windows
                 test::RunMake,
             ),
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index c5d460ac55b..1f6ed8129da 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -471,4 +471,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "A --compile-time-deps flag has been added to reduce the time it takes rust-analyzer to start",
     },
+    ChangeInfo {
+        change_id: 143733,
+        severity: ChangeSeverity::Info,
+        summary: "Option `tool.TOOL_NAME.features` now works on any subcommand, not just `build`.",
+    },
 ];
diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md
index b05318ce9e6..4f44cf1701c 100644
--- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md
+++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-test-suite.md
@@ -55,6 +55,9 @@ Similar to shell commands,
 directives can extend across multiple lines if their last char is `\`.
 In this case, the start of the next line should be `//`, with no `@`.
 
+Similar to compiletest directives, besides a space you can also use a colon `:` to separate
+the directive name and the arguments, however a space is preferred for HtmlDocCk directives.
+
 Use the special string `{{channel}}` in XPaths, `PATTERN` arguments and [snapshot files](#snapshot)
 if you'd like to refer to the URL `https://doc.rust-lang.org/CHANNEL` where `CHANNEL` refers to the
 current release channel (e.g, `stable` or `nightly`).
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index ddbd256a0d8..72975cc6206 100755
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -147,48 +147,17 @@ def concat_multi_lines(f):
         print_err(lineno, line, "Trailing backslash at the end of the file")
 
 
-def get_known_directive_names():
-    def filter_line(line):
-        line = line.strip()
-        return line.startswith('"') and (line.endswith('",') or line.endswith('"'))
-
-    # Equivalent to `src/tools/compiletest/src/header.rs` constant of the same name.
-    with open(
-        os.path.join(
-            # We go back to `src`.
-            os.path.dirname(os.path.dirname(__file__)),
-            "tools/compiletest/src/directive-list.rs",
-        ),
-        "r",
-        encoding="utf8",
-    ) as fd:
-        content = fd.read()
-        return [
-            line.strip().replace('",', "").replace('"', "")
-            for line in content.split("\n")
-            if filter_line(line)
-        ]
-
-
-# To prevent duplicating the list of commmands between `compiletest` and `htmldocck`, we put
-# it into a common file which is included in rust code and parsed here.
-# FIXME: This setup is temporary until we figure out how to improve this situation.
-#        See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
-KNOWN_DIRECTIVE_NAMES = get_known_directive_names()
-
 LINE_PATTERN = re.compile(
     r"""
     //@\s+
-    (?P<negated>!?)(?P<cmd>[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)
-    (?P<args>.*)$
+    (?P<negated>!?)(?P<cmd>.+?)
+    (?:[\s:](?P<args>.*))?$
 """,
     re.X | re.UNICODE,
 )
 
 DEPRECATED_LINE_PATTERN = re.compile(
-    r"""
-    //\s+@
-""",
+    r"//\s+@",
     re.X | re.UNICODE,
 )
 
@@ -209,12 +178,7 @@ def get_commands(template):
 
             cmd = m.group("cmd")
             negated = m.group("negated") == "!"
-            if not negated and cmd in KNOWN_DIRECTIVE_NAMES:
-                continue
-            args = m.group("args")
-            if args and not args[:1].isspace():
-                print_err(lineno, line, "Invalid template syntax")
-                continue
+            args = m.group("args") or ""
             try:
                 args = shlex.split(args)
             except UnicodeEncodeError:
@@ -636,14 +600,11 @@ def check_command(c, cache):
             else:
                 raise InvalidCheck("Invalid number of {} arguments".format(c.cmd))
 
-        elif c.cmd == "valid-html":
-            raise InvalidCheck("Unimplemented valid-html")
-
-        elif c.cmd == "valid-links":
-            raise InvalidCheck("Unimplemented valid-links")
-
         else:
-            raise InvalidCheck("Unrecognized {}".format(c.cmd))
+            # Ignore unknown directives as they might be compiletest directives
+            # since they share the same `//@` prefix by convention. In any case,
+            # compiletest rejects unknown directives for us.
+            return
 
         if ret == c.negated:
             raise FailedCheck(cerr)
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index a05aab22f1e..3ecd41db2dd 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -796,6 +796,9 @@ impl Item {
                             }
                             Some(format!("#[target_feature({output})]"))
                         }
+                        hir::Attribute::Parsed(AttributeKind::AutomaticallyDerived(..)) => {
+                            Some("#[automatically_derived]".to_string())
+                        }
                         _ => Some({
                             let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
                             assert_eq!(s.pop(), Some('\n'));
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 6a1fad06ae3..70f3f54e4c0 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -980,7 +980,7 @@ fn assoc_method(
     let name = meth.name.as_ref().unwrap();
     let vis = visibility_print_with_space(meth, cx).to_string();
     let defaultness = print_default_space(meth.is_default());
-    // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
+    // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
     // this condition.
     let constness = match render_mode {
         RenderMode::Normal => print_constness_with_space(
@@ -2152,7 +2152,7 @@ fn render_rightside(
     let tcx = cx.tcx();
 
     fmt::from_fn(move |w| {
-        // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
+        // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
         // this condition.
         let const_stability = match render_mode {
             RenderMode::Normal => item.const_stability(tcx),
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 99f0e0531688a822a753cc585b7408b069cb682
+Subproject d3c793b025645a4565ac59aceb30d2d116ff1a4
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 0c39aae9ca9..16c58ecb455 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -30,6 +30,7 @@ use rustc_span::edition::Edition::Edition2021;
 use rustc_span::{Span, Symbol, sym};
 use rustc_trait_selection::infer::TyCtxtInferExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCause, Selection, SelectionContext};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -656,7 +657,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
                     };
                     let selection = SelectionContext::new(&infcx).select(&obligation);
                     let derived = if let Ok(Some(Selection::UserDefined(data))) = selection {
-                        tcx.has_attr(data.impl_def_id, sym::automatically_derived)
+                        find_attr!(tcx.get_all_attrs(data.impl_def_id), AttributeKind::AutomaticallyDerived(..))
                     } else {
                         false
                     };
diff --git a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
index a1dacd359a0..88b099c477f 100644
--- a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs
@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown {
         }
 
         // Is it derived?
-        if !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) {
+        if !find_attr!(cx.tcx.get_all_attrs(item.owner_id), AttributeKind::AutomaticallyDerived(..)) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_test_deps/Cargo.lock b/src/tools/clippy/clippy_test_deps/Cargo.lock
new file mode 100644
index 00000000000..a591dae3a1a
--- /dev/null
+++ b/src/tools/clippy/clippy_test_deps/Cargo.lock
@@ -0,0 +1,505 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "addr2line"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "backtrace"
+version = "0.3.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+
+[[package]]
+name = "bytes"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
+
+[[package]]
+name = "clippy_test_deps"
+version = "0.1.0"
+dependencies = [
+ "futures",
+ "if_chain",
+ "itertools",
+ "parking_lot",
+ "quote",
+ "regex",
+ "serde",
+ "syn",
+ "tokio",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "futures"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
+[[package]]
+name = "if_chain"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
+
+[[package]]
+name = "io-uring"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.174"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
+
+[[package]]
+name = "lock_api"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys",
+]
+
+[[package]]
+name = "object"
+version = "0.36.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "syn"
+version = "2.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tokio"
+version = "1.46.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "io-uring",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/src/tools/clippy/clippy_test_deps/Cargo.toml b/src/tools/clippy/clippy_test_deps/Cargo.toml
index f41334f0ade..a23ffcaf2f9 100644
--- a/src/tools/clippy/clippy_test_deps/Cargo.toml
+++ b/src/tools/clippy/clippy_test_deps/Cargo.toml
@@ -15,3 +15,6 @@ futures = "0.3"
 parking_lot = "0.12"
 tokio = { version = "1", features = ["io-util"] }
 itertools = "0.12"
+
+# Make sure we are not part of the rustc workspace.
+[workspace]
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 54de9baeb12..ad8c816e204 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1785,9 +1785,9 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
     tcx.hir_parent_owner_iter(id)
         .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_))))
         .any(|(id, _)| {
-            has_attr(
+            find_attr!(
                 tcx.hir_attrs(tcx.local_def_id_to_hir_id(id.def_id)),
-                sym::automatically_derived,
+                AttributeKind::AutomaticallyDerived(..)
             )
         })
 }
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 849f44031b7..33da1a25db1 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -53,6 +53,32 @@ impl TestMode {
     }
 }
 
+// Note that coverage tests use the same test files for multiple test modes.
+string_enum! {
+    #[derive(Clone, Copy, PartialEq, Debug)]
+    pub enum TestSuite {
+        Assembly => "assembly",
+        Codegen => "codegen",
+        CodegenUnits => "codegen-units",
+        Coverage => "coverage",
+        CoverageRunRustdoc => "coverage-run-rustdoc",
+        Crashes => "crashes",
+        Debuginfo => "debuginfo",
+        Incremental => "incremental",
+        MirOpt => "mir-opt",
+        Pretty => "pretty",
+        RunMake => "run-make",
+        Rustdoc => "rustdoc",
+        RustdocGui => "rustdoc-gui",
+        RustdocJs => "rustdoc-js",
+        RustdocJsStd=> "rustdoc-js-std",
+        RustdocJson => "rustdoc-json",
+        RustdocUi => "rustdoc-ui",
+        Ui => "ui",
+        UiFullDeps => "ui-fulldeps",
+    }
+}
+
 string_enum! {
     #[derive(Clone, Copy, PartialEq, Debug, Hash)]
     pub enum PassMode {
@@ -276,15 +302,13 @@ pub struct Config {
 
     /// The test suite.
     ///
-    /// Example: `tests/ui/` is the "UI" test *suite*, which happens to also be of the
+    /// Example: `tests/ui/` is [`TestSuite::Ui`] test *suite*, which happens to also be of the
     /// [`TestMode::Ui`] test *mode*.
     ///
-    /// Note that the same test directory (e.g. `tests/coverage/`) may correspond to multiple test
+    /// Note that the same test suite (e.g. `tests/coverage/`) may correspond to multiple test
     /// modes, e.g. `tests/coverage/` can be run under both [`TestMode::CoverageRun`] and
     /// [`TestMode::CoverageMap`].
-    ///
-    /// FIXME: stop using stringly-typed test suites!
-    pub suite: String,
+    pub suite: TestSuite,
 
     /// When specified, **only** the specified [`Debugger`] will be used to run against the
     /// `tests/debuginfo` test suite. When unspecified, `compiletest` will attempt to find all three
@@ -537,8 +561,8 @@ pub struct Config {
     // Configuration for various run-make tests frobbing things like C compilers or querying about
     // various LLVM component information.
     //
-    // FIXME: this really should be better packaged together. FIXME: these need better docs, e.g.
-    // for *host*, or for *target*?
+    // FIXME: this really should be better packaged together.
+    // FIXME: these need better docs, e.g. for *host*, or for *target*?
     pub cc: String,
     pub cxx: String,
     pub cflags: String,
@@ -617,6 +641,8 @@ impl Config {
         // For instance, `//@ ignore-stage1` will not work at all.
         Config {
             mode: TestMode::Rustdoc,
+            // E.g. this has no sensible default tbh.
+            suite: TestSuite::Ui,
 
             // Dummy values.
             edition: Default::default(),
@@ -642,7 +668,6 @@ impl Config {
             sysroot_base: Utf8PathBuf::default(),
             stage: Default::default(),
             stage_id: String::default(),
-            suite: Default::default(),
             debugger: Default::default(),
             run_ignored: Default::default(),
             with_rustc_debug_assertions: Default::default(),
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
deleted file mode 100644
index adf2a7bffef..00000000000
--- a/src/tools/compiletest/src/directive-list.rs
+++ /dev/null
@@ -1,260 +0,0 @@
-/// This was originally generated by collecting directives from ui tests and then extracting their
-/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
-/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
-const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
-    // tidy-alphabetical-start
-    "add-core-stubs",
-    "assembly-output",
-    "aux-bin",
-    "aux-build",
-    "aux-codegen-backend",
-    "aux-crate",
-    "build-aux-docs",
-    "build-fail",
-    "build-pass",
-    "check-fail",
-    "check-pass",
-    "check-run-results",
-    "check-stdout",
-    "check-test-line-numbers-match",
-    "compile-flags",
-    "doc-flags",
-    "dont-check-compiler-stderr",
-    "dont-check-compiler-stdout",
-    "dont-check-failure-status",
-    "dont-require-annotations",
-    "edition",
-    "error-pattern",
-    "exact-llvm-major-version",
-    "exec-env",
-    "failure-status",
-    "filecheck-flags",
-    "forbid-output",
-    "force-host",
-    "ignore-16bit",
-    "ignore-32bit",
-    "ignore-64bit",
-    "ignore-aarch64",
-    "ignore-aarch64-pc-windows-msvc",
-    "ignore-aarch64-unknown-linux-gnu",
-    "ignore-aix",
-    "ignore-android",
-    "ignore-apple",
-    "ignore-arm",
-    "ignore-arm-unknown-linux-gnueabi",
-    "ignore-arm-unknown-linux-gnueabihf",
-    "ignore-arm-unknown-linux-musleabi",
-    "ignore-arm-unknown-linux-musleabihf",
-    "ignore-auxiliary",
-    "ignore-avr",
-    "ignore-beta",
-    "ignore-cdb",
-    "ignore-compare-mode-next-solver",
-    "ignore-compare-mode-polonius",
-    "ignore-coverage-map",
-    "ignore-coverage-run",
-    "ignore-cross-compile",
-    "ignore-eabi",
-    "ignore-elf",
-    "ignore-emscripten",
-    "ignore-endian-big",
-    "ignore-enzyme",
-    "ignore-freebsd",
-    "ignore-fuchsia",
-    "ignore-gdb",
-    "ignore-gdb-version",
-    "ignore-gnu",
-    "ignore-haiku",
-    "ignore-horizon",
-    "ignore-i686-pc-windows-gnu",
-    "ignore-i686-pc-windows-msvc",
-    "ignore-illumos",
-    "ignore-ios",
-    "ignore-linux",
-    "ignore-lldb",
-    "ignore-llvm-version",
-    "ignore-loongarch32",
-    "ignore-loongarch64",
-    "ignore-macabi",
-    "ignore-macos",
-    "ignore-msp430",
-    "ignore-msvc",
-    "ignore-musl",
-    "ignore-netbsd",
-    "ignore-nightly",
-    "ignore-none",
-    "ignore-nto",
-    "ignore-nvptx64",
-    "ignore-nvptx64-nvidia-cuda",
-    "ignore-openbsd",
-    "ignore-pass",
-    "ignore-powerpc",
-    "ignore-remote",
-    "ignore-riscv64",
-    "ignore-rustc-debug-assertions",
-    "ignore-rustc_abi-x86-sse2",
-    "ignore-s390x",
-    "ignore-sgx",
-    "ignore-sparc64",
-    "ignore-spirv",
-    "ignore-stable",
-    "ignore-stage1",
-    "ignore-stage2",
-    "ignore-std-debug-assertions",
-    "ignore-test",
-    "ignore-thumb",
-    "ignore-thumbv8m.base-none-eabi",
-    "ignore-thumbv8m.main-none-eabi",
-    "ignore-tvos",
-    "ignore-unix",
-    "ignore-unknown",
-    "ignore-uwp",
-    "ignore-visionos",
-    "ignore-vxworks",
-    "ignore-wasi",
-    "ignore-wasm",
-    "ignore-wasm32",
-    "ignore-wasm32-bare",
-    "ignore-wasm64",
-    "ignore-watchos",
-    "ignore-windows",
-    "ignore-windows-gnu",
-    "ignore-windows-msvc",
-    "ignore-x32",
-    "ignore-x86",
-    "ignore-x86_64",
-    "ignore-x86_64-apple-darwin",
-    "ignore-x86_64-pc-windows-gnu",
-    "ignore-x86_64-unknown-linux-gnu",
-    "incremental",
-    "known-bug",
-    "llvm-cov-flags",
-    "max-llvm-major-version",
-    "min-cdb-version",
-    "min-gdb-version",
-    "min-lldb-version",
-    "min-llvm-version",
-    "min-system-llvm-version",
-    "needs-asm-support",
-    "needs-crate-type",
-    "needs-deterministic-layouts",
-    "needs-dlltool",
-    "needs-dynamic-linking",
-    "needs-enzyme",
-    "needs-force-clang-based-tests",
-    "needs-git-hash",
-    "needs-llvm-components",
-    "needs-llvm-zstd",
-    "needs-profiler-runtime",
-    "needs-relocation-model-pic",
-    "needs-run-enabled",
-    "needs-rust-lld",
-    "needs-rustc-debug-assertions",
-    "needs-sanitizer-address",
-    "needs-sanitizer-cfi",
-    "needs-sanitizer-dataflow",
-    "needs-sanitizer-hwaddress",
-    "needs-sanitizer-kcfi",
-    "needs-sanitizer-leak",
-    "needs-sanitizer-memory",
-    "needs-sanitizer-memtag",
-    "needs-sanitizer-safestack",
-    "needs-sanitizer-shadow-call-stack",
-    "needs-sanitizer-support",
-    "needs-sanitizer-thread",
-    "needs-std-debug-assertions",
-    "needs-subprocess",
-    "needs-symlink",
-    "needs-target-has-atomic",
-    "needs-target-std",
-    "needs-threads",
-    "needs-unwind",
-    "needs-wasmtime",
-    "needs-xray",
-    "no-auto-check-cfg",
-    "no-prefer-dynamic",
-    "normalize-stderr",
-    "normalize-stderr-32bit",
-    "normalize-stderr-64bit",
-    "normalize-stdout",
-    "only-16bit",
-    "only-32bit",
-    "only-64bit",
-    "only-aarch64",
-    "only-aarch64-apple-darwin",
-    "only-aarch64-unknown-linux-gnu",
-    "only-apple",
-    "only-arm",
-    "only-avr",
-    "only-beta",
-    "only-bpf",
-    "only-cdb",
-    "only-dist",
-    "only-elf",
-    "only-emscripten",
-    "only-gnu",
-    "only-i686-pc-windows-gnu",
-    "only-i686-pc-windows-msvc",
-    "only-i686-unknown-linux-gnu",
-    "only-ios",
-    "only-linux",
-    "only-loongarch32",
-    "only-loongarch64",
-    "only-loongarch64-unknown-linux-gnu",
-    "only-macos",
-    "only-mips",
-    "only-mips64",
-    "only-msp430",
-    "only-msvc",
-    "only-nightly",
-    "only-nvptx64",
-    "only-powerpc",
-    "only-riscv64",
-    "only-rustc_abi-x86-sse2",
-    "only-s390x",
-    "only-sparc",
-    "only-sparc64",
-    "only-stable",
-    "only-thumb",
-    "only-tvos",
-    "only-unix",
-    "only-visionos",
-    "only-wasm32",
-    "only-wasm32-bare",
-    "only-wasm32-wasip1",
-    "only-watchos",
-    "only-windows",
-    "only-windows-gnu",
-    "only-windows-msvc",
-    "only-x86",
-    "only-x86_64",
-    "only-x86_64-apple-darwin",
-    "only-x86_64-fortanix-unknown-sgx",
-    "only-x86_64-pc-windows-gnu",
-    "only-x86_64-pc-windows-msvc",
-    "only-x86_64-unknown-linux-gnu",
-    "pp-exact",
-    "pretty-compare-only",
-    "pretty-mode",
-    "proc-macro",
-    "reference",
-    "regex-error-pattern",
-    "remap-src-base",
-    "revisions",
-    "run-fail",
-    "run-flags",
-    "run-pass",
-    "run-rustfix",
-    "rustc-env",
-    "rustfix-only-machine-applicable",
-    "should-fail",
-    "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`.
-    "unused-revision-names",
-    // tidy-alphabetical-end
-];
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index 7fadb4dae2a..6bf968a3132 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -56,7 +56,6 @@ impl EarlyProps {
         let mut poisoned = false;
         iter_directives(
             config.mode,
-            &config.suite,
             &mut poisoned,
             testfile,
             rdr,
@@ -349,7 +348,6 @@ impl TestProps {
 
             iter_directives(
                 config.mode,
-                &config.suite,
                 &mut poisoned,
                 testfile,
                 file,
@@ -765,11 +763,266 @@ fn line_directive<'line>(
     Some(DirectiveLine { line_number, revision, raw_directive })
 }
 
-// To prevent duplicating the list of directives between `compiletest`,`htmldocck` and `jsondocck`,
-// we put it into a common file which is included in rust code and parsed here.
-// FIXME: This setup is temporary until we figure out how to improve this situation.
-//        See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
-include!("directive-list.rs");
+/// This was originally generated by collecting directives from ui tests and then extracting their
+/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
+/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
+const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
+    // tidy-alphabetical-start
+    "add-core-stubs",
+    "assembly-output",
+    "aux-bin",
+    "aux-build",
+    "aux-codegen-backend",
+    "aux-crate",
+    "build-aux-docs",
+    "build-fail",
+    "build-pass",
+    "check-fail",
+    "check-pass",
+    "check-run-results",
+    "check-stdout",
+    "check-test-line-numbers-match",
+    "compile-flags",
+    "doc-flags",
+    "dont-check-compiler-stderr",
+    "dont-check-compiler-stdout",
+    "dont-check-failure-status",
+    "dont-require-annotations",
+    "edition",
+    "error-pattern",
+    "exact-llvm-major-version",
+    "exec-env",
+    "failure-status",
+    "filecheck-flags",
+    "forbid-output",
+    "force-host",
+    "ignore-16bit",
+    "ignore-32bit",
+    "ignore-64bit",
+    "ignore-aarch64",
+    "ignore-aarch64-pc-windows-msvc",
+    "ignore-aarch64-unknown-linux-gnu",
+    "ignore-aix",
+    "ignore-android",
+    "ignore-apple",
+    "ignore-arm",
+    "ignore-arm-unknown-linux-gnueabi",
+    "ignore-arm-unknown-linux-gnueabihf",
+    "ignore-arm-unknown-linux-musleabi",
+    "ignore-arm-unknown-linux-musleabihf",
+    "ignore-auxiliary",
+    "ignore-avr",
+    "ignore-beta",
+    "ignore-cdb",
+    "ignore-compare-mode-next-solver",
+    "ignore-compare-mode-polonius",
+    "ignore-coverage-map",
+    "ignore-coverage-run",
+    "ignore-cross-compile",
+    "ignore-eabi",
+    "ignore-elf",
+    "ignore-emscripten",
+    "ignore-endian-big",
+    "ignore-enzyme",
+    "ignore-freebsd",
+    "ignore-fuchsia",
+    "ignore-gdb",
+    "ignore-gdb-version",
+    "ignore-gnu",
+    "ignore-haiku",
+    "ignore-horizon",
+    "ignore-i686-pc-windows-gnu",
+    "ignore-i686-pc-windows-msvc",
+    "ignore-illumos",
+    "ignore-ios",
+    "ignore-linux",
+    "ignore-lldb",
+    "ignore-llvm-version",
+    "ignore-loongarch32",
+    "ignore-loongarch64",
+    "ignore-macabi",
+    "ignore-macos",
+    "ignore-msp430",
+    "ignore-msvc",
+    "ignore-musl",
+    "ignore-netbsd",
+    "ignore-nightly",
+    "ignore-none",
+    "ignore-nto",
+    "ignore-nvptx64",
+    "ignore-nvptx64-nvidia-cuda",
+    "ignore-openbsd",
+    "ignore-pass",
+    "ignore-powerpc",
+    "ignore-remote",
+    "ignore-riscv64",
+    "ignore-rustc-debug-assertions",
+    "ignore-rustc_abi-x86-sse2",
+    "ignore-s390x",
+    "ignore-sgx",
+    "ignore-sparc64",
+    "ignore-spirv",
+    "ignore-stable",
+    "ignore-stage1",
+    "ignore-stage2",
+    "ignore-std-debug-assertions",
+    "ignore-test",
+    "ignore-thumb",
+    "ignore-thumbv8m.base-none-eabi",
+    "ignore-thumbv8m.main-none-eabi",
+    "ignore-tvos",
+    "ignore-unix",
+    "ignore-unknown",
+    "ignore-uwp",
+    "ignore-visionos",
+    "ignore-vxworks",
+    "ignore-wasi",
+    "ignore-wasm",
+    "ignore-wasm32",
+    "ignore-wasm32-bare",
+    "ignore-wasm64",
+    "ignore-watchos",
+    "ignore-windows",
+    "ignore-windows-gnu",
+    "ignore-windows-msvc",
+    "ignore-x32",
+    "ignore-x86",
+    "ignore-x86_64",
+    "ignore-x86_64-apple-darwin",
+    "ignore-x86_64-pc-windows-gnu",
+    "ignore-x86_64-unknown-linux-gnu",
+    "incremental",
+    "known-bug",
+    "llvm-cov-flags",
+    "max-llvm-major-version",
+    "min-cdb-version",
+    "min-gdb-version",
+    "min-lldb-version",
+    "min-llvm-version",
+    "min-system-llvm-version",
+    "needs-asm-support",
+    "needs-crate-type",
+    "needs-deterministic-layouts",
+    "needs-dlltool",
+    "needs-dynamic-linking",
+    "needs-enzyme",
+    "needs-force-clang-based-tests",
+    "needs-git-hash",
+    "needs-llvm-components",
+    "needs-llvm-zstd",
+    "needs-profiler-runtime",
+    "needs-relocation-model-pic",
+    "needs-run-enabled",
+    "needs-rust-lld",
+    "needs-rustc-debug-assertions",
+    "needs-sanitizer-address",
+    "needs-sanitizer-cfi",
+    "needs-sanitizer-dataflow",
+    "needs-sanitizer-hwaddress",
+    "needs-sanitizer-kcfi",
+    "needs-sanitizer-leak",
+    "needs-sanitizer-memory",
+    "needs-sanitizer-memtag",
+    "needs-sanitizer-safestack",
+    "needs-sanitizer-shadow-call-stack",
+    "needs-sanitizer-support",
+    "needs-sanitizer-thread",
+    "needs-std-debug-assertions",
+    "needs-subprocess",
+    "needs-symlink",
+    "needs-target-has-atomic",
+    "needs-target-std",
+    "needs-threads",
+    "needs-unwind",
+    "needs-wasmtime",
+    "needs-xray",
+    "no-auto-check-cfg",
+    "no-prefer-dynamic",
+    "normalize-stderr",
+    "normalize-stderr-32bit",
+    "normalize-stderr-64bit",
+    "normalize-stdout",
+    "only-16bit",
+    "only-32bit",
+    "only-64bit",
+    "only-aarch64",
+    "only-aarch64-apple-darwin",
+    "only-aarch64-unknown-linux-gnu",
+    "only-apple",
+    "only-arm",
+    "only-avr",
+    "only-beta",
+    "only-bpf",
+    "only-cdb",
+    "only-dist",
+    "only-elf",
+    "only-emscripten",
+    "only-gnu",
+    "only-i686-pc-windows-gnu",
+    "only-i686-pc-windows-msvc",
+    "only-i686-unknown-linux-gnu",
+    "only-ios",
+    "only-linux",
+    "only-loongarch32",
+    "only-loongarch64",
+    "only-loongarch64-unknown-linux-gnu",
+    "only-macos",
+    "only-mips",
+    "only-mips64",
+    "only-msp430",
+    "only-msvc",
+    "only-nightly",
+    "only-nvptx64",
+    "only-powerpc",
+    "only-riscv64",
+    "only-rustc_abi-x86-sse2",
+    "only-s390x",
+    "only-sparc",
+    "only-sparc64",
+    "only-stable",
+    "only-thumb",
+    "only-tvos",
+    "only-unix",
+    "only-visionos",
+    "only-wasm32",
+    "only-wasm32-bare",
+    "only-wasm32-wasip1",
+    "only-watchos",
+    "only-windows",
+    "only-windows-gnu",
+    "only-windows-msvc",
+    "only-x86",
+    "only-x86_64",
+    "only-x86_64-apple-darwin",
+    "only-x86_64-fortanix-unknown-sgx",
+    "only-x86_64-pc-windows-gnu",
+    "only-x86_64-pc-windows-msvc",
+    "only-x86_64-unknown-linux-gnu",
+    "pp-exact",
+    "pretty-compare-only",
+    "pretty-mode",
+    "proc-macro",
+    "reference",
+    "regex-error-pattern",
+    "remap-src-base",
+    "revisions",
+    "run-fail",
+    "run-flags",
+    "run-pass",
+    "run-rustfix",
+    "rustc-env",
+    "rustfix-only-machine-applicable",
+    "should-fail",
+    "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`.
+    "unused-revision-names",
+    // tidy-alphabetical-end
+];
 
 const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
     "count",
@@ -834,42 +1087,32 @@ pub(crate) struct CheckDirectiveResult<'ln> {
 pub(crate) fn check_directive<'a>(
     directive_ln: &'a str,
     mode: TestMode,
-    original_line: &str,
 ) -> CheckDirectiveResult<'a> {
     let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
 
+    let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name)
+        || match mode {
+            TestMode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES.contains(&directive_name),
+            TestMode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES.contains(&directive_name),
+            _ => false,
+        };
+
     let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
-    let is_known = |s: &str| {
-        KNOWN_DIRECTIVE_NAMES.contains(&s)
-            || match mode {
-                TestMode::Rustdoc | TestMode::RustdocJson => {
-                    original_line.starts_with("//@")
-                        && match mode {
-                            TestMode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES,
-                            TestMode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
-                            _ => unreachable!(),
-                        }
-                        .contains(&s)
-                }
-                _ => false,
-            }
-    };
     let trailing_directive = {
         // 1. is the directive name followed by a space? (to exclude `:`)
-        matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(' '))
+        directive_ln.get(directive_name.len()..).is_some_and(|s| s.starts_with(' '))
             // 2. is what is after that directive also a directive (ex: "only-x86 only-arm")
-            && is_known(trailing)
+            && KNOWN_DIRECTIVE_NAMES.contains(&trailing)
     }
     .then_some(trailing);
 
-    CheckDirectiveResult { is_known_directive: is_known(&directive_name), trailing_directive }
+    CheckDirectiveResult { is_known_directive, trailing_directive }
 }
 
 const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
 
 fn iter_directives(
     mode: TestMode,
-    _suite: &str,
     poisoned: &mut bool,
     testfile: &Utf8Path,
     rdr: impl Read,
@@ -914,9 +1157,9 @@ fn iter_directives(
         };
 
         // Perform unknown directive check on Rust files.
-        if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
+        if testfile.extension() == Some("rs") {
             let CheckDirectiveResult { is_known_directive, trailing_directive } =
-                check_directive(directive_line.raw_directive, mode, ln);
+                check_directive(directive_line.raw_directive, mode);
 
             if !is_known_directive {
                 *poisoned = true;
@@ -936,7 +1179,7 @@ fn iter_directives(
                     "{testfile}:{line_number}: detected trailing compiletest test directive `{}`",
                     trailing_directive,
                 );
-                help!("put the trailing directive in it's own line: `//@ {}`", trailing_directive);
+                help!("put the trailing directive in its own line: `//@ {}`", trailing_directive);
 
                 return;
             }
@@ -1388,7 +1631,6 @@ pub(crate) fn make_test_description<R: Read>(
     // Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives.
     iter_directives(
         config.mode,
-        &config.suite,
         &mut local_poisoned,
         path,
         src,
diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs
index 9c5751b416b..5682cc57b6f 100644
--- a/src/tools/compiletest/src/directives/tests.rs
+++ b/src/tools/compiletest/src/directives/tests.rs
@@ -785,7 +785,7 @@ fn threads_support() {
 
 fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) {
     let rdr = std::io::Cursor::new(&buf);
-    iter_directives(TestMode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
+    iter_directives(TestMode::Ui, poisoned, path, rdr, &mut |_| {});
 }
 
 #[test]
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index be82f8cb480..f3b3605a120 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -360,7 +360,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         stage_id: matches.opt_str("stage-id").unwrap(),
 
         mode,
-        suite: matches.opt_str("suite").unwrap(),
+        suite: matches.opt_str("suite").unwrap().parse().expect("invalid suite"),
         debugger: matches.opt_str("debugger").map(|debugger| {
             debugger
                 .parse::<Debugger>()
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 12111e9c6ef..cb8f593c9df 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -16,9 +16,9 @@ use regex::{Captures, Regex};
 use tracing::*;
 
 use crate::common::{
-    CompareMode, Config, Debugger, FailMode, PassMode, TestMode, TestPaths, UI_EXTENSIONS,
-    UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG,
-    expected_output_path, incremental_dir, output_base_dir, output_base_name,
+    CompareMode, Config, Debugger, FailMode, PassMode, TestMode, TestPaths, TestSuite,
+    UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG,
+    UI_WINDOWS_SVG, expected_output_path, incremental_dir, output_base_dir, output_base_name,
     output_testname_unique,
 };
 use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
@@ -1494,7 +1494,10 @@ impl<'test> TestCx<'test> {
     }
 
     fn is_rustdoc(&self) -> bool {
-        matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json")
+        matches!(
+            self.config.suite,
+            TestSuite::RustdocUi | TestSuite::RustdocJs | TestSuite::RustdocJson
+        )
     }
 
     fn make_compile_args(
diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs
index 38f0e956474..d0a0c960b45 100644
--- a/src/tools/compiletest/src/runtest/coverage.rs
+++ b/src/tools/compiletest/src/runtest/coverage.rs
@@ -6,7 +6,7 @@ use std::process::Command;
 use camino::{Utf8Path, Utf8PathBuf};
 use glob::glob;
 
-use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP};
+use crate::common::{TestSuite, UI_COVERAGE, UI_COVERAGE_MAP};
 use crate::runtest::{Emit, ProcRes, TestCx, WillExecute};
 use crate::util::static_regex;
 
@@ -91,7 +91,7 @@ impl<'test> TestCx<'test> {
         let mut profraw_paths = vec![profraw_path];
         let mut bin_paths = vec![self.make_exe_name()];
 
-        if self.config.suite == "coverage-run-rustdoc" {
+        if self.config.suite == TestSuite::CoverageRunRustdoc {
             self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths);
         }
 
diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs
index 637ea833357..236f021ce82 100644
--- a/src/tools/compiletest/src/runtest/rustdoc.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc.rs
@@ -4,7 +4,7 @@ use super::{TestCx, remove_and_create_dir_all};
 
 impl TestCx<'_> {
     pub(super) fn run_rustdoc_test(&self) {
-        assert!(self.revision.is_none(), "revisions not relevant here");
+        assert!(self.revision.is_none(), "revisions not supported in this test suite");
 
         let out_dir = self.output_base_dir();
         remove_and_create_dir_all(&out_dir).unwrap_or_else(|e| {
diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs
index 9f88faca892..4f35efedfde 100644
--- a/src/tools/compiletest/src/runtest/rustdoc_json.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs
@@ -6,7 +6,7 @@ impl TestCx<'_> {
     pub(super) fn run_rustdoc_json_test(&self) {
         //FIXME: Add bless option.
 
-        assert!(self.revision.is_none(), "revisions not relevant here");
+        assert!(self.revision.is_none(), "revisions not supported in this test suite");
 
         let out_dir = self.output_base_dir();
         remove_and_create_dir_all(&out_dir).unwrap_or_else(|e| {
diff --git a/src/tools/jsondocck/src/directive.rs b/src/tools/jsondocck/src/directive.rs
index fdb2fa6dbbe..c52c1686660 100644
--- a/src/tools/jsondocck/src/directive.rs
+++ b/src/tools/jsondocck/src/directive.rs
@@ -105,13 +105,10 @@ impl DirectiveKind {
                 [_path, value] => Self::HasNotValue { value: value.clone() },
                 _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"),
             },
-            // Ignore compiletest directives, like //@ edition
-            (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&directive_name) => {
-                return None;
-            }
-            _ => {
-                panic!("Invalid directive `//@ {}{directive_name}`", if negated { "!" } else { "" })
-            }
+            // Ignore unknown directives as they might be compiletest directives
+            // since they share the same `//@` prefix by convention. In any case,
+            // compiletest rejects unknown directives for us.
+            _ => return None,
         };
 
         Some((kind, &args[0]))
@@ -216,10 +213,6 @@ fn get_one<'a>(matches: &[&'a Value]) -> Result<&'a Value, String> {
     }
 }
 
-// FIXME: This setup is temporary until we figure out how to improve this situation.
-//        See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
-include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs"));
-
 fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
     if s.starts_with("$") {
         Cow::Borrowed(&cache.variables.get(&s[1..]).unwrap_or_else(|| {
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index d84be4d3a3a..c3487565c23 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -47,8 +47,8 @@ static LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
         ^\s*
         //@\s+
         (?P<negated>!?)
-        (?P<directive>[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)
-        (?P<args>.*)$
+        (?P<directive>.+?)
+        (?:[\s:](?P<args>.*))?$
     "#,
     )
     .ignore_whitespace(true)
@@ -58,15 +58,7 @@ static LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
 });
 
 static DEPRECATED_LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
-    RegexBuilder::new(
-        r#"
-        //\s+@
-    "#,
-    )
-    .ignore_whitespace(true)
-    .unicode(true)
-    .build()
-    .unwrap()
+    RegexBuilder::new(r"//\s+@").ignore_whitespace(true).unicode(true).build().unwrap()
 });
 
 fn print_err(msg: &str, lineno: usize) {
@@ -94,7 +86,7 @@ fn get_directives(template: &str) -> Result<Vec<Directive>, ()> {
 
         let negated = &cap["negated"] == "!";
 
-        let args_str = &cap["args"];
+        let args_str = cap.name("args").map(|m| m.as_str()).unwrap_or_default();
         let Some(args) = shlex::split(args_str) else {
             print_err(&format!("Invalid arguments to shlex::split: `{args_str}`",), lineno);
             errors = true;
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index fa833b51fa3..35555723f5d 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -34,4 +34,5 @@ windows-sys = { version = "0.59", features = [
     "Wdk_Storage_FileSystem",
 ] }
 
+# Make sure we are not part of the rustc workspace.
 [workspace]
diff --git a/src/tools/miri/tests/pass/shims/random.rs b/src/tools/miri/tests/pass/shims/random.rs
index ae75ebdcd3f..2a5c8993662 100644
--- a/src/tools/miri/tests/pass/shims/random.rs
+++ b/src/tools/miri/tests/pass/shims/random.rs
@@ -1,5 +1,5 @@
 #![feature(random)]
 
 fn main() {
-    let _x: i32 = std::random::random();
+    let _x: i32 = std::random::random(..);
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index de8a42979bb..f9eb44d03ab 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -4711,9 +4711,9 @@ The tracking issue for this feature is: [#133668]
         label: "const_trait_impl",
         description: r##"# `const_trait_impl`
 
-The tracking issue for this feature is: [#67792]
+The tracking issue for this feature is: [#143874]
 
-[#67792]: https://github.com/rust-lang/rust/issues/67792
+[#143874]: https://github.com/rust-lang/rust/issues/143874
 
 ------------------------
 "##,
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index 4835c220210..d995106ae02 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "tidy"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 autobins = false
 
 [dependencies]
diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs
index 141083290c6..9ddce725106 100644
--- a/src/tools/tidy/src/alphabetical.rs
+++ b/src/tools/tidy/src/alphabetical.rs
@@ -103,7 +103,7 @@ fn check_section<'a>(
 
         let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' ');
 
-        if version_sort(&trimmed_line, &prev_line_trimmed_lowercase).is_lt() {
+        if version_sort(trimmed_line, prev_line_trimmed_lowercase).is_lt() {
             tidy_error_ext!(err, bad, "{file}:{}: line not in alphabetical order", idx + 1);
         }
 
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index 9b78ba75a05..a18f549844b 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -75,7 +75,7 @@ mod os_impl {
                         return ReadOnlyFs;
                     }
 
-                    panic!("unable to create temporary file `{:?}`: {:?}", path, e);
+                    panic!("unable to create temporary file `{path:?}`: {e:?}");
                 }
             }
         }
@@ -83,12 +83,7 @@ mod os_impl {
         for &source_dir in sources {
             match check_dir(source_dir) {
                 Unsupported => return false,
-                ReadOnlyFs => {
-                    return match check_dir(output) {
-                        Supported => true,
-                        _ => false,
-                    };
-                }
+                ReadOnlyFs => return matches!(check_dir(output), Supported),
                 _ => {}
             }
         }
@@ -139,7 +134,7 @@ mod os_impl {
                     return;
                 }
 
-                if t!(is_executable(&file), file) {
+                if t!(is_executable(file), file) {
                     let rel_path = file.strip_prefix(path).unwrap();
                     let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
 
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index bf813d2131e..f43f5eae9a5 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -624,7 +624,7 @@ fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, bad: &mut b
     let is_proc_macro_pkg = |pkg: &Package| pkg.targets.iter().any(|target| target.is_proc_macro());
 
     let mut proc_macro_deps = HashSet::new();
-    for pkg in metadata.packages.iter().filter(|pkg| is_proc_macro_pkg(*pkg)) {
+    for pkg in metadata.packages.iter().filter(|pkg| is_proc_macro_pkg(pkg)) {
         deps_of(&metadata, &pkg.id, &mut proc_macro_deps);
     }
     // Remove the proc-macro crates themselves
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index bb61412f678..65aa89fe801 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -119,8 +119,7 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
             let Some(split_line) = split_line else {
                 errors.push(format!(
                     "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
-                    but got \"{}\" without a `:` delimiter",
-                    line,
+                    but got \"{line}\" without a `:` delimiter",
                 ));
                 continue;
             };
@@ -129,10 +128,8 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
 
             // If this is a duplicate of another error code, emit a fatal error.
             if error_codes.contains(&err_code) {
-                errors.push(format!(
-                    "{path}:{line_index}: Found duplicate error code: `{}`",
-                    err_code
-                ));
+                errors
+                    .push(format!("{path}:{line_index}: Found duplicate error code: `{err_code}`"));
                 continue;
             }
 
@@ -145,8 +142,7 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
             let Some(rest) = rest else {
                 errors.push(format!(
                     "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
-                    but got \"{}\" without a `,` delimiter",
-                    line,
+                    but got \"{line}\" without a `,` delimiter",
                 ));
                 continue;
             };
@@ -209,7 +205,7 @@ fn check_error_codes_docs(
         }
 
         let (found_code_example, found_proper_doctest, emit_ignore_warning, no_longer_emitted) =
-            check_explanation_has_doctest(&contents, &err_code);
+            check_explanation_has_doctest(contents, err_code);
 
         if emit_ignore_warning {
             verbose_print!(
@@ -232,7 +228,7 @@ fn check_error_codes_docs(
             return;
         }
 
-        let test_ignored = IGNORE_DOCTEST_CHECK.contains(&&err_code);
+        let test_ignored = IGNORE_DOCTEST_CHECK.contains(&err_code);
 
         // Check that the explanation has a doctest, and if it shouldn't, that it doesn't
         if !found_proper_doctest && !test_ignored {
@@ -300,7 +296,7 @@ fn check_error_codes_tests(
     let tests_path = root_path.join(Path::new(ERROR_TESTS_PATH));
 
     for code in error_codes {
-        let test_path = tests_path.join(format!("{}.stderr", code));
+        let test_path = tests_path.join(format!("{code}.stderr"));
 
         if !test_path.exists() && !IGNORE_UI_TEST_CHECK.contains(&code.as_str()) {
             verbose_print!(
@@ -388,7 +384,7 @@ fn check_error_codes_used(
 
                     if !error_codes.contains(&error_code) {
                         // This error code isn't properly defined, we must error.
-                        errors.push(format!("Error code `{}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/lib.rs`.", error_code));
+                        errors.push(format!("Error code `{error_code}` is used in the compiler but not defined and documented in `compiler/rustc_error_codes/src/lib.rs`."));
                         continue;
                     }
 
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
index baab46752a5..381ea44fd46 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -64,8 +64,8 @@ fn check_impl(
     extra_checks: Option<&str>,
     pos_args: &[String],
 ) -> Result<(), Error> {
-    let show_diff = std::env::var("TIDY_PRINT_DIFF")
-        .map_or(false, |v| v.eq_ignore_ascii_case("true") || v == "1");
+    let show_diff =
+        std::env::var("TIDY_PRINT_DIFF").is_ok_and(|v| v.eq_ignore_ascii_case("true") || v == "1");
 
     // Split comma-separated args up
     let lint_args = match extra_checks {
@@ -141,7 +141,7 @@ fn check_impl(
             );
         }
         // Rethrow error
-        let _ = res?;
+        res?;
     }
 
     if python_fmt {
@@ -173,7 +173,7 @@ fn check_impl(
         }
 
         // Rethrow error
-        let _ = res?;
+        res?;
     }
 
     if cpp_fmt {
@@ -244,7 +244,7 @@ fn check_impl(
             }
         }
         // Rethrow error
-        let _ = res?;
+        res?;
     }
 
     if shell_lint {
@@ -286,8 +286,8 @@ fn run_ruff(
     file_args: &[&OsStr],
     ruff_args: &[&OsStr],
 ) -> Result<(), Error> {
-    let mut cfg_args_ruff = cfg_args.into_iter().copied().collect::<Vec<_>>();
-    let mut file_args_ruff = file_args.into_iter().copied().collect::<Vec<_>>();
+    let mut cfg_args_ruff = cfg_args.to_vec();
+    let mut file_args_ruff = file_args.to_vec();
 
     let mut cfg_path = root_path.to_owned();
     cfg_path.extend(RUFF_CONFIG_PATH);
@@ -305,7 +305,7 @@ fn run_ruff(
         file_args_ruff.push(root_path.as_os_str());
     }
 
-    let mut args: Vec<&OsStr> = ruff_args.into_iter().copied().collect();
+    let mut args: Vec<&OsStr> = ruff_args.to_vec();
     args.extend(merge_args(&cfg_args_ruff, &file_args_ruff));
     py_runner(py_path, true, None, "ruff", &args)
 }
diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs
index 55f937aeacf..bc217a55cc1 100644
--- a/src/tools/tidy/src/extdeps.rs
+++ b/src/tools/tidy/src/extdeps.rs
@@ -41,7 +41,7 @@ pub fn check(root: &Path, bad: &mut bool) {
             let source = line.split_once('=').unwrap().1.trim();
 
             // Ensure source is allowed.
-            if !ALLOWED_SOURCES.contains(&&*source) {
+            if !ALLOWED_SOURCES.contains(&source) {
                 tidy_error!(bad, "invalid source: {}", source);
             }
         }
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 6093e7fd263..e83b47e1380 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -125,8 +125,8 @@ pub fn check(
                 let gate_test_str = "gate-test-";
 
                 let feature_name = match line.find(gate_test_str) {
-                    // NB: the `splitn` always succeeds, even if the delimiter is not present.
-                    Some(i) => line[i + gate_test_str.len()..].splitn(2, ' ').next().unwrap(),
+                    // `split` always contains at least 1 element, even if the delimiter is not present.
+                    Some(i) => line[i + gate_test_str.len()..].split(' ').next().unwrap(),
                     None => continue,
                 };
                 match features.get_mut(feature_name) {
@@ -135,16 +135,14 @@ pub fn check(
                             err(&format!(
                                 "The file is already marked as gate test \
                                       through its name, no need for a \
-                                      'gate-test-{}' comment",
-                                feature_name
+                                      'gate-test-{feature_name}' comment"
                             ));
                         }
                         f.has_gate_test = true;
                     }
                     None => {
                         err(&format!(
-                            "gate-test test found referencing a nonexistent feature '{}'",
-                            feature_name
+                            "gate-test test found referencing a nonexistent feature '{feature_name}'"
                         ));
                     }
                 }
@@ -170,8 +168,7 @@ pub fn check(
         );
         println!(
             "Hint: If you already have such a test and don't want to rename it,\
-                \n      you can also add a // gate-test-{} line to the test file.",
-            name
+                \n      you can also add a // gate-test-{name} line to the test file."
         );
     }
 
@@ -231,7 +228,7 @@ pub fn check(
 fn get_version_and_channel(src_path: &Path) -> (Version, String) {
     let version_str = t!(std::fs::read_to_string(src_path.join("version")));
     let version_str = version_str.trim();
-    let version = t!(std::str::FromStr::from_str(&version_str).map_err(|e| format!("{e:?}")));
+    let version = t!(std::str::FromStr::from_str(version_str).map_err(|e| format!("{e:?}")));
     let channel_str = t!(std::fs::read_to_string(src_path.join("ci").join("channel")));
     (version, channel_str.trim().to_owned())
 }
@@ -468,7 +465,7 @@ fn get_and_check_lib_features(
     map_lib_features(base_src_path, &mut |res, file, line| match res {
         Ok((name, f)) => {
             let mut check_features = |f: &Feature, list: &Features, display: &str| {
-                if let Some(ref s) = list.get(name) {
+                if let Some(s) = list.get(name) {
                     if f.tracking_issue != s.tracking_issue && f.level != Status::Accepted {
                         tidy_error!(
                             bad,
@@ -483,7 +480,7 @@ fn get_and_check_lib_features(
                     }
                 }
             };
-            check_features(&f, &lang_features, "corresponding lang feature");
+            check_features(&f, lang_features, "corresponding lang feature");
             check_features(&f, &lib_features, "previous");
             lib_features.insert(name.to_owned(), f);
         }
@@ -543,7 +540,7 @@ fn map_lib_features(
                     continue;
                 }
 
-                if let Some((ref name, ref mut f)) = becoming_feature {
+                if let Some((name, ref mut f)) = becoming_feature {
                     if f.tracking_issue.is_none() {
                         f.tracking_issue = find_attr_val(line, "issue").and_then(handle_issue_none);
                     }
diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs
index 6a902e80f8e..0e0629a48e2 100644
--- a/src/tools/tidy/src/features/version.rs
+++ b/src/tools/tidy/src/features/version.rs
@@ -20,7 +20,7 @@ impl fmt::Display for Version {
             Version::Explicit { parts } => {
                 f.pad(&format!("{}.{}.{}", parts[0], parts[1], parts[2]))
             }
-            Version::CurrentPlaceholder => f.pad(&format!("CURRENT")),
+            Version::CurrentPlaceholder => f.pad("CURRENT"),
         }
     }
 }
diff --git a/src/tools/tidy/src/features/version/tests.rs b/src/tools/tidy/src/features/version/tests.rs
index 7701dce2df1..453ba40586e 100644
--- a/src/tools/tidy/src/features/version/tests.rs
+++ b/src/tools/tidy/src/features/version/tests.rs
@@ -33,6 +33,6 @@ fn test_to_string() {
 
     assert_eq!(v_1_0_0.to_string(), "1.0.0");
     assert_eq!(v_1_32_1.to_string(), "1.32.1");
-    assert_eq!(format!("{:<8}", v_1_32_1), "1.32.1  ");
-    assert_eq!(format!("{:>8}", v_1_32_1), "  1.32.1");
+    assert_eq!(format!("{v_1_32_1:<8}"), "1.32.1  ");
+    assert_eq!(format!("{v_1_32_1:>8}"), "  1.32.1");
 }
diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs
index 6f154b92eff..48d14a37514 100644
--- a/src/tools/tidy/src/fluent_alphabetical.rs
+++ b/src/tools/tidy/src/fluent_alphabetical.rs
@@ -13,8 +13,8 @@ fn message() -> &'static Regex {
     static_regex!(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#)
 }
 
-fn filter_fluent(path: &Path) -> bool {
-    if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
+fn is_fluent(path: &Path) -> bool {
+    path.extension().is_some_and(|ext| ext == "flt")
 }
 
 fn check_alphabetic(
@@ -92,7 +92,7 @@ pub fn check(path: &Path, bless: bool, bad: &mut bool) {
     let mut all_defined_msgs = HashMap::new();
     walk(
         path,
-        |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
+        |path, is_dir| filter_dirs(path) || (!is_dir && !is_fluent(path)),
         &mut |ent, contents| {
             if bless {
                 let sorted = sort_messages(
@@ -104,7 +104,7 @@ pub fn check(path: &Path, bless: bool, bad: &mut bool) {
                 if sorted != contents {
                     let mut f =
                         OpenOptions::new().write(true).truncate(true).open(ent.path()).unwrap();
-                    f.write(sorted.as_bytes()).unwrap();
+                    f.write_all(sorted.as_bytes()).unwrap();
                 }
             } else {
                 check_alphabetic(
diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs
index 6a136e5aec6..85c1ef6166a 100644
--- a/src/tools/tidy/src/fluent_period.rs
+++ b/src/tools/tidy/src/fluent_period.rs
@@ -37,7 +37,7 @@ fn check_period(filename: &str, contents: &str, bad: &mut bool) {
                 if let Some(PatternElement::TextElement { value }) = pat.elements.last() {
                     // We don't care about ellipses.
                     if value.ends_with(".") && !value.ends_with("...") {
-                        let ll = find_line(contents, *value);
+                        let ll = find_line(contents, value);
                         let name = m.id.name;
                         tidy_error!(bad, "{filename}:{ll}: message `{name}` ends in a period");
                     }
@@ -52,7 +52,7 @@ fn check_period(filename: &str, contents: &str, bad: &mut bool) {
 
                 if let Some(PatternElement::TextElement { value }) = attr.value.elements.last() {
                     if value.ends_with(".") && !value.ends_with("...") {
-                        let ll = find_line(contents, *value);
+                        let ll = find_line(contents, value);
                         let name = attr.id.name;
                         tidy_error!(bad, "{filename}:{ll}: attr `{name}` ends in a period");
                     }
diff --git a/src/tools/tidy/src/fluent_used.rs b/src/tools/tidy/src/fluent_used.rs
index ab56b5f0b0e..12fafd9a7ff 100644
--- a/src/tools/tidy/src/fluent_used.rs
+++ b/src/tools/tidy/src/fluent_used.rs
@@ -13,8 +13,8 @@ fn filter_used_messages(
     // we don't just check messages never appear in Rust files,
     // because messages can be used as parts of other fluent messages in Fluent files,
     // so we do checking messages appear only once in all Rust and Fluent files.
-    let mut matches = static_regex!(r"\w+").find_iter(contents);
-    while let Some(name) = matches.next() {
+    let matches = static_regex!(r"\w+").find_iter(contents);
+    for name in matches {
         if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) {
             // if one msg appears for the first time,
             // remove it from `msgs_not_appeared_yet` and insert it into `msgs_appeared_only_once`.
diff --git a/src/tools/tidy/src/gcc_submodule.rs b/src/tools/tidy/src/gcc_submodule.rs
index 952ebe9e0cf..5d726c3ea48 100644
--- a/src/tools/tidy/src/gcc_submodule.rs
+++ b/src/tools/tidy/src/gcc_submodule.rs
@@ -7,7 +7,9 @@ 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()))
+        .unwrap_or_else(|_| {
+            panic!("Cannot read GCC version from {}", cg_gcc_version_path.display())
+        })
         .trim()
         .to_string();
 
@@ -27,14 +29,13 @@ pub fn check(root_path: &Path, compiler_path: &Path, bad: &mut bool) {
     //  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(&['+', '-']);
+    let gcc_submodule_sha = git_output.trim_start_matches(['+', '-']);
     if gcc_submodule_sha != cg_gcc_version {
         *bad = true;
         eprintln!(
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 1eb5485f2b8..a67f7a511b5 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -15,11 +15,12 @@ use std::{env, process};
 use tidy::*;
 
 fn main() {
-    // Running Cargo will read the libstd Cargo.toml
+    // Enable nightly, because Cargo will read the libstd Cargo.toml
     // which uses the unstable `public-dependency` feature.
-    //
-    // `setenv` might not be thread safe, so run it before using multiple threads.
-    env::set_var("RUSTC_BOOTSTRAP", "1");
+    // SAFETY: no other threads have been spawned
+    unsafe {
+        env::set_var("RUSTC_BOOTSTRAP", "1");
+    }
 
     let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into();
     let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into();
diff --git a/src/tools/tidy/src/mir_opt_tests.rs b/src/tools/tidy/src/mir_opt_tests.rs
index bb0d8150be4..1efe71b1687 100644
--- a/src/tools/tidy/src/mir_opt_tests.rs
+++ b/src/tools/tidy/src/mir_opt_tests.rs
@@ -49,7 +49,7 @@ fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) {
 }
 
 fn check_dash_files(path: &Path, bless: bool, bad: &mut bool) {
-    for file in walkdir::WalkDir::new(&path.join("mir-opt"))
+    for file in walkdir::WalkDir::new(path.join("mir-opt"))
         .into_iter()
         .filter_map(Result::ok)
         .filter(|e| e.file_type().is_file())
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index 9b915e0f737..b7d4a331891 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -86,7 +86,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             return;
         }
 
-        check_cfgs(contents, &file, bad, &mut saw_target_arch, &mut saw_cfg_bang);
+        check_cfgs(contents, file, bad, &mut saw_target_arch, &mut saw_cfg_bang);
     });
 
     assert!(saw_target_arch);
diff --git a/src/tools/tidy/src/rustdoc_gui_tests.rs b/src/tools/tidy/src/rustdoc_gui_tests.rs
index 91776bc989e..3b995f219d2 100644
--- a/src/tools/tidy/src/rustdoc_gui_tests.rs
+++ b/src/tools/tidy/src/rustdoc_gui_tests.rs
@@ -5,7 +5,7 @@ use std::path::Path;
 pub fn check(path: &Path, bad: &mut bool) {
     crate::walk::walk(
         &path.join("rustdoc-gui"),
-        |p, is_dir| !is_dir && p.extension().map_or(true, |e| e != "goml"),
+        |p, is_dir| !is_dir && p.extension().is_none_or(|e| e != "goml"),
         &mut |entry, content| {
             for line in content.lines() {
                 if !line.starts_with("// ") {
diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs
index 5e924544f0d..5737fcbafc0 100644
--- a/src/tools/tidy/src/rustdoc_js.rs
+++ b/src/tools/tidy/src/rustdoc_js.rs
@@ -88,7 +88,7 @@ pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &m
     let mut files_to_check = Vec::new();
     walk_no_read(
         &[&librustdoc_path.join("html/static/js")],
-        |path, is_dir| is_dir || !path.extension().is_some_and(|ext| ext == OsStr::new("js")),
+        |path, is_dir| is_dir || path.extension().is_none_or(|ext| ext != OsStr::new("js")),
         &mut |path: &DirEntry| {
             files_to_check.push(path.path().into());
         },
diff --git a/src/tools/tidy/src/rustdoc_json.rs b/src/tools/tidy/src/rustdoc_json.rs
index 19b8e79ec33..722e1ebd0ca 100644
--- a/src/tools/tidy/src/rustdoc_json.rs
+++ b/src/tools/tidy/src/rustdoc_json.rs
@@ -20,7 +20,7 @@ pub fn check(src_path: &Path, ci_info: &crate::CiInfo, bad: &mut bool) {
         return;
     }
     // Then we check that if `FORMAT_VERSION` was updated, the `Latest feature:` was also updated.
-    match crate::git_diff(&base_commit, src_path.join("rustdoc-json-types")) {
+    match crate::git_diff(base_commit, src_path.join("rustdoc-json-types")) {
         Some(output) => {
             let mut format_version_updated = false;
             let mut latest_feature_comment_updated = false;
diff --git a/src/tools/tidy/src/rustdoc_templates.rs b/src/tools/tidy/src/rustdoc_templates.rs
index 2173dbf7e74..dca3e8d9d25 100644
--- a/src/tools/tidy/src/rustdoc_templates.rs
+++ b/src/tools/tidy/src/rustdoc_templates.rs
@@ -14,7 +14,7 @@ const TAGS: &[(&str, &str)] = &[("{#", "#}"), ("{%", "%}"), ("{{", "}}")];
 pub fn check(librustdoc_path: &Path, bad: &mut bool) {
     walk(
         &librustdoc_path.join("html/templates"),
-        |path, is_dir| is_dir || !path.extension().is_some_and(|ext| ext == OsStr::new("html")),
+        |path, is_dir| is_dir || path.extension().is_none_or(|ext| ext != OsStr::new("html")),
         &mut |path: &DirEntry, file_content: &str| {
             let mut lines = file_content.lines().enumerate().peekable();
 
@@ -23,7 +23,7 @@ pub fn check(librustdoc_path: &Path, bad: &mut bool) {
                 if let Some(need_next_line_check) = TAGS.iter().find_map(|(tag, end_tag)| {
                     // We first check if the line ends with a jinja tag.
                     if !line.ends_with(end_tag) {
-                        return None;
+                        None
                     // Then we check if this a comment tag.
                     } else if *tag != "{#" {
                         return Some(false);
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 2237eac200d..8dde4618ce5 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -94,10 +94,9 @@ fn generate_problems<'a>(
     letter_digit: &'a FxHashMap<char, char>,
 ) -> impl Iterator<Item = u32> + 'a {
     consts.iter().flat_map(move |const_value| {
-        let problem =
-            letter_digit.iter().fold(format!("{:X}", const_value), |acc, (key, value)| {
-                acc.replace(&value.to_string(), &key.to_string())
-            });
+        let problem = letter_digit.iter().fold(format!("{const_value:X}"), |acc, (key, value)| {
+            acc.replace(&value.to_string(), &key.to_string())
+        });
         let indexes: Vec<usize> = problem
             .chars()
             .enumerate()
@@ -341,7 +340,7 @@ fn is_unexplained_ignore(extension: &str, line: &str) -> bool {
 
 pub fn check(path: &Path, bad: &mut bool) {
     fn skip(path: &Path, is_dir: bool) -> bool {
-        if path.file_name().map_or(false, |name| name.to_string_lossy().starts_with(".#")) {
+        if path.file_name().is_some_and(|name| name.to_string_lossy().starts_with(".#")) {
             // vim or emacs temporary file
             return true;
         }
@@ -358,12 +357,12 @@ pub fn check(path: &Path, bad: &mut bool) {
         let extensions = ["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "goml"];
 
         // NB: don't skip paths without extensions (or else we'll skip all directories and will only check top level files)
-        if path.extension().map_or(true, |ext| !extensions.iter().any(|e| ext == OsStr::new(e))) {
+        if path.extension().is_none_or(|ext| !extensions.iter().any(|e| ext == OsStr::new(e))) {
             return true;
         }
 
         // We only check CSS files in rustdoc.
-        path.extension().map_or(false, |e| e == "css") && !is_in(path, "src", "librustdoc")
+        path.extension().is_some_and(|e| e == "css") && !is_in(path, "src", "librustdoc")
     }
 
     // This creates a RegexSet as regex contains performance optimizations to be able to deal with these over
@@ -435,7 +434,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             mut skip_copyright,
             mut skip_dbg,
             mut skip_odd_backticks,
-        ] = contains_ignore_directives(&path_str, can_contain, &contents, CONFIGURABLE_CHECKS);
+        ] = contains_ignore_directives(&path_str, can_contain, contents, CONFIGURABLE_CHECKS);
         let mut leading_new_lines = false;
         let mut trailing_new_lines = 0;
         let mut lines = 0;
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index a66ccd37070..1a6fd3eaf2d 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -30,10 +30,9 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                         comp_vec.push(component);
                     }
                 }
-            } else if directive.starts_with(COMPILE_FLAGS_HEADER) {
-                let compile_flags = &directive[COMPILE_FLAGS_HEADER.len()..];
+            } else if let Some(compile_flags) = directive.strip_prefix(COMPILE_FLAGS_HEADER) {
                 if let Some((_, v)) = compile_flags.split_once("--target") {
-                    let v = v.trim_start_matches(|c| c == ' ' || c == '=');
+                    let v = v.trim_start_matches([' ', '=']);
                     let v = if v == "{{target}}" { Some((v, v)) } else { v.split_once("-") };
                     if let Some((arch, _)) = v {
                         let info = header_map.entry(revision).or_insert(RevisionInfo::default());
@@ -57,15 +56,13 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                 (None, None) => {}
                 (Some(_), None) => {
                     eprintln!(
-                        "{}: revision {} should specify `{}` as it has `--target` set",
-                        file, rev, LLVM_COMPONENTS_HEADER
+                        "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER}` as it has `--target` set"
                     );
                     *bad = true;
                 }
                 (None, Some(_)) => {
                     eprintln!(
-                        "{}: revision {} should not specify `{}` as it doesn't need `--target`",
-                        file, rev, LLVM_COMPONENTS_HEADER
+                        "{file}: revision {rev} should not specify `{LLVM_COMPONENTS_HEADER}` as it doesn't need `--target`"
                     );
                     *bad = true;
                 }
diff --git a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
index ee92d302db3..02412b6f190 100644
--- a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
+++ b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
@@ -38,7 +38,7 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
 
             let sibling_path = sibling.path();
 
-            let Some(ext) = sibling_path.extension().map(OsStr::to_str).flatten() else {
+            let Some(ext) = sibling_path.extension().and_then(OsStr::to_str) else {
                 continue;
             };
 
@@ -84,7 +84,7 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
                 }
             });
 
-            let Some(test_name) = test.file_stem().map(OsStr::to_str).flatten() else {
+            let Some(test_name) = test.file_stem().and_then(OsStr::to_str) else {
                 continue;
             };
 
@@ -102,9 +102,9 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
         // of the form: `test-name.revision.compare_mode.extension`, but our only concern is
         // `test-name.revision` and `extension`.
         for sibling in files_under_inspection.iter().filter(|f| {
-            f.extension().map(OsStr::to_str).flatten().is_some_and(|ext| EXTENSIONS.contains(&ext))
+            f.extension().and_then(OsStr::to_str).is_some_and(|ext| EXTENSIONS.contains(&ext))
         }) {
-            let Some(filename) = sibling.file_name().map(OsStr::to_str).flatten() else {
+            let Some(filename) = sibling.file_name().and_then(OsStr::to_str) else {
                 continue;
             };
 
@@ -131,10 +131,10 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
                 }
                 [_, _] => return,
                 [_, found_revision, .., extension] => {
-                    if !IGNORES.contains(&found_revision)
+                    if !IGNORES.contains(found_revision)
                         && !expected_revisions.contains(*found_revision)
                         // This is from `//@ stderr-per-bitwidth`
-                        && !(*extension == "stderr" && ["32bit", "64bit"].contains(&found_revision))
+                        && !(*extension == "stderr" && ["32bit", "64bit"].contains(found_revision))
                     {
                         // Found some unexpected revision-esque component that is not a known
                         // compare-mode or expected revision.
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 53226fcb80e..b1ace74e5bd 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -57,11 +57,9 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
 fn check_entries(tests_path: &Path, bad: &mut bool) {
     let mut directories: HashMap<PathBuf, u32> = HashMap::new();
 
-    for dir in Walk::new(&tests_path.join("ui")) {
-        if let Ok(entry) = dir {
-            let parent = entry.path().parent().unwrap().to_path_buf();
-            *directories.entry(parent).or_default() += 1;
-        }
+    for entry in Walk::new(tests_path.join("ui")).flatten() {
+        let parent = entry.path().parent().unwrap().to_path_buf();
+        *directories.entry(parent).or_default() += 1;
     }
 
     let (mut max, mut max_issues) = (0, 0);
@@ -99,7 +97,7 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
 "#;
 
     let path = &root_path.join("tests");
-    check_entries(&path, bad);
+    check_entries(path, bad);
 
     // the list of files in ui tests that are allowed to start with `issue-XXXX`
     // BTreeSet because we would like a stable ordering so --bless works
@@ -109,13 +107,12 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
         .strip_prefix(issues_txt_header)
         .unwrap()
         .lines()
-        .map(|line| {
+        .inspect(|&line| {
             if prev_line > line {
                 is_sorted = false;
             }
 
             prev_line = line;
-            line
         })
         .collect();
 
@@ -203,7 +200,7 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
         // so we don't bork things on panic or a contributor using Ctrl+C
         let blessed_issues_path = tidy_src.join("issues_blessed.txt");
         let mut blessed_issues_txt = fs::File::create(&blessed_issues_path).unwrap();
-        blessed_issues_txt.write(issues_txt_header.as_bytes()).unwrap();
+        blessed_issues_txt.write_all(issues_txt_header.as_bytes()).unwrap();
         // If we changed paths to use the OS separator, reassert Unix chauvinism for blessing.
         for filename in allowed_issue_names.difference(&remaining_issue_names) {
             writeln!(blessed_issues_txt, "{filename}").unwrap();
diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs
index a2453a6c960..9dc9d42d466 100644
--- a/src/tools/tidy/src/unstable_book.rs
+++ b/src/tools/tidy/src/unstable_book.rs
@@ -38,7 +38,7 @@ fn dir_entry_is_file(dir_entry: &fs::DirEntry) -> bool {
 pub fn collect_unstable_feature_names(features: &Features) -> BTreeSet<String> {
     features
         .iter()
-        .filter(|&(_, ref f)| f.level == Status::Unstable)
+        .filter(|&(_, f)| f.level == Status::Unstable)
         .map(|(name, _)| name.replace('_', "-"))
         .collect()
 }
@@ -90,7 +90,7 @@ pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) {
     let lib_features = features
         .lib
         .into_iter()
-        .filter(|&(ref name, _)| !lang_features.contains_key(name))
+        .filter(|(name, _)| !lang_features.contains_key(name))
         .collect::<Features>();
 
     // Library features
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index c2c9eb8d250..7825ebeb5ba 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -66,7 +66,7 @@ pub fn walk_many(
             Ok(s) => s,
             Err(_) => return, // skip this file
         };
-        f(&entry, &contents_str);
+        f(entry, contents_str);
     });
 }
 
@@ -83,7 +83,7 @@ pub(crate) fn walk_no_read(
         !skip(e.path(), e.file_type().map(|ft| ft.is_dir()).unwrap_or(false))
     });
     for entry in walker.build().flatten() {
-        if entry.file_type().map_or(true, |kind| kind.is_dir() || kind.is_symlink()) {
+        if entry.file_type().is_none_or(|kind| kind.is_dir() || kind.is_symlink()) {
             continue;
         }
         f(&entry);
diff --git a/src/tools/tidy/src/x_version.rs b/src/tools/tidy/src/x_version.rs
index 489343561e1..6a5e9eca813 100644
--- a/src/tools/tidy/src/x_version.rs
+++ b/src/tools/tidy/src/x_version.rs
@@ -26,7 +26,7 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
                     // Check this is the rust-lang/rust x tool installation since it should be
                     // installed at a path containing `src/tools/x`.
                     if let Some(path) = iter.next() {
-                        if path.contains(&"src/tools/x") {
+                        if path.contains("src/tools/x") {
                             let version = version.strip_prefix("v").unwrap();
                             installed = Some(Version::parse(version).unwrap());
                             break;
@@ -42,15 +42,15 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
 
         if let Some(expected) = get_x_wrapper_version(root, cargo) {
             if installed < expected {
-                return println!(
+                println!(
                     "Current version of x is {installed}, but the latest version is {expected}\nConsider updating to the newer version of x by running `cargo install --path src/tools/x`"
-                );
+                )
             }
         } else {
-            return tidy_error!(
+            tidy_error!(
                 bad,
                 "Unable to parse the latest version of `x` at `src/tools/x/Cargo.toml`"
-            );
+            )
         }
     } else {
         tidy_error!(bad, "failed to check version of `x`: {}", cargo_list.status)
diff --git a/src/tools/tier-check/Cargo.toml b/src/tools/tier-check/Cargo.toml
index 3f08165a3fc..a34f9447fab 100644
--- a/src/tools/tier-check/Cargo.toml
+++ b/src/tools/tier-check/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "tier-check"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 license = "MIT OR Apache-2.0"
 
 [dependencies]
diff --git a/src/tools/tier-check/src/main.rs b/src/tools/tier-check/src/main.rs
index 91b96117db0..6c27a2ec442 100644
--- a/src/tools/tier-check/src/main.rs
+++ b/src/tools/tier-check/src/main.rs
@@ -25,29 +25,27 @@ fn main() {
     let doc_targets: HashSet<_> = doc_targets_md
         .lines()
         .filter(|line| line.starts_with(&['`', '['][..]) && line.contains('|'))
-        .map(|line| line.split('`').skip(1).next().expect("expected target code span"))
+        .map(|line| line.split('`').nth(1).expect("expected target code span"))
         .collect();
 
     let missing: Vec<_> = target_list.difference(&doc_targets).collect();
     let extra: Vec<_> = doc_targets.difference(&target_list).collect();
     for target in &missing {
         eprintln!(
-            "error: target `{}` is missing from {}\n\
-            If this is a new target, please add it to {}.",
-            target, filename, src
+            "error: target `{target}` is missing from {filename}\n\
+            If this is a new target, please add it to {src}."
         );
     }
     for target in &extra {
         eprintln!(
-            "error: target `{}` is in {}, but does not appear in the rustc target list\n\
-            If the target has been removed, please edit {} and remove the target.",
-            target, filename, src
+            "error: target `{target}` is in {filename}, but does not appear in the rustc target list\n\
+            If the target has been removed, please edit {src} and remove the target."
         );
     }
     // Check target names for unwanted characters like `.` that can cause problems e.g. in Cargo.
     // See also Tier 3 target policy.
     // If desired, target names can ignore this check.
-    let ignore_target_names = vec![
+    let ignore_target_names = [
         "thumbv8m.base-none-eabi",
         "thumbv8m.main-none-eabi",
         "thumbv8m.main-none-eabihf",