Skip to content

Commit fe1e433

Browse files
committed
add support for certain ui_test style only and ignore
1 parent d500858 commit fe1e433

File tree

2 files changed

+140
-92
lines changed

2 files changed

+140
-92
lines changed

src/tools/compiletest/src/header.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -402,14 +402,10 @@ impl TestProps {
402402

403403
config.set_name_directive(&comment, IgnorePassDirective, &mut self.ignore_pass);
404404

405-
if let Some(rule) =
406-
config.parse_custom_normalization(comment.comment_str(), "normalize-stdout")
407-
{
405+
if let Some(rule) = config.parse_custom_normalization(comment, "normalize-stdout") {
408406
self.normalize_stdout.push(rule);
409407
}
410-
if let Some(rule) =
411-
config.parse_custom_normalization(comment.comment_str(), "normalize-stderr")
412-
{
408+
if let Some(rule) = config.parse_custom_normalization(comment, "normalize-stderr") {
413409
self.normalize_stderr.push(rule);
414410
}
415411

@@ -659,8 +655,13 @@ impl Config {
659655
}
660656
}
661657

662-
fn parse_custom_normalization(&self, mut line: &str, prefix: &str) -> Option<(String, String)> {
663-
if parse_cfg_name_directive(self, line, prefix).outcome == MatchOutcome::Match {
658+
fn parse_custom_normalization(
659+
&self,
660+
comment: TestComment<'_>,
661+
prefix: &str,
662+
) -> Option<(String, String)> {
663+
if matches!(parse_cfg_name_directive(self, &comment, prefix), MatchOutcome::Match { .. }) {
664+
let mut line = comment.comment_str();
664665
let from = parse_normalization_string(&mut line)?;
665666
let to = parse_normalization_string(&mut line)?;
666667
Some((from, to))
@@ -927,8 +928,8 @@ pub fn make_test_description<R: Read>(
927928
}
928929

929930
let ln = comment.comment_str();
930-
decision!(cfg::handle_ignore(config, ln));
931-
decision!(cfg::handle_only(config, ln));
931+
decision!(cfg::handle_ignore(config, comment));
932+
decision!(cfg::handle_only(config, comment));
932933
decision!(needs::handle_needs(&cache.needs, config, comment));
933934
decision!(ignore_llvm(config, &comment));
934935
decision!(ignore_cdb(config, ln));

src/tools/compiletest/src/header/cfg.rs

+129-82
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,140 @@
1+
use test_common::{CommentKind, TestComment};
2+
13
use crate::common::{CompareMode, Config, Debugger};
24
use crate::header::IgnoreDecision;
35
use std::collections::HashSet;
46

57
const EXTRA_ARCHS: &[&str] = &["spirv"];
68

7-
pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision {
8-
let parsed = parse_cfg_name_directive(config, line, "ignore");
9-
match parsed.outcome {
10-
MatchOutcome::NoMatch => IgnoreDecision::Continue,
11-
MatchOutcome::Match => IgnoreDecision::Ignore {
12-
reason: match parsed.comment {
13-
Some(comment) => format!("ignored {} ({comment})", parsed.pretty_reason.unwrap()),
14-
None => format!("ignored {}", parsed.pretty_reason.unwrap()),
9+
pub(super) fn handle_ignore(config: &Config, comment: TestComment<'_>) -> IgnoreDecision {
10+
match parse_cfg_name_directive(config, &comment, "ignore") {
11+
MatchOutcome::Match { message, comment } => IgnoreDecision::Ignore {
12+
reason: match comment {
13+
Some(comment) => format!("ignored {} ({comment})", message),
14+
None => format!("ignored {}", message),
1515
},
1616
},
17-
MatchOutcome::Invalid => IgnoreDecision::Error { message: format!("invalid line: {line}") },
17+
MatchOutcome::NoMatch { .. } => IgnoreDecision::Continue,
18+
MatchOutcome::Invalid => {
19+
IgnoreDecision::Error { message: format!("invalid line: {}", comment.comment_str()) }
20+
}
1821
MatchOutcome::External => IgnoreDecision::Continue,
1922
MatchOutcome::NotADirective => IgnoreDecision::Continue,
2023
}
2124
}
2225

23-
pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
24-
let parsed = parse_cfg_name_directive(config, line, "only");
25-
match parsed.outcome {
26-
MatchOutcome::Match => IgnoreDecision::Continue,
27-
MatchOutcome::NoMatch => IgnoreDecision::Ignore {
28-
reason: match parsed.comment {
29-
Some(comment) => {
30-
format!("only executed {} ({comment})", parsed.pretty_reason.unwrap())
31-
}
32-
None => format!("only executed {}", parsed.pretty_reason.unwrap()),
26+
pub(super) fn handle_only(config: &Config, comment: TestComment<'_>) -> IgnoreDecision {
27+
match parse_cfg_name_directive(config, &comment, "only") {
28+
MatchOutcome::Match { .. } => IgnoreDecision::Continue,
29+
MatchOutcome::NoMatch { message, comment } => IgnoreDecision::Ignore {
30+
reason: match comment {
31+
Some(comment) => format!("only executed {} ({comment})", message),
32+
None => format!("only executed {}", message),
3333
},
3434
},
35-
MatchOutcome::Invalid => IgnoreDecision::Error { message: format!("invalid line: {line}") },
35+
MatchOutcome::Invalid => {
36+
IgnoreDecision::Error { message: format!("invalid line: {}", comment.comment_str()) }
37+
}
3638
MatchOutcome::External => IgnoreDecision::Continue,
3739
MatchOutcome::NotADirective => IgnoreDecision::Continue,
3840
}
3941
}
4042

4143
/// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
4244
/// or `normalize-stderr-32bit`.
43-
pub(super) fn parse_cfg_name_directive<'a>(
45+
pub(super) fn parse_cfg_name_directive<'line>(
4446
config: &Config,
45-
line: &'a str,
47+
comment: &'line TestComment<'line>,
4648
prefix: &str,
47-
) -> ParsedNameDirective<'a> {
48-
if !line.as_bytes().starts_with(prefix.as_bytes()) {
49-
return ParsedNameDirective::not_a_directive();
50-
}
51-
if line.as_bytes().get(prefix.len()) != Some(&b'-') {
52-
return ParsedNameDirective::not_a_directive();
49+
) -> MatchOutcome<'line> {
50+
match comment.comment() {
51+
CommentKind::Compiletest(line) => {
52+
parse_cfg_name_directive_compiletest(config, line, prefix)
53+
}
54+
CommentKind::UiTest(line) => parse_cfg_name_directive_ui_test(config, line, prefix),
5355
}
54-
let line = &line[prefix.len() + 1..];
56+
}
5557

56-
let (name, comment) =
57-
line.split_once(&[':', ' ']).map(|(l, c)| (l, Some(c))).unwrap_or((line, None));
58+
fn directive_name_for_line<'line, 'p>(
59+
line: &'line str,
60+
prefix: &'p str,
61+
) -> Option<(&'line str, Option<&'line str>)> {
62+
// Directives start with a specified prefix, and are immediately followed by a '-'.
63+
let expected_start = format!("{}-", prefix);
64+
let after_prefix = if line.starts_with(expected_start.as_str()) {
65+
&line[expected_start.len()..]
66+
} else {
67+
return None;
68+
};
69+
70+
// If there is a ':' or a ' ' (space), split the name off, and consider the rest of the line to
71+
// be a "comment" that is ignored.
72+
let (name, comment) = after_prefix
73+
.split_once(&[':', ' '])
74+
.map(|(l, c)| (l.trim(), Some(c)))
75+
.unwrap_or((after_prefix, None));
5876

5977
// Some of the matchers might be "" depending on what the target information is. To avoid
6078
// problems we outright reject empty directives.
61-
if name == "" {
62-
return ParsedNameDirective::not_a_directive();
79+
if name == "" { None } else { Some((name, comment)) }
80+
}
81+
82+
fn parse_cfg_name_directive_ui_test<'line>(
83+
config: &Config,
84+
line: &'line str,
85+
prefix: &str,
86+
) -> MatchOutcome<'line> {
87+
let Some((name, comment)) = directive_name_for_line(line, prefix) else {
88+
return MatchOutcome::NotADirective;
89+
};
90+
let comment = comment.map(|c| c.trim().trim_start_matches('-').trim());
91+
92+
let target_cfg = config.target_cfg();
93+
94+
if name == "on-host" {
95+
unimplemented!("idk what to do about this yet")
96+
} else if let Some(bits) = name.strip_suffix("bit") {
97+
let Ok(bits) = bits.parse::<u32>() else {
98+
// "invalid ignore/only filter ending in 'bit': {bits:?} is not a valid bitwdith"
99+
return MatchOutcome::Invalid;
100+
};
101+
102+
let message = format!("when the pointer width is {}", target_cfg.pointer_width);
103+
if bits == target_cfg.pointer_width {
104+
MatchOutcome::Match { message, comment }
105+
} else {
106+
MatchOutcome::NoMatch { message, comment }
107+
}
108+
} else if let Some(triple_substr) = name.strip_prefix("target-") {
109+
let message = format!("when the target is {}", config.target);
110+
if config.target.contains(triple_substr) {
111+
MatchOutcome::Match { message, comment }
112+
} else {
113+
MatchOutcome::NoMatch { message, comment }
114+
}
115+
} else if let Some(triple_substr) = name.strip_prefix("host-") {
116+
let message = format!("when the host is {}", config.host);
117+
if config.host.contains(triple_substr) {
118+
MatchOutcome::Match { message, comment }
119+
} else {
120+
MatchOutcome::NoMatch { message, comment }
121+
}
122+
} else {
123+
panic!(
124+
"`{name}` is not a valid condition, expected `on-host`, /[0-9]+bit/, /host-.*/, or /target-.*/"
125+
)
63126
}
127+
}
64128

65-
let mut outcome = MatchOutcome::Invalid;
66-
let mut message = None;
129+
fn parse_cfg_name_directive_compiletest<'a>(
130+
config: &Config,
131+
line: &'a str,
132+
prefix: &str,
133+
) -> MatchOutcome<'a> {
134+
let Some((name, comment)) = directive_name_for_line(line, prefix) else {
135+
return MatchOutcome::NotADirective;
136+
};
137+
let comment = comment.map(|c| c.trim().trim_start_matches('-').trim());
67138

68139
macro_rules! condition {
69140
(
@@ -75,19 +146,24 @@ pub(super) fn parse_cfg_name_directive<'a>(
75146
// This is not inlined to avoid problems with macro repetitions.
76147
let format_message = || format!($($message)*);
77148

78-
if outcome != MatchOutcome::Invalid {
79-
// Ignore all other matches if we already found one
80-
} else if $name.custom_matches(name) {
81-
message = Some(format_message());
149+
if $name.custom_matches(name) {
82150
if true $(&& $condition)? {
83-
outcome = MatchOutcome::Match;
151+
return MatchOutcome::Match {
152+
message: format_message(),
153+
comment,
154+
};
84155
} else {
85-
outcome = MatchOutcome::NoMatch;
156+
return MatchOutcome::NoMatch{
157+
message: format_message(),
158+
comment,
159+
};
86160
}
87161
}
88162
$(else if $allowed_names.custom_contains(name) {
89-
message = Some(format_message());
90-
outcome = MatchOutcome::NoMatch;
163+
return MatchOutcome::NoMatch {
164+
message: format_message(),
165+
comment,
166+
};
91167
})?
92168
}};
93169
}
@@ -124,11 +200,6 @@ pub(super) fn parse_cfg_name_directive<'a>(
124200
allowed_names: &target_cfgs.all_oses_and_envs,
125201
message: "when the operating system and target environment are {name}"
126202
}
127-
condition! {
128-
name: &target_cfg.abi,
129-
allowed_names: &target_cfgs.all_abis,
130-
message: "when the ABI is {name}"
131-
}
132203
condition! {
133204
name: &target_cfg.arch,
134205
allowed_names: ContainsEither { a: &target_cfgs.all_archs, b: &EXTRA_ARCHS },
@@ -215,64 +286,40 @@ pub(super) fn parse_cfg_name_directive<'a>(
215286
message: "when comparing with {name}",
216287
}
217288

218-
if prefix == "ignore" && outcome == MatchOutcome::Invalid {
289+
if prefix == "ignore" {
219290
// Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest.
220291
if name.starts_with("tidy-") {
221-
outcome = MatchOutcome::External;
292+
return MatchOutcome::External;
222293
}
223294

224295
// Don't error out for ignore-pass, as that is handled elsewhere.
225296
if name == "pass" {
226-
outcome = MatchOutcome::External;
297+
return MatchOutcome::External;
227298
}
228299

229300
// Don't error out for ignore-llvm-version, that has a custom syntax and is handled
230301
// elsewhere.
231302
if name == "llvm-version" {
232-
outcome = MatchOutcome::External;
303+
return MatchOutcome::External;
233304
}
234305

235306
// Don't error out for ignore-llvm-version, that has a custom syntax and is handled
236307
// elsewhere.
237308
if name == "gdb-version" {
238-
outcome = MatchOutcome::External;
309+
return MatchOutcome::External;
239310
}
240311
}
241312

242-
ParsedNameDirective {
243-
name: Some(name),
244-
comment: comment.map(|c| c.trim().trim_start_matches('-').trim()),
245-
outcome,
246-
pretty_reason: message,
247-
}
313+
// Did not match any known condition, emit an error.
314+
MatchOutcome::Invalid
248315
}
249316

250-
/// The result of parse_cfg_name_directive.
251317
#[derive(Clone, PartialEq, Debug)]
252-
pub(super) struct ParsedNameDirective<'a> {
253-
pub(super) name: Option<&'a str>,
254-
pub(super) pretty_reason: Option<String>,
255-
pub(super) comment: Option<&'a str>,
256-
pub(super) outcome: MatchOutcome,
257-
}
258-
259-
impl ParsedNameDirective<'_> {
260-
fn not_a_directive() -> Self {
261-
Self {
262-
name: None,
263-
pretty_reason: None,
264-
comment: None,
265-
outcome: MatchOutcome::NotADirective,
266-
}
267-
}
268-
}
269-
270-
#[derive(Clone, Copy, PartialEq, Debug)]
271-
pub(super) enum MatchOutcome {
318+
pub(super) enum MatchOutcome<'a> {
272319
/// No match.
273-
NoMatch,
320+
NoMatch { message: String, comment: Option<&'a str> },
274321
/// Match.
275-
Match,
322+
Match { message: String, comment: Option<&'a str> },
276323
/// The directive was invalid.
277324
Invalid,
278325
/// The directive is handled by other parts of our tooling.

0 commit comments

Comments
 (0)