Skip to content

Commit 046b205

Browse files
committed
Use new DirectiveLine features in directive parsing
1 parent 287bf69 commit 046b205

File tree

5 files changed

+67
-84
lines changed

5 files changed

+67
-84
lines changed

src/tools/compiletest/src/directives.rs

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -831,9 +831,7 @@ fn check_directive<'a>(
831831
directive_ln: &DirectiveLine<'a>,
832832
mode: TestMode,
833833
) -> CheckDirectiveResult<'a> {
834-
let &DirectiveLine { raw_directive: directive_ln, .. } = directive_ln;
835-
836-
let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
834+
let &DirectiveLine { name: directive_name, .. } = directive_ln;
837835

838836
let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name)
839837
|| match mode {
@@ -842,14 +840,13 @@ fn check_directive<'a>(
842840
_ => false,
843841
};
844842

845-
let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
846-
let trailing_directive = {
847-
// 1. is the directive name followed by a space? (to exclude `:`)
848-
directive_ln.get(directive_name.len()..).is_some_and(|s| s.starts_with(' '))
849-
// 2. is what is after that directive also a directive (ex: "only-x86 only-arm")
850-
&& KNOWN_DIRECTIVE_NAMES.contains(&trailing)
851-
}
852-
.then_some(trailing);
843+
// If it looks like the user tried to put two directives on the same line
844+
// (e.g. `//@ only-linux only-x86_64`), signal an error, because the
845+
// second "directive" would actually be ignored with no effect.
846+
let trailing_directive = directive_ln
847+
.remark_after_space()
848+
.map(|remark| remark.trim_start().split(' ').next().unwrap())
849+
.filter(|token| KNOWN_DIRECTIVE_NAMES.contains(token));
853850

