about summary refs log tree commit diff
path: root/src/tools/tidy
diff options
context:
space:
mode:
authorDaniel Paoliello <danpao@microsoft.com>2025-07-16 16:16:24 -0700
committerDaniel Paoliello <danpao@microsoft.com>2025-07-29 11:20:23 -0700
commitcffde732ceecd1bcb333d34fe7a9c9caa4d9a9fa (patch)
treeb1f3a5851136a0b5de7cbb23e25fa5f6f9936433 /src/tools/tidy
parent7278554d82fa474a4e8b5c67afb009e11e41a841 (diff)
downloadrust-cffde732ceecd1bcb333d34fe7a9c9caa4d9a9fa.tar.gz
rust-cffde732ceecd1bcb333d34fe7a9c9caa4d9a9fa.zip
Verify llvm-needs-components are not empty and match the --target value
Diffstat (limited to 'src/tools/tidy')
-rw-r--r--src/tools/tidy/src/style.rs7
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs61
2 files changed, 56 insertions, 12 deletions
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 35ed61eacc7..fca097c091b 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -519,8 +519,11 @@ pub fn check(path: &Path, bad: &mut bool) {
                         .any(|directive| matches!(directive, Directive::Ignore(_)));
                 let has_alphabetical_directive = line.contains("tidy-alphabetical-start")
                     || line.contains("tidy-alphabetical-end");
-                let has_recognized_directive =
-                    has_recognized_ignore_directive || has_alphabetical_directive;
+                let has_other_tidy_ignore_directive =
+                    line.contains("ignore-tidy-target-specific-tests");
+                let has_recognized_directive = has_recognized_ignore_directive
+                    || has_alphabetical_directive
+                    || has_other_tidy_ignore_directive;
                 if contains_potential_directive && (!has_recognized_directive) {
                     err("Unrecognized tidy directive")
                 }
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index f4a6783abb6..b2d5f259eb2 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -12,12 +12,16 @@ const COMPILE_FLAGS_HEADER: &str = "compile-flags:";
 
 #[derive(Default, Debug)]
 struct RevisionInfo<'a> {
-    target_arch: Option<&'a str>,
+    target_arch: Option<Option<&'a str>>,
     llvm_components: Option<Vec<&'a str>>,
 }
 
 pub fn check(tests_path: &Path, bad: &mut bool) {
     crate::walk::walk(tests_path, |path, _is_dir| filter_not_rust(path), &mut |entry, content| {
+        if content.contains("// ignore-tidy-target-specific-tests") {
+            return;
+        }
+
         let file = entry.path().display();
         let mut header_map = BTreeMap::new();
         iter_header(content, &mut |HeaderLine { revision, directive, .. }| {
@@ -34,10 +38,11 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                 && let Some((_, v)) = compile_flags.split_once("--target")
             {
                 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());
-                    info.target_arch.replace(arch);
+                let info = header_map.entry(revision).or_insert(RevisionInfo::default());
+                if v.starts_with("{{") {
+                    info.target_arch.replace(None);
+                } else if let Some((arch, _)) = v.split_once("-") {
+                    info.target_arch.replace(Some(arch));
                 } else {
                     eprintln!("{file}: seems to have a malformed --target value");
                     *bad = true;
@@ -54,9 +59,11 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
             let rev = rev.unwrap_or("[unspecified]");
             match (target_arch, llvm_components) {
                 (None, None) => {}
-                (Some(_), None) => {
+                (Some(target_arch), None) => {
+                    let llvm_component =
+                        target_arch.map_or_else(|| "<arch>".to_string(), arch_to_llvm_component);
                     eprintln!(
-                        "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER}` as it has `--target` set"
+                        "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER} {llvm_component}` as it has `--target` set"
                     );
                     *bad = true;
                 }
@@ -66,11 +73,45 @@ pub fn check(tests_path: &Path, bad: &mut bool) {
                     );
                     *bad = true;
                 }
-                (Some(_), Some(_)) => {
-                    // FIXME: check specified components against the target architectures we
-                    // gathered.
+                (Some(target_arch), Some(llvm_components)) => {
+                    if let Some(target_arch) = target_arch {
+                        let llvm_component = arch_to_llvm_component(target_arch);
+                        if !llvm_components.contains(&llvm_component.as_str()) {
+                            eprintln!(
+                                "{file}: revision {rev} should specify `{LLVM_COMPONENTS_HEADER} {llvm_component}` as it has `--target` set"
+                            );
+                            *bad = true;
+                        }
+                    }
                 }
             }
         }
     });
 }
+
+fn arch_to_llvm_component(arch: &str) -> String {
+    // NOTE: This is an *approximate* mapping of Rust's `--target` architecture to LLVM component
+    // names. It is not intended to be an authoritative source, but rather a best-effort that's good
+    // enough for the purpose of this tidy check.
+    match arch {
+        "amdgcn" => "amdgpu".into(),
+        "aarch64_be" | "arm64_32" | "arm64e" | "arm64ec" => "aarch64".into(),
+        "i386" | "i586" | "i686" | "x86" | "x86_64" | "x86_64h" => "x86".into(),
+        "loongarch32" | "loongarch64" => "loongarch".into(),
+        "nvptx64" => "nvptx".into(),
+        "s390x" => "systemz".into(),
+        "sparc64" | "sparcv9" => "sparc".into(),
+        "wasm32" | "wasm32v1" | "wasm64" => "webassembly".into(),
+        _ if arch.starts_with("armeb")
+            || arch.starts_with("armv")
+            || arch.starts_with("thumbv") =>
+        {
+            "arm".into()
+        }
+        _ if arch.starts_with("bpfe") => "bpf".into(),
+        _ if arch.starts_with("mips") => "mips".into(),
+        _ if arch.starts_with("powerpc") => "powerpc".into(),
+        _ if arch.starts_with("riscv") => "riscv".into(),
+        _ => arch.to_ascii_lowercase(),
+    }
+}