Skip to content

Commit 54d51bc

Browse files
Allow multiple cfgs per comment in "revisions:" tests
The `//[X]~` syntax filters errors for tests that are run across multiple cfgs with `// revisions:`. This commit extends that syntax to accept `//[X,Y]~`, which will match multiple cfgs to the same error annotation. This is functionally the same as writing two comments, `//[X]~` and `//[Y]~`, but can fit on a single line.
1 parent 53712f8 commit 54d51bc

File tree

1 file changed

+47
-42
lines changed

1 file changed

+47
-42
lines changed

src/tools/compiletest/src/errors.rs

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use std::io::BufReader;
77
use std::path::Path;
88
use std::str::FromStr;
99

10+
use lazy_static::lazy_static;
1011
use log::*;
12+
use regex::Regex;
1113

1214
#[derive(Clone, Debug, PartialEq)]
1315
pub enum ErrorKind {
@@ -85,20 +87,16 @@ pub fn load_errors(testfile: &Path, cfg: Option<&str>) -> Vec<Error> {
8587
// updating it in the map callback below.)
8688
let mut last_nonfollow_error = None;
8789

88-
let tag = match cfg {
89-
Some(rev) => format!("//[{}]~", rev),
90-
None => "//~".to_string(),
91-
};
92-
9390
rdr.lines()
9491
.enumerate()
9592
.filter_map(|(line_num, line)| {
96-
parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), &tag).map(
93+
parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), cfg).map(
9794
|(which, error)| {
9895
match which {
9996
FollowPrevious(_) => {}
10097
_ => last_nonfollow_error = Some(error.line_num),
10198
}
99+
102100
error
103101
},
104102
)
@@ -110,46 +108,53 @@ fn parse_expected(
110108
last_nonfollow_error: Option<usize>,
111109
line_num: usize,
112110
line: &str,
113-
tag: &str,
111+
cfg: Option<&str>,
114112
) -> Option<(WhichLine, Error)> {
115-
let start = line.find(tag)?;
116-
let (follow, adjusts) = if line[start + tag.len()..].chars().next().unwrap() == '|' {
117-
(true, 0)
118-
} else {
119-
(
120-
false,
121-
line[start + tag.len()..]
122-
.chars()
123-
.take_while(|c| *c == '^')
124-
.count(),
125-
)
113+
// Matches comments like:
114+
// //~
115+
// //~|
116+
// //~^
117+
// //~^^^^^
118+
// //[cfg1]~
119+
// //[cfg1,cfg2]~^^
120+
lazy_static! {
121+
static ref RE: Regex =
122+
Regex::new(r"//(?:\[(?P<cfgs>[\w,]+)])?~(?P<adjust>\||\^*)").unwrap();
123+
}
124+
125+
let captures = RE.captures(line)?;
126+
127+
match (cfg, captures.name("cfgs")) {
128+
// Only error messages that contain our `cfg` betweeen the square brackets apply to us.
129+
(Some(cfg), Some(filter)) if !filter.as_str().split(',').any(|s| s == cfg)
130+
=> return None,
131+
(Some(_), Some(_)) => {}
132+
133+
(None, Some(_)) => panic!("Only tests with revisions should use `//[X]~`"),
134+
135+
// If an error has no list of revisions, it applies to all revisions.
136+
(Some(_), None) | (None, None) => {}
137+
}
138+
139+
let (follow, adjusts) = match &captures["adjust"] {
140+
"|" => (true, 0),
141+
circumflexes => (false, circumflexes.len()),
126142
};
127-
let kind_start = start + tag.len() + adjusts + (follow as usize);
128-
let (kind, msg);
129-
match line[kind_start..]
143+
144+
// Get the part of the comment after the sigil (e.g. `~^^` or ~|).
145+
let (_, mut msg) = line.split_at(captures.get(0).unwrap().end());
146+
147+
let first_word = msg
130148
.split_whitespace()
131149
.next()
132-
.expect("Encountered unexpected empty comment")
133-
.parse::<ErrorKind>()
134-
{
135-
Ok(k) => {
136-
// If we find `//~ ERROR foo` or something like that:
137-
kind = Some(k);
138-
let letters = line[kind_start..].chars();
139-
msg = letters
140-
.skip_while(|c| c.is_whitespace())
141-
.skip_while(|c| !c.is_whitespace())
142-
.collect::<String>();
143-
}
144-
Err(_) => {
145-
// Otherwise we found `//~ foo`:
146-
kind = None;
147-
let letters = line[kind_start..].chars();
148-
msg = letters
149-
.skip_while(|c| c.is_whitespace())
150-
.collect::<String>();
151-
}
150+
.expect("Encountered unexpected empty comment");
151+
152+
// If we find `//~ ERROR foo` or something like that, skip the first word.
153+
let kind = first_word.parse::<ErrorKind>().ok();
154+
if let Some(_) = kind {
155+
msg = &msg.trim_start().split_at(first_word.len()).1;
152156
}
157+
153158
let msg = msg.trim().to_owned();
154159

155160
let (which, line_num) = if follow {
@@ -171,7 +176,7 @@ fn parse_expected(
171176

172177
debug!(
173178
"line={} tag={:?} which={:?} kind={:?} msg={:?}",
174-
line_num, tag, which, kind, msg
179+
line_num, &captures[0], which, kind, msg
175180
);
176181
Some((
177182
which,

0 commit comments

Comments
 (0)