Skip to content

Commit bd816fd

Browse files
committed
Auto merge of #66524 - ecstatic-morse:compiletest-multiple-revisions, r=Centril
Support multiple revisions in `compiletest` 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. While refactoring `compiletest` to support this, I also uncovered a small bug that was causing an incremental test to always pass, despite no errors being emitted. r? @Centril
2 parents abd6955 + c537f22 commit bd816fd

File tree

7 files changed

+55
-61
lines changed

7 files changed

+55
-61
lines changed

src/test/incremental/warnings-reemitted.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
// compile-flags: -Coverflow-checks=on
33
// build-pass (FIXME(62277): could be check-pass?)
44

5-
#![allow(warnings)]
65
#![warn(const_err)]
76

87
fn main() {
9-
255u8 + 1; //~ WARNING this expression will panic at run-time
8+
let _ = 255u8 + 1; //~ WARNING attempt to add with overflow
109
}

src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,4 @@ fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
4747
}
4848

4949
#[rustc_error]
50-
fn main() { }
51-
//[ok]~^ ERROR fatal error triggered by #[rustc_error]
52-
//[oneuse]~^^ ERROR fatal error triggered by #[rustc_error]
50+
fn main() { } //[ok,oneuse]~ ERROR fatal error triggered by #[rustc_error]

src/test/ui/error-codes/E0161.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,8 @@
2020

2121
fn foo(x: Box<[i32]>) {
2222
box *x;
23-
//[migrate]~^ ERROR E0161
24-
//[nll]~^^ ERROR E0161
25-
//[zflags]~^^^ ERROR E0161
26-
//[edition]~^^^^ ERROR E0161
27-
//[migrateul]~^^^^^ ERROR E0161
28-
//[nllul]~^^^^^^ ERROR E0161
29-
//[zflagsul]~^^^^^^^ ERROR E0161
30-
//[editionul]~^^^^^^^^ ERROR E0161
23+
//[migrate,nll,zflags,edition]~^ ERROR E0161
24+
//[migrateul,nllul,zflagsul,editionul]~^^ ERROR E0161
3125
}
3226

3327
fn main() {}

src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ struct Foo<T> {
1111
impl<T> Foo<T>
1212
where
1313
T: WithRegion<'_>
14-
//[rust2015]~^ ERROR `'_` cannot be used here
15-
//[rust2018]~^^ ERROR `'_` cannot be used here
14+
//[rust2015,rust2018]~^ ERROR `'_` cannot be used here
1615
{ }
1716

1817
fn main() {}

src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ trait Foo { }
99
impl<T> Foo for Vec<T>
1010
where
1111
T: WithType<&u32>
12-
//[rust2015]~^ ERROR `&` without an explicit lifetime name cannot be used here
13-
//[rust2018]~^^ ERROR `&` without an explicit lifetime name cannot be used here
12+
//[rust2015,rust2018]~^ ERROR `&` without an explicit lifetime name cannot be used here
1413
{ }
1514

1615
fn main() {}

src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ trait Foo { }
99
impl<T> Foo for Vec<T>
1010
where
1111
T: WithRegion<'_>
12-
//[rust2015]~^ ERROR `'_` cannot be used here
13-
//[rust2018]~^^ ERROR `'_` cannot be used here
12+
//[rust2015,rust2018]~^ ERROR `'_` cannot be used here
1413
{ }
1514

1615
fn main() {}

src/tools/compiletest/src/errors.rs

+48-42
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,54 @@ 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 whole_match = captures.get(0).unwrap();
146+
let (_, mut msg) = line.split_at(whole_match.end());
147+
148+
let first_word = msg
130149
.split_whitespace()
131150
.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-
}
151+
.expect("Encountered unexpected empty comment");
152+
153+
// If we find `//~ ERROR foo` or something like that, skip the first word.
154+
let kind = first_word.parse::<ErrorKind>().ok();
155+
if let Some(_) = kind {
156+
msg = &msg.trim_start().split_at(first_word.len()).1;
152157
}
158+
153159
let msg = msg.trim().to_owned();
154160

155161
let (which, line_num) = if follow {
@@ -171,7 +177,7 @@ fn parse_expected(
171177

172178
debug!(
173179
"line={} tag={:?} which={:?} kind={:?} msg={:?}",
174-
line_num, tag, which, kind, msg
180+
line_num, whole_match.as_str(), which, kind, msg
175181
);
176182
Some((
177183
which,

0 commit comments

Comments
 (0)