Skip to content

Commit 192bb9c

Browse files
authored
Rollup merge of #148510 - Zalathar:known-directives, r=jieyouxu
compiletest: Do the known-directives check only once, and improve its error message This PR is a combination of three changes: - Store the list of known directives in a set, so that checking a directive name doesn't require a linear scan - Extract the known-directives check out of `iter_directives` and do it only once, instead of multiple times per file - Improve the error message for unknown directives, [as requested on Zulip](https://rust-lang.zulipchat.com/#narrow/channel/326414-t-infra.2Fbootstrap/topic/Compiletest.20directive.20parsing.20error/with/553598083) The change to error messages is fused with the extraction, since doing it independently would have been more awkward. --- ## Before ```text Testing stage1 with compiletest suite=coverage mode=coverage-map (aarch64-apple-darwin) errors encountered during EarlyProps parsing: /Users/stuart/Dev/rust/rust/tests/coverage/trivial.rs 2025-11-05T01:55:46.440012Z ERROR compiletest::directives: /Users/stuart/Dev/rust/rust/tests/coverage/trivial.rs:2: detected unknown compiletest test directive `add-core-stubs` thread '<unnamed>' (36268582) panicked at src/tools/compiletest/src/directives.rs:72:13: errors encountered during EarlyProps parsing note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` ## After ```text Testing stage1 with compiletest suite=coverage mode=coverage-map (aarch64-apple-darwin) thread '<unnamed>' (36270772) panicked at src/tools/compiletest/src/lib.rs:876:9: directives check failed: ERROR: unknown compiletest directive `add-core-stubs` at /Users/stuart/Dev/rust/rust/tests/coverage/trivial.rs:2 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ```
2 parents 5591d7e + 795e906 commit 192bb9c

File tree

4 files changed

+51
-61
lines changed

4 files changed

+51
-61
lines changed

src/tools/compiletest/src/directives.rs

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::debuggers::{extract_cdb_version, extract_gdb_version};
1111
pub(crate) use crate::directives::auxiliary::AuxProps;
1212
use crate::directives::auxiliary::parse_and_update_aux;
1313
use crate::directives::directive_names::{
14-
KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
14+
KNOWN_DIRECTIVE_NAMES_SET, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
1515
};
1616
pub(crate) use crate::directives::file::FileDirectives;
1717
use crate::directives::line::{DirectiveLine, line_directive};
@@ -53,25 +53,17 @@ impl EarlyProps {
5353
config: &Config,
5454
file_directives: &FileDirectives<'_>,
5555
) -> Self {
56-
let testfile = file_directives.path;
5756
let mut props = EarlyProps::default();
58-
let mut poisoned = false;
5957

6058
iter_directives(
6159
config.mode,
62-
&mut poisoned,
6360
file_directives,
6461
// (dummy comment to force args into vertical layout)
6562
&mut |ln: &DirectiveLine<'_>| {
6663
config.parse_and_update_revisions(ln, &mut props.revisions);
6764
},
6865
);
6966

70-
if poisoned {
71-
eprintln!("errors encountered during EarlyProps parsing: {}", testfile);
72-
panic!("errors encountered during EarlyProps parsing");
73-
}
74-
7567
props
7668
}
7769
}
@@ -358,12 +350,10 @@ impl TestProps {
358350
let file_contents = fs::read_to_string(testfile).unwrap();
359351
let file_directives = FileDirectives::from_file_contents(testfile, &file_contents);
360352

361-
let mut poisoned = false;
362-
363353
iter_directives(
364354
config.mode,
365-
&mut poisoned,
366355
&file_directives,
356+
// (dummy comment to force args into vertical layout)
367357
&mut |ln: &DirectiveLine<'_>| {
368358
if !ln.applies_to_test_revision(test_revision) {
369359
return;
@@ -634,11 +624,6 @@ impl TestProps {
634624
);
635625
},
636626
);
637-
638-
if poisoned {
639-
eprintln!("errors encountered during TestProps parsing: {}", testfile);
640-
panic!("errors encountered during TestProps parsing");
641-
}
642627
}
643628

644629
if self.should_ice {
@@ -775,6 +760,34 @@ impl TestProps {
775760
}
776761
}
777762

763+
pub(crate) fn do_early_directives_check(
764+
mode: TestMode,
765+
file_directives: &FileDirectives<'_>,
766+
) -> Result<(), String> {
767+
let testfile = file_directives.path;
768+
769+
for directive_line @ DirectiveLine { line_number, .. } in &file_directives.lines {
770+
let CheckDirectiveResult { is_known_directive, trailing_directive } =
771+
check_directive(directive_line, mode);
772+
773+
if !is_known_directive {
774+
return Err(format!(
775+
"ERROR: unknown compiletest directive `{directive}` at {testfile}:{line_number}",
776+
directive = directive_line.display(),
777+
));
778+
}
779+
780+
if let Some(trailing_directive) = &trailing_directive {
781+
return Err(format!(
782+
"ERROR: detected trailing compiletest directive `{trailing_directive}` at {testfile}:{line_number}\n\
783+
HELP: put the directive on its own line: `//@ {trailing_directive}`"
784+
));
785+
}
786+
}
787+
788+
Ok(())
789+
}
790+
778791
pub(crate) struct CheckDirectiveResult<'ln> {
779792
is_known_directive: bool,
780793
trailing_directive: Option<&'ln str>,
@@ -786,7 +799,7 @@ fn check_directive<'a>(
786799
) -> CheckDirectiveResult<'a> {
787800
let &DirectiveLine { name: directive_name, .. } = directive_ln;
788801

