Skip to content

Commit 722f01c

Browse files
authored
Unrolled build for #147522
Rollup merge of #147522 - Zalathar:directive, r=jieyouxu compiletest: Use the same directive lines for EarlyProps and ignore/only/needs Currently we load each discovered test file to scan it for directives once for EarlyProps parsing, then reload and scan it once *per revision* for ignore processing. If a revision is not ignored, we then reload and scan it again during actual execution. That's a bit silly, so this PR tries to reduce the number of unnecessary file loads and line scans for directive parsing, by reusing the same collection of `DirectiveLine` values for EarlyProps and for each revision's ignores. Each individual directive still needs to be re-parsed a bunch of times, but those steps can at least avoid scanning the whole file, or having to split out names from values. --- There's more that could be done after this, such as only doing known-directive checks once per file, or embedding file paths in each `DirectiveLine`, but I decided to stop here to allow review in modest chunks. r? jieyouxu
2 parents b3f8586 + f3f8385 commit 722f01c

File tree

4 files changed

+62
-43
lines changed

4 files changed

+62
-43
lines changed

src/tools/compiletest/src/directives.rs

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
1212
use crate::directives::directive_names::{
1313
KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
1414
};
15+
pub(crate) use crate::directives::file::FileDirectives;
1516
use crate::directives::line::{DirectiveLine, line_directive};
1617
use crate::directives::needs::CachedNeedsConditions;
1718
use crate::edition::{Edition, parse_edition};
@@ -23,6 +24,7 @@ use crate::{fatal, help};
2324
pub(crate) mod auxiliary;
2425
mod cfg;
2526
mod directive_names;
27+
mod file;
2628
mod line;
2729
mod needs;
2830
#[cfg(test)]
@@ -41,31 +43,29 @@ impl DirectivesCache {
4143
/// Properties which must be known very early, before actually running
4244
/// the test.
4345
#[derive(Default)]
44-
pub struct EarlyProps {
46+
pub(crate) struct EarlyProps {
4547
/// Auxiliary crates that should be built and made available to this test.
4648
/// Included in [`EarlyProps`] so that the indicated files can participate
4749
/// in up-to-date checking. Building happens via [`TestProps::aux`] instead.
4850
pub(crate) aux: AuxProps,
49-
pub revisions: Vec<String>,
51+
pub(crate) revisions: Vec<String>,
5052
}
5153

5254
impl EarlyProps {
53-
pub fn from_file(config: &Config, testfile: &Utf8Path) -> Self {
54-
let file_contents =
55-
fs::read_to_string(testfile).expect("read test file to parse earlyprops");
56-
Self::from_file_contents(config, testfile, &file_contents)
57-
}
58-
59-
pub fn from_file_contents(config: &Config, testfile: &Utf8Path, file_contents: &str) -> Self {
55+
pub(crate) fn from_file_directives(
56+
config: &Config,
57+
file_directives: &FileDirectives<'_>,
58+
) -> Self {
59+
let testfile = file_directives.path;
6060
let mut props = EarlyProps::default();
6161
let mut poisoned = false;
62+
6263
iter_directives(
6364
config.mode,
6465
&mut poisoned,
65-
testfile,
66-
file_contents,
66+
file_directives,
6767
// (dummy comment to force args into vertical layout)
68-
&mut |ref ln: DirectiveLine<'_>| {
68+
&mut |ln: &DirectiveLine<'_>| {
6969
parse_and_update_aux(config, ln, testfile, &mut props.aux);
7070
config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
7171
},
@@ -358,15 +358,15 @@ impl TestProps {
358358
let mut has_edition = false;
359359
if !testfile.is_dir() {
360360
let file_contents = fs::read_to_string(testfile).unwrap();
361+
let file_directives = FileDirectives::from_file_contents(testfile, &file_contents);
361362

362363
let mut poisoned = false;
363364

364365
iter_directives(
365366
config.mode,
366367
&mut poisoned,
367-
testfile,
368-
&file_contents,
369-
&mut |ref ln: DirectiveLine<'_>| {
368+
&file_directives,
369+
&mut |ln: &DirectiveLine<'_>| {
370370
if !ln.applies_to_test_revision(test_revision) {
371371
return;
372372
}
@@ -851,13 +851,10 @@ fn check_directive<'a>(
851851
fn iter_directives(
852852
mode: TestMode,
853853
poisoned: &mut bool,
854-
testfile: &Utf8Path,
855-
file_contents: &str,
856-
it: &mut dyn FnMut(DirectiveLine<'_>),
854+
file_directives: &FileDirectives<'_>,
855+
it: &mut dyn FnMut(&DirectiveLine<'_>),
857856
) {
858-
if testfile.is_dir() {
859-
return;
860-
}
857+
let testfile = file_directives.path;
861858

862859
// Coverage tests in coverage-run mode always have these extra directives, without needing to
863860
// specify them manually in every test file.
@@ -875,21 +872,15 @@ fn iter_directives(
875872
for directive_str in extra_directives {
876873
let directive_line = line_directive(0, directive_str)
877874
.unwrap_or_else(|| panic!("bad extra-directive line: {directive_str:?}"));
878-
it(directive_line);
875+
it(&directive_line);
879876
}
880877
}
881878

882-
for (line_number, ln) in (1..).zip(file_contents.lines()) {
883-
let ln = ln.trim();
884-
885-
let Some(directive_line) = line_directive(line_number, ln) else {
886-
continue;
887-
};
888-
879+
for directive_line @ &DirectiveLine { line_number, .. } in &file_directives.lines {
889880
// Perform unknown directive check on Rust files.
890881
if testfile.extension() == Some("rs") {
891882
let CheckDirectiveResult { is_known_directive, trailing_directive } =
892-
check_directive(&directive_line, mode);
883+
check_directive(directive_line, mode);
893884

894885
if !is_known_directive {
895886
*poisoned = true;
@@ -1349,7 +1340,7 @@ pub(crate) fn make_test_description(
13491340
name: String,
13501341
path: &Utf8Path,
13511342
filterable_path: &Utf8Path,
1352-
file_contents: &str,
1343+
file_directives: &FileDirectives<'_>,
13531344
test_revision: Option<&str>,
13541345
poisoned: &mut bool,
13551346
) -> CollectedTestDesc {
@@ -1363,9 +1354,8 @@ pub(crate) fn make_test_description(
13631354
iter_directives(
13641355
config.mode,
13651356
&mut local_poisoned,
1366-
path,
1367-
file_contents,
1368-
&mut |ref ln @ DirectiveLine { line_number, .. }| {
1357+
file_directives,
1358+
&mut |ln @ &DirectiveLine { line_number, .. }| {
13691359
if !ln.applies_to_test_revision(test_revision) {
13701360
return;
13711361
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use camino::Utf8Path;
2+
3+
use crate::directives::line::{DirectiveLine, line_directive};
4+
5+
pub(crate) struct FileDirectives<'a> {
6+
pub(crate) path: &'a Utf8Path,
7+
pub(crate) lines: Vec<DirectiveLine<'a>>,
8+
}
9+
10+
impl<'a> FileDirectives<'a> {
11+
pub(crate) fn from_file_contents(path: &'a Utf8Path, file_contents: &'a str) -> Self {
12+
let mut lines = vec![];
13+
14+
for (line_number, ln) in (1..).zip(file_contents.lines()) {
15+
let ln = ln.trim();
16+
17+
if let Some(directive_line) = line_directive(line_number, ln) {
18+
lines.push(directive_line);
19+
}
20+
}
21+
22+
Self { path, lines }
23+
}
24+
}

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

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

44
use crate::common::{Config, Debugger, TestMode};
55
use crate::directives::{
6-
DirectivesCache, EarlyProps, Edition, EditionRange, extract_llvm_version,
6+
DirectivesCache, EarlyProps, Edition, EditionRange, FileDirectives, extract_llvm_version,
77
extract_version_range, iter_directives, line_directive, parse_edition, parse_normalize_rule,
88
};
99
use crate::executor::{CollectedTestDesc, ShouldPanic};
@@ -18,13 +18,15 @@ fn make_test_description(
1818
) -> CollectedTestDesc {
1919
let cache = DirectivesCache::load(config);
2020
let mut poisoned = false;
21+
let file_directives = FileDirectives::from_file_contents(path, file_contents);
22+
2123
let test = crate::directives::make_test_description(
2224
config,
2325
&cache,
2426
name,
2527
path,
2628
filterable_path,
27-
file_contents,
29+
&file_directives,
2830
revision,
2931
&mut poisoned,
3032
);
@@ -224,7 +226,8 @@ fn cfg() -> ConfigBuilder {
224226
}
225227

226228
fn parse_rs(config: &Config, contents: &str) -> EarlyProps {
227-
EarlyProps::from_file_contents(config, Utf8Path::new("a.rs"), contents)
229+
let file_directives = FileDirectives::from_file_contents(Utf8Path::new("a.rs"), contents);
230+
EarlyProps::from_file_directives(config, &file_directives)
228231
}
229232

230233
fn check_ignore(config: &Config, contents: &str) -> bool {
@@ -776,7 +779,8 @@ fn threads_support() {
776779
}
777780

778781
fn run_path(poisoned: &mut bool, path: &Utf8Path, file_contents: &str) {
779-
iter_directives(TestMode::Ui, poisoned, path, file_contents, &mut |_| {});
782+
let file_directives = FileDirectives::from_file_contents(path, file_contents);
783+
iter_directives(TestMode::Ui, poisoned, &file_directives, &mut |_| {});
780784
}
781785

782786
#[test]

src/tools/compiletest/src/lib.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use crate::common::{
4141
CodegenBackend, CompareMode, Config, Debugger, PassMode, TestMode, TestPaths, UI_EXTENSIONS,
4242
expected_output_path, output_base_dir, output_relative_path,
4343
};
44-
use crate::directives::DirectivesCache;
44+
use crate::directives::{DirectivesCache, FileDirectives};
4545
use crate::edition::parse_edition;
4646
use crate::executor::{CollectedTest, ColorConfig};
4747

@@ -868,7 +868,10 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
868868
};
869869

870870
// Scan the test file to discover its revisions, if any.
871-
let early_props = EarlyProps::from_file(&cx.config, &test_path);
871+
let file_contents =
872+
fs::read_to_string(&test_path).expect("reading test file for directives should succeed");
873+
let file_directives = FileDirectives::from_file_contents(&test_path, &file_contents);
874+
let early_props = EarlyProps::from_file_directives(&cx.config, &file_directives);
872875

873876
// Normally we create one structure per revision, with two exceptions:
874877
// - If a test doesn't use revisions, create a dummy revision (None) so that
@@ -886,8 +889,6 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
886889
// `CollectedTest` that can be handed over to the test executor.
887890
collector.tests.extend(revisions.into_iter().map(|revision| {
888891
// Create a test name and description to hand over to the executor.
889-
let file_contents =
890-
fs::read_to_string(&test_path).expect("read test file to parse ignores");
891892
let (test_name, filterable_path) =
892893
make_test_name_and_filterable_path(&cx.config, testpaths, revision);
893894
// Create a description struct for the test/revision.
@@ -899,7 +900,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
899900
test_name,
900901
&test_path,
901902
&filterable_path,
902-
&file_contents,
903+
&file_directives,
903904
revision,
904905
&mut collector.poisoned,
905906
);

0 commit comments

Comments
 (0)