diff options
| author | Daniel Paoliello <danpao@microsoft.com> | 2025-07-16 16:16:24 -0700 |
|---|---|---|
| committer | Daniel Paoliello <danpao@microsoft.com> | 2025-07-29 11:20:23 -0700 |
| commit | cffde732ceecd1bcb333d34fe7a9c9caa4d9a9fa (patch) | |
| tree | b1f3a5851136a0b5de7cbb23e25fa5f6f9936433 /src | |
| parent | 7278554d82fa474a4e8b5c67afb009e11e41a841 (diff) | |
| download | rust-cffde732ceecd1bcb333d34fe7a9c9caa4d9a9fa.tar.gz rust-cffde732ceecd1bcb333d34fe7a9c9caa4d9a9fa.zip | |
Verify llvm-needs-components are not empty and match the --target value
Diffstat (limited to 'src')
| -rw-r--r-- | src/doc/rustc-dev-guide/src/tests/directives.md | 13 | ||||
| -rw-r--r-- | src/tools/compiletest/src/directives.rs | 184 | ||||
| -rw-r--r-- | src/tools/compiletest/src/directives/auxiliary.rs | 41 | ||||
| -rw-r--r-- | src/tools/compiletest/src/runtest/debugger.rs | 8 | ||||
| -rw-r--r-- | src/tools/tidy/src/style.rs | 7 | ||||
| -rw-r--r-- | src/tools/tidy/src/target_specific_tests.rs | 61 |
6 files changed, 248 insertions, 66 deletions
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 5c3ae359ba0..89e4d3e9b58 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -293,8 +293,6 @@ See [Pretty-printer](compiletest.md#pretty-printer-tests). - `no-auto-check-cfg` — disable auto check-cfg (only for `--check-cfg` tests) - [`revisions`](compiletest.md#revisions) — compile multiple times -- [`unused-revision-names`](compiletest.md#ignoring-unused-revision-names) - - suppress tidy checks for mentioning unknown revision names -[`forbid-output`](compiletest.md#incremental-tests) — incremental cfail rejects output pattern - [`should-ice`](compiletest.md#incremental-tests) — incremental cfail should @@ -315,6 +313,17 @@ test suites that use those tools: - `llvm-cov-flags` adds extra flags when running LLVM's `llvm-cov` tool. - Used by [coverage tests](compiletest.md#coverage-tests) in `coverage-run` mode. +### Tidy specific directives + +The following directives control how the [tidy script](../conventions.md#formatting) +verifies tests. + +- `ignore-tidy-target-specific-tests` disables checking that the appropriate + LLVM component is required (via a `needs-llvm-components` directive) when a + test is compiled for a specific target (via the `--target` flag in a + `compile-flag` directive). +- [`unused-revision-names`](compiletest.md#ignoring-unused-revision-names) - + suppress tidy checks for mentioning unknown revision names. ## Substitutions diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index a1f76a07556..69ff846330e 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -59,9 +59,9 @@ impl EarlyProps { &mut poisoned, testfile, rdr, - &mut |DirectiveLine { raw_directive: ln, .. }| { - parse_and_update_aux(config, ln, &mut props.aux); - config.parse_and_update_revisions(testfile, ln, &mut props.revisions); + &mut |DirectiveLine { line_number, raw_directive: ln, .. }| { + parse_and_update_aux(config, ln, testfile, line_number, &mut props.aux); + config.parse_and_update_revisions(testfile, line_number, ln, &mut props.revisions); }, ); @@ -351,7 +351,7 @@ impl TestProps { &mut poisoned, testfile, file, - &mut |directive @ DirectiveLine { raw_directive: ln, .. }| { + &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| { if !directive.applies_to_test_revision(test_revision) { return; } @@ -361,17 +361,28 @@ impl TestProps { config.push_name_value_directive( ln, ERROR_PATTERN, + testfile, + line_number, &mut self.error_patterns, |r| r, ); config.push_name_value_directive( ln, REGEX_ERROR_PATTERN, + testfile, + line_number, &mut self.regex_error_patterns, |r| r, ); - config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r); + config.push_name_value_directive( + ln, + DOC_FLAGS, + testfile, + line_number, + &mut self.doc_flags, + |r| r, + ); fn split_flags(flags: &str) -> Vec<String> { // Individual flags can be single-quoted to preserve spaces; see @@ -386,7 +397,9 @@ impl TestProps { .collect::<Vec<_>>() } - if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { + if let Some(flags) = + config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile, line_number) + { let flags = split_flags(&flags); for flag in &flags { if flag == "--edition" || flag.starts_with("--edition=") { @@ -395,25 +408,40 @@ impl TestProps { } self.compile_flags.extend(flags); } - if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() { + if config + .parse_name_value_directive( + ln, + INCORRECT_COMPILER_FLAGS, + testfile, + line_number, + ) + .is_some() + { panic!("`compiler-flags` directive should be spelled `compile-flags`"); } - if let Some(edition) = config.parse_edition(ln) { + if let Some(edition) = config.parse_edition(ln, testfile, line_number) { // The edition is added at the start, since flags from //@compile-flags must // be passed to rustc last. self.compile_flags.insert(0, format!("--edition={}", edition.trim())); has_edition = true; } - config.parse_and_update_revisions(testfile, ln, &mut self.revisions); + config.parse_and_update_revisions( + testfile, + line_number, + ln, + &mut self.revisions, + ); - if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS) { + if let Some(flags) = + config.parse_name_value_directive(ln, RUN_FLAGS, testfile, line_number) + { self.run_flags.extend(split_flags(&flags)); } if self.pp_exact.is_none() { - self.pp_exact = config.parse_pp_exact(ln, testfile); + self.pp_exact = config.parse_pp_exact(ln, testfile, line_number); } config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice); @@ -435,7 +463,9 @@ impl TestProps { ); config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic); - if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) { + if let Some(m) = + config.parse_name_value_directive(ln, PRETTY_MODE, testfile, line_number) + { self.pretty_mode = m; } @@ -446,35 +476,45 @@ impl TestProps { ); // Call a helper method to deal with aux-related directives. - parse_and_update_aux(config, ln, &mut self.aux); + parse_and_update_aux(config, ln, testfile, line_number, &mut self.aux); config.push_name_value_directive( ln, EXEC_ENV, + testfile, + line_number, &mut self.exec_env, Config::parse_env, ); config.push_name_value_directive( ln, UNSET_EXEC_ENV, + testfile, + line_number, &mut self.unset_exec_env, |r| r.trim().to_owned(), ); config.push_name_value_directive( ln, RUSTC_ENV, + testfile, + line_number, &mut self.rustc_env, Config::parse_env, ); config.push_name_value_directive( ln, UNSET_RUSTC_ENV, + testfile, + line_number, &mut self.unset_rustc_env, |r| r.trim().to_owned(), ); config.push_name_value_directive( ln, FORBID_OUTPUT, + testfile, + line_number, &mut self.forbid_output, |r| r, ); @@ -510,7 +550,7 @@ impl TestProps { } if let Some(code) = config - .parse_name_value_directive(ln, FAILURE_STATUS) + .parse_name_value_directive(ln, FAILURE_STATUS, testfile, line_number) .and_then(|code| code.trim().parse::<i32>().ok()) { self.failure_status = Some(code); @@ -531,6 +571,8 @@ impl TestProps { config.set_name_value_directive( ln, ASSEMBLY_OUTPUT, + testfile, + line_number, &mut self.assembly_output, |r| r.trim().to_string(), ); @@ -543,7 +585,9 @@ impl TestProps { // Unlike the other `name_value_directive`s this needs to be handled manually, // because it sets a `bool` flag. - if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) { + if let Some(known_bug) = + config.parse_name_value_directive(ln, KNOWN_BUG, testfile, line_number) + { let known_bug = known_bug.trim(); if known_bug == "unknown" || known_bug.split(',').all(|issue_ref| { @@ -571,16 +615,25 @@ impl TestProps { config.set_name_value_directive( ln, TEST_MIR_PASS, + testfile, + line_number, &mut self.mir_unit_test, |s| s.trim().to_string(), ); config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base); - if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) { + if let Some(flags) = + config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile, line_number) + { self.llvm_cov_flags.extend(split_flags(&flags)); } - if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) { + if let Some(flags) = config.parse_name_value_directive( + ln, + FILECHECK_FLAGS, + testfile, + line_number, + ) { self.filecheck_flags.extend(split_flags(&flags)); } @@ -588,9 +641,12 @@ impl TestProps { self.update_add_core_stubs(ln, config); - if let Some(err_kind) = - config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) - { + if let Some(err_kind) = config.parse_name_value_directive( + ln, + DONT_REQUIRE_ANNOTATIONS, + testfile, + line_number, + ) { self.dont_require_annotations .insert(ErrorKind::expect_from_user_str(err_kind.trim())); } @@ -1206,6 +1262,7 @@ impl Config { fn parse_and_update_revisions( &self, testfile: &Utf8Path, + line_number: usize, line: &str, existing: &mut Vec<String>, ) { @@ -1219,7 +1276,8 @@ impl Config { const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] = ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"]; - if let Some(raw) = self.parse_name_value_directive(line, "revisions") { + if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number) + { if self.mode == TestMode::RunMake { panic!("`run-make` tests do not support revisions: {}", testfile); } @@ -1264,8 +1322,13 @@ impl Config { (name.to_owned(), value.to_owned()) } - fn parse_pp_exact(&self, line: &str, testfile: &Utf8Path) -> Option<Utf8PathBuf> { - if let Some(s) = self.parse_name_value_directive(line, "pp-exact") { + fn parse_pp_exact( + &self, + line: &str, + testfile: &Utf8Path, + line_number: usize, + ) -> Option<Utf8PathBuf> { + if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile, line_number) { Some(Utf8PathBuf::from(&s)) } else if self.parse_name_directive(line, "pp-exact") { testfile.file_name().map(Utf8PathBuf::from) @@ -1306,19 +1369,31 @@ impl Config { line.starts_with("no-") && self.parse_name_directive(&line[3..], directive) } - pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option<String> { + pub fn parse_name_value_directive( + &self, + line: &str, + directive: &str, + testfile: &Utf8Path, + line_number: usize, + ) -> Option<String> { let colon = directive.len(); if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') { let value = line[(colon + 1)..].to_owned(); debug!("{}: {}", directive, value); - Some(expand_variables(value, self)) + let value = expand_variables(value, self); + if value.is_empty() { + error!("{testfile}:{line_number}: empty value for directive `{directive}`"); + help!("expected syntax is: `{directive}: value`"); + panic!("empty directive value detected"); + } + Some(value) } else { None } } - fn parse_edition(&self, line: &str) -> Option<String> { - self.parse_name_value_directive(line, "edition") + fn parse_edition(&self, line: &str, testfile: &Utf8Path, line_number: usize) -> Option<String> { + self.parse_name_value_directive(line, "edition", testfile, line_number) } fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) { @@ -1340,11 +1415,14 @@ impl Config { &self, line: &str, directive: &str, + testfile: &Utf8Path, + line_number: usize, value: &mut Option<T>, parse: impl FnOnce(String) -> T, ) { if value.is_none() { - *value = self.parse_name_value_directive(line, directive).map(parse); + *value = + self.parse_name_value_directive(line, directive, testfile, line_number).map(parse); } } @@ -1352,10 +1430,14 @@ impl Config { &self, line: &str, directive: &str, + testfile: &Utf8Path, + line_number: usize, values: &mut Vec<T>, parse: impl FnOnce(String) -> T, ) { - if let Some(value) = self.parse_name_value_directive(line, directive).map(parse) { + if let Some(value) = + self.parse_name_value_directive(line, directive, testfile, line_number).map(parse) + { values.push(value); } } @@ -1672,9 +1754,9 @@ pub(crate) fn make_test_description<R: Read>( decision!(cfg::handle_ignore(config, ln)); decision!(cfg::handle_only(config, ln)); decision!(needs::handle_needs(&cache.needs, config, ln)); - decision!(ignore_llvm(config, path, ln)); - decision!(ignore_backends(config, path, ln)); - decision!(needs_backends(config, path, ln)); + decision!(ignore_llvm(config, path, ln, line_number)); + decision!(ignore_backends(config, path, ln, line_number)); + decision!(needs_backends(config, path, ln, line_number)); decision!(ignore_cdb(config, ln)); decision!(ignore_gdb(config, ln)); decision!(ignore_lldb(config, ln)); @@ -1801,8 +1883,15 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { IgnoreDecision::Continue } -fn ignore_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { - if let Some(backends_to_ignore) = config.parse_name_value_directive(line, "ignore-backends") { +fn ignore_backends( + config: &Config, + path: &Utf8Path, + line: &str, + line_number: usize, +) -> IgnoreDecision { + if let Some(backends_to_ignore) = + config.parse_name_value_directive(line, "ignore-backends", path, line_number) + { for backend in backends_to_ignore.split_whitespace().map(|backend| { match CodegenBackend::try_from(backend) { Ok(backend) => backend, @@ -1821,8 +1910,15 @@ fn ignore_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecisi IgnoreDecision::Continue } -fn needs_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { - if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends") { +fn needs_backends( + config: &Config, + path: &Utf8Path, + line: &str, + line_number: usize, +) -> IgnoreDecision { + if let Some(needed_backends) = + config.parse_name_value_directive(line, "needs-backends", path, line_number) + { if !needed_backends .split_whitespace() .map(|backend| match CodegenBackend::try_from(backend) { @@ -1844,9 +1940,9 @@ fn needs_backends(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecisio IgnoreDecision::Continue } -fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { +fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) -> IgnoreDecision { if let Some(needed_components) = - config.parse_name_value_directive(line, "needs-llvm-components") + config.parse_name_value_directive(line, "needs-llvm-components", path, line_number) { let components: HashSet<_> = config.llvm_components.split_whitespace().collect(); if let Some(missing_component) = needed_components @@ -1867,7 +1963,9 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { if let Some(actual_version) = &config.llvm_version { // Note that these `min` versions will check for not just major versions. - if let Some(version_string) = config.parse_name_value_directive(line, "min-llvm-version") { + if let Some(version_string) = + config.parse_name_value_directive(line, "min-llvm-version", path, line_number) + { let min_version = extract_llvm_version(&version_string); // Ignore if actual version is smaller than the minimum required version. if *actual_version < min_version { @@ -1878,7 +1976,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { }; } } else if let Some(version_string) = - config.parse_name_value_directive(line, "max-llvm-major-version") + config.parse_name_value_directive(line, "max-llvm-major-version", path, line_number) { let max_version = extract_llvm_version(&version_string); // Ignore if actual major version is larger than the maximum required major version. @@ -1892,7 +1990,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { }; } } else if let Some(version_string) = - config.parse_name_value_directive(line, "min-system-llvm-version") + config.parse_name_value_directive(line, "min-system-llvm-version", path, line_number) { let min_version = extract_llvm_version(&version_string); // Ignore if using system LLVM and actual version @@ -1905,7 +2003,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { }; } } else if let Some(version_range) = - config.parse_name_value_directive(line, "ignore-llvm-version") + config.parse_name_value_directive(line, "ignore-llvm-version", path, line_number) { // Syntax is: "ignore-llvm-version: <version1> [- <version2>]" let (v_min, v_max) = @@ -1931,7 +2029,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision { } } } else if let Some(version_string) = - config.parse_name_value_directive(line, "exact-llvm-major-version") + config.parse_name_value_directive(line, "exact-llvm-major-version", path, line_number) { // Syntax is "exact-llvm-major-version: <version>" let version = extract_llvm_version(&version_string); diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index cdb75f6ffa9..7c1ed2e7006 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -3,6 +3,8 @@ use std::iter; +use camino::Utf8Path; + use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO}; use crate::common::Config; @@ -41,17 +43,42 @@ impl AuxProps { /// If the given test directive line contains an `aux-*` directive, parse it /// and update [`AuxProps`] accordingly. -pub(super) fn parse_and_update_aux(config: &Config, ln: &str, aux: &mut AuxProps) { +pub(super) fn parse_and_update_aux( + config: &Config, + ln: &str, + testfile: &Utf8Path, + line_number: usize, + aux: &mut AuxProps, +) { if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) { return; } - config.push_name_value_directive(ln, AUX_BUILD, &mut aux.builds, |r| r.trim().to_string()); - config.push_name_value_directive(ln, AUX_BIN, &mut aux.bins, |r| r.trim().to_string()); - config.push_name_value_directive(ln, AUX_CRATE, &mut aux.crates, parse_aux_crate); - config - .push_name_value_directive(ln, PROC_MACRO, &mut aux.proc_macros, |r| r.trim().to_string()); - if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) { + config.push_name_value_directive(ln, AUX_BUILD, testfile, line_number, &mut aux.builds, |r| { + r.trim().to_string() + }); + config.push_name_value_directive(ln, AUX_BIN, testfile, line_number, &mut aux.bins, |r| { + r.trim().to_string() + }); + config.push_name_value_directive( + ln, + AUX_CRATE, + testfile, + line_number, + &mut aux.crates, + parse_aux_crate, + ); + config.push_name_value_directive( + ln, + PROC_MACRO, + testfile, + line_number, + &mut aux.proc_macros, + |r| r.trim().to_string(), + ); + if let Some(r) = + config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile, line_number) + { aux.codegen_backend = Some(r.trim().to_owned()); } } diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index a4103c5b4a9..ba824124e87 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -47,10 +47,14 @@ impl DebuggerCommands { continue; }; - if let Some(command) = config.parse_name_value_directive(&line, &command_directive) { + if let Some(command) = + config.parse_name_value_directive(&line, &command_directive, file, line_no) + { commands.push(command); } - if let Some(pattern) = config.parse_name_value_directive(&line, &check_directive) { + if let Some(pattern) = + config.parse_name_value_directive(&line, &check_directive, file, line_no) + { check_lines.push((line_no, pattern)); } } 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(), + } +} |