789-
let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name)
802+
let is_known_directive = KNOWN_DIRECTIVE_NAMES_SET.contains(&directive_name)
790803
|| match mode {
791804
TestMode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES.contains(&directive_name),
792805
TestMode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES.contains(&directive_name),
@@ -799,7 +812,7 @@ fn check_directive<'a>(
799812
let trailing_directive = directive_ln
800813
.remark_after_space()
801814
.map(|remark| remark.trim_start().split(' ').next().unwrap())
802-
.filter(|token| KNOWN_DIRECTIVE_NAMES.contains(token));
815+
.filter(|token| KNOWN_DIRECTIVE_NAMES_SET.contains(token));
803816

804817
// FIXME(Zalathar): Consider emitting specialized error/help messages for
805818
// bogus directive names that are similar to real ones, e.g.:
@@ -811,7 +824,6 @@ fn check_directive<'a>(
811824

812825
fn iter_directives(
813826
mode: TestMode,
814-
poisoned: &mut bool,
815827
file_directives: &FileDirectives<'_>,
816828
it: &mut dyn FnMut(&DirectiveLine<'_>),
817829
) {
@@ -837,36 +849,7 @@ fn iter_directives(
837849
}
838850
}
839851

840-
for directive_line @ &DirectiveLine { line_number, .. } in &file_directives.lines {
841-
// Perform unknown directive check on Rust files.
842-
if testfile.extension() == Some("rs") {
843-
let CheckDirectiveResult { is_known_directive, trailing_directive } =
844-
check_directive(directive_line, mode);
845-
846-
if !is_known_directive {
847-
*poisoned = true;
848-
849-
error!(
850-
"{testfile}:{line_number}: detected unknown compiletest test directive `{}`",
851-
directive_line.display(),
852-
);
853-
854-
return;
855-
}
856-
857-
if let Some(trailing_directive) = &trailing_directive {
858-
*poisoned = true;
859-
860-
error!(
861-
"{testfile}:{line_number}: detected trailing compiletest test directive `{}`",
862-
trailing_directive,
863-
);
864-
help!("put the trailing directive in its own line: `//@ {}`", trailing_directive);
865-
866-
return;
867-
}
868-
}
869-
852+
for directive_line in &file_directives.lines {
870853
it(directive_line);
871854
}
872855
}
@@ -1304,12 +1287,9 @@ pub(crate) fn make_test_description(
13041287
let mut ignore_message = None;
13051288
let mut should_fail = false;
13061289

1307-
let mut local_poisoned = false;
1308-
13091290
// Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives.
13101291
iter_directives(
13111292
config.mode,
1312-
&mut local_poisoned,
13131293
file_directives,
13141294
&mut |ln @ &DirectiveLine { line_number, .. }| {
13151295
if !ln.applies_to_test_revision(test_revision) {
@@ -1358,11 +1338,6 @@ pub(crate) fn make_test_description(
13581338
},
13591339
);
13601340

1361-
if local_poisoned {
1362-
eprintln!("errors encountered when trying to make test description: {}", path);
1363-
panic!("errors encountered when trying to make test description");
1364-
}
1365-
13661341
// The `should-fail` annotation doesn't apply to pretty tests,
13671342
// since we run the pretty printer across all tests by default.
13681343
// If desired, we could add a `should-fail-pretty` annotation.

src/tools/compiletest/src/directives/directive_names.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
use std::collections::HashSet;
2+
use std::sync::LazyLock;
3+
4+
pub(crate) static KNOWN_DIRECTIVE_NAMES_SET: LazyLock<HashSet<&str>> =
5+
LazyLock::new(|| KNOWN_DIRECTIVE_NAMES.iter().copied().collect());
6+
17
/// This was originally generated by collecting directives from ui tests and then extracting their
28
/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
39
/// a best-effort approximation for diagnostics. Add new directives to this list when needed.

src/tools/compiletest/src/directives/tests.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use semver::Version;
33

44
use crate::common::{Config, Debugger, TestMode};
55
use crate::directives::{
6-
AuxProps, DirectivesCache, EarlyProps, Edition, EditionRange, FileDirectives,
7-
extract_llvm_version, extract_version_range, iter_directives, line_directive, parse_edition,
6+
self, AuxProps, DirectivesCache, EarlyProps, Edition, EditionRange, FileDirectives,
7+
extract_llvm_version, extract_version_range, line_directive, parse_edition,
88
parse_normalize_rule,
99
};
1010
use crate::executor::{CollectedTestDesc, ShouldFail};
@@ -767,7 +767,10 @@ fn threads_support() {
767767

768768
fn run_path(poisoned: &mut bool, path: &Utf8Path, file_contents: &str) {
769769
let file_directives = FileDirectives::from_file_contents(path, file_contents);
770-
iter_directives(TestMode::Ui, poisoned, &file_directives, &mut |_| {});
770+
let result = directives::do_early_directives_check(TestMode::Ui, &file_directives);
771+
if result.is_err() {
772+
*poisoned = true;
773+
}
771774
}
772775

773776
#[test]

src/tools/compiletest/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,12 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
869869
let file_contents =
870870
fs::read_to_string(&test_path).expect("reading test file for directives should succeed");
871871
let file_directives = FileDirectives::from_file_contents(&test_path, &file_contents);
872+
873+
if let Err(message) = directives::do_early_directives_check(cx.config.mode, &file_directives) {
874+
// FIXME(Zalathar): Overhaul compiletest error handling so that we
875+
// don't have to resort to ad-hoc panics everywhere.
876+
panic!("directives check failed:\n{message}");
877+
}
872878
let early_props = EarlyProps::from_file_directives(&cx.config, &file_directives);
873879

874880
// Normally we create one structure per revision, with two exceptions:

0 commit comments

Comments
 (0)