854851
CheckDirectiveResult { is_known_directive, trailing_directive }
855852
}
@@ -911,7 +908,7 @@ fn iter_directives(
911908

912909
error!(
913910
"{testfile}:{line_number}: detected unknown compiletest test directive `{}`",
914-
directive_line.raw_directive,
911+
directive_line.display(),
915912
);
916913

917914
return;
@@ -1007,35 +1004,30 @@ impl Config {
10071004
}
10081005

10091006
fn parse_custom_normalization(&self, line: &DirectiveLine<'_>) -> Option<NormalizeRule> {
1010-
let &DirectiveLine { raw_directive, .. } = line;
1011-
1012-
// FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine`
1013-
// instead of doing it here.
1014-
let (directive_name, raw_value) = raw_directive.split_once(':')?;
1007+
let &DirectiveLine { name, .. } = line;
10151008

1016-
let kind = match directive_name {
1009+
let kind = match name {
10171010
"normalize-stdout" => NormalizeKind::Stdout,
10181011
"normalize-stderr" => NormalizeKind::Stderr,
10191012
"normalize-stderr-32bit" => NormalizeKind::Stderr32bit,
10201013
"normalize-stderr-64bit" => NormalizeKind::Stderr64bit,
10211014
_ => return None,
10221015
};
10231016

1024-
let Some((regex, replacement)) = parse_normalize_rule(raw_value) else {
1025-
error!("couldn't parse custom normalization rule: `{raw_directive}`");
1026-
help!("expected syntax is: `{directive_name}: \"REGEX\" -> \"REPLACEMENT\"`");
1017+
let Some((regex, replacement)) = line.value_after_colon().and_then(parse_normalize_rule)
1018+
else {
1019+
error!("couldn't parse custom normalization rule: `{}`", line.display());
1020+
help!("expected syntax is: `{name}: \"REGEX\" -> \"REPLACEMENT\"`");
10271021
panic!("invalid normalization rule detected");
10281022
};
10291023
Some(NormalizeRule { kind, regex, replacement })
10301024
}
10311025

10321026
fn parse_name_directive(&self, line: &DirectiveLine<'_>, directive: &str) -> bool {
1033-
let &DirectiveLine { raw_directive: line, .. } = line;
1034-
1035-
// Ensure the directive is a whole word. Do not match "ignore-x86" when
1036-
// the line says "ignore-x86_64".
1037-
line.starts_with(directive)
1038-
&& matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':'))
1027+
// FIXME(Zalathar): Ideally, this should raise an error if a name-only
1028+
// directive is followed by a colon, since that's the wrong syntax.
1029+
// But we would need to fix tests that rely on the current behaviour.
1030+
line.name == directive
10391031
}
10401032

10411033
fn parse_name_value_directive(
@@ -1044,22 +1036,26 @@ impl Config {
10441036
directive: &str,
10451037
testfile: &Utf8Path,
10461038
) -> Option<String> {
1047-
let &DirectiveLine { line_number, raw_directive: line, .. } = line;
1048-
1049-
let colon = directive.len();
1050-
if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') {
1051-
let value = line[(colon + 1)..].to_owned();
1052-
debug!("{}: {}", directive, value);
1053-
let value = expand_variables(value, self);
1054-
if value.is_empty() {
1055-
error!("{testfile}:{line_number}: empty value for directive `{directive}`");
1056-
help!("expected syntax is: `{directive}: value`");
1057-
panic!("empty directive value detected");
1058-
}
1059-
Some(value)
1060-
} else {
1061-
None
1039+
let &DirectiveLine { line_number, .. } = line;
1040+
1041+
if line.name != directive {
1042+
return None;
1043+
};
1044+
1045+
// FIXME(Zalathar): This silently discards directives with a matching
1046+
// name but no colon. Unfortunately, some directives (e.g. "pp-exact")
1047+
// currently rely on _not_ panicking here.
1048+
let value = line.value_after_colon()?;
1049+
debug!("{}: {}", directive, value);
1050+
let value = expand_variables(value.to_owned(), self);
1051+
1052+
if value.is_empty() {
1053+
error!("{testfile}:{line_number}: empty value for directive `{directive}`");
1054+
help!("expected syntax is: `{directive}: value`");
1055+
panic!("empty directive value detected");
10621056
}
1057+
1058+
Some(value)
10631059
}
10641060

10651061
fn parse_edition(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option<String> {
@@ -1453,14 +1449,14 @@ pub(crate) fn make_test_description<R: Read>(
14531449
}
14541450

14551451
fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
1456-
let &DirectiveLine { raw_directive: line, .. } = line;
1457-
14581452
if config.debugger != Some(Debugger::Cdb) {
14591453
return IgnoreDecision::Continue;
14601454
}
14611455

14621456
if let Some(actual_version) = config.cdb_version {
1463-
if let Some(rest) = line.strip_prefix("min-cdb-version:").map(str::trim) {
1457+
if line.name == "min-cdb-version"
1458+
&& let Some(rest) = line.value_after_colon().map(str::trim)
1459+
{
14641460
let min_version = extract_cdb_version(rest).unwrap_or_else(|| {
14651461
panic!("couldn't parse version range: {:?}", rest);
14661462
});
@@ -1478,14 +1474,14 @@ fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
14781474
}
14791475

14801476
fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
1481-
let &DirectiveLine { raw_directive: line, .. } = line;
1482-
14831477
if config.debugger != Some(Debugger::Gdb) {
14841478
return IgnoreDecision::Continue;
14851479
}
14861480

14871481
if let Some(actual_version) = config.gdb_version {
1488-
if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) {
1482+
if line.name == "min-gdb-version"
1483+
&& let Some(rest) = line.value_after_colon().map(str::trim)
1484+
{
14891485
let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version)
14901486
.unwrap_or_else(|| {
14911487
panic!("couldn't parse version range: {:?}", rest);
@@ -1501,7 +1497,9 @@ fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
15011497
reason: format!("ignored when the GDB version is lower than {rest}"),
15021498
};
15031499
}
1504-
} else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) {
1500+
} else if line.name == "ignore-gdb-version"
1501+
&& let Some(rest) = line.value_after_colon().map(str::trim)
1502+
{
15051503
let (min_version, max_version) = extract_version_range(rest, extract_gdb_version)
15061504
.unwrap_or_else(|| {
15071505
panic!("couldn't parse version range: {:?}", rest);
@@ -1528,14 +1526,14 @@ fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
15281526
}
15291527

15301528
fn ignore_lldb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
1531-
let &DirectiveLine { raw_directive: line, .. } = line;
1532-
15331529
if config.debugger != Some(Debugger::Lldb) {
15341530
return IgnoreDecision::Continue;
15351531
}
15361532

15371533
if let Some(actual_version) = config.lldb_version {
1538-
if let Some(rest) = line.strip_prefix("min-lldb-version:").map(str::trim) {
1534+
if line.name == "min-lldb-version"
1535+
&& let Some(rest) = line.value_after_colon().map(str::trim)
1536+
{
15391537
let min_version = rest.parse().unwrap_or_else(|e| {
15401538
panic!("Unexpected format of LLDB version string: {}\n{:?}", rest, e);
15411539
});

src/tools/compiletest/src/directives/auxiliary.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ pub(super) fn parse_and_update_aux(
5050
testfile: &Utf8Path,
5151
aux: &mut AuxProps,
5252
) {
53-
let &DirectiveLine { raw_directive: ln, .. } = directive_line;
54-
55-
if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) {
53+
if !(directive_line.name.starts_with("aux-") || directive_line.name == "proc-macro") {
5654
return;
5755
}
5856

src/tools/compiletest/src/directives/cfg.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use crate::directives::{DirectiveLine, IgnoreDecision};
66
const EXTRA_ARCHS: &[&str] = &["spirv"];
77

88
pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
9-
let parsed = parse_cfg_name_directive(config, line, "ignore");
10-
let &DirectiveLine { raw_directive: line, .. } = line;
9+
let parsed = parse_cfg_name_directive(config, line, "ignore-");
10+
let line = line.display();
1111

1212
match parsed.outcome {
1313
MatchOutcome::NoMatch => IgnoreDecision::Continue,
@@ -24,8 +24,8 @@ pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> Ignore
2424
}
2525

2626
pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
27-
let parsed = parse_cfg_name_directive(config, line, "only");
28-
let &DirectiveLine { raw_directive: line, .. } = line;
27+
let parsed = parse_cfg_name_directive(config, line, "only-");
28+
let line = line.display();
2929

3030
match parsed.outcome {
3131
MatchOutcome::Match => IgnoreDecision::Continue,
@@ -50,18 +50,14 @@ fn parse_cfg_name_directive<'a>(
5050
line: &'a DirectiveLine<'a>,
5151
prefix: &str,
5252
) -> ParsedNameDirective<'a> {
53-
let &DirectiveLine { raw_directive: line, .. } = line;
54-
55-
if !line.as_bytes().starts_with(prefix.as_bytes()) {
56-
return ParsedNameDirective::not_a_directive();
57-
}
58-
if line.as_bytes().get(prefix.len()) != Some(&b'-') {
53+
let Some(name) = line.name.strip_prefix(prefix) else {
5954
return ParsedNameDirective::not_a_directive();
60-
}
61-
let line = &line[prefix.len() + 1..];
55+
};
6256

63-
let (name, comment) =
64-
line.split_once(&[':', ' ']).map(|(l, c)| (l, Some(c))).unwrap_or((line, None));
57+
// FIXME(Zalathar): This currently allows either a space or a colon, and
58+
// treats any "value" after a colon as though it were a remark.
59+
// We should instead forbid the colon syntax for these directives.
60+
let comment = line.remark_after_space().or_else(|| line.value_after_colon());
6561

6662
// Some of the matchers might be "" depending on what the target information is. To avoid
6763
// problems we outright reject empty directives.
@@ -269,7 +265,7 @@ fn parse_cfg_name_directive<'a>(
269265
message: "when performing tests on dist toolchain"
270266
}
271267

272-
if prefix == "ignore" && outcome == MatchOutcome::Invalid {
268+
if prefix == "ignore-" && outcome == MatchOutcome::Invalid {
273269
// Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest.
274270
if name.starts_with("tidy-") {
275271
outcome = MatchOutcome::External;

src/tools/compiletest/src/directives/line.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![expect(dead_code)] // (removed later in this PR)
2-
31
use std::fmt;
42

53
const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
@@ -66,7 +64,7 @@ pub(crate) struct DirectiveLine<'ln> {
6664
///
6765
/// This is "raw" because the directive's name and colon-separated value
6866
/// (if present) have not yet been extracted or checked.
69-
pub(crate) raw_directive: &'ln str,
67+
raw_directive: &'ln str,
7068

7169
/// Name of the directive.
7270
///

src/tools/compiletest/src/directives/needs.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,10 @@ pub(super) fn handle_needs(
181181
},
182182
];
183183

184-
let &DirectiveLine { raw_directive: ln, .. } = ln;
184+
let &DirectiveLine { name, .. } = ln;
185185

186-
let (name, rest) = match ln.split_once([':', ' ']) {
187-
Some((name, rest)) => (name, Some(rest)),
188-
None => (ln, None),
189-
};
190-
191-
// FIXME(jieyouxu): tighten up this parsing to reject using both `:` and ` ` as means to
192-
// delineate value.
193186
if name == "needs-target-has-atomic" {
194-
let Some(rest) = rest else {
187+
let Some(rest) = ln.value_after_colon() else {
195188
return IgnoreDecision::Error {
196189
message: "expected `needs-target-has-atomic` to have a comma-separated list of atomic widths".to_string(),
197190
};
@@ -233,7 +226,7 @@ pub(super) fn handle_needs(
233226

234227
// FIXME(jieyouxu): share multi-value directive logic with `needs-target-has-atomic` above.
235228
if name == "needs-crate-type" {
236-
let Some(rest) = rest else {
229+
let Some(rest) = ln.value_after_colon() else {
237230
return IgnoreDecision::Error {
238231
message:
239232
"expected `needs-crate-type` to have a comma-separated list of crate types"
@@ -295,7 +288,7 @@ pub(super) fn handle_needs(
295288
break;
296289
} else {
297290
return IgnoreDecision::Ignore {
298-
reason: if let Some(comment) = rest {
291+
reason: if let Some(comment) = ln.remark_after_space() {
299292
format!("{} ({})", need.ignore_reason, comment.trim())
300293
} else {
301294
need.ignore_reason.into()

0 commit comments

Comments
 (0)