about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-11-22 04:06:52 +0000
committerbors <bors@rust-lang.org>2019-11-22 04:06:52 +0000
commitbd816fd76f4f7a040ca7ac8ca5bc556d761f96fa (patch)
tree0bfe068351cf25b176f2d8ab16c43ae33eb69f68 /src
parentabd69551bf8b8755b5e00d4f4d45ae5d4a0cd17d (diff)
parentc537f229009bcec23ac89132fd6f571acbc23c38 (diff)
downloadrust-bd816fd76f4f7a040ca7ac8ca5bc556d761f96fa.tar.gz
rust-bd816fd76f4f7a040ca7ac8ca5bc556d761f96fa.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/test/incremental/warnings-reemitted.rs3
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs4
-rw-r--r--src/test/ui/error-codes/E0161.rs10
-rw-r--r--src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs3
-rw-r--r--src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs3
-rw-r--r--src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs3
-rw-r--r--src/tools/compiletest/src/errors.rs90
7 files changed, 55 insertions, 61 deletions
diff --git a/src/test/incremental/warnings-reemitted.rs b/src/test/incremental/warnings-reemitted.rs
index a1d11f8aa5b..5fc89395827 100644
--- a/src/test/incremental/warnings-reemitted.rs
+++ b/src/test/incremental/warnings-reemitted.rs
@@ -2,9 +2,8 @@
 // compile-flags: -Coverflow-checks=on
 // build-pass (FIXME(62277): could be check-pass?)
 
-#![allow(warnings)]
 #![warn(const_err)]
 
 fn main() {
-    255u8 + 1; //~ WARNING this expression will panic at run-time
+    let _ = 255u8 + 1; //~ WARNING attempt to add with overflow
 }
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs
index ebf52918153..8c6073e2f7a 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs
+++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.rs
@@ -47,6 +47,4 @@ fn transmute<'a,'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
 }
 
 #[rustc_error]
-fn main() { }
-//[ok]~^ ERROR fatal error triggered by #[rustc_error]
-//[oneuse]~^^ ERROR fatal error triggered by #[rustc_error]
+fn main() { } //[ok,oneuse]~ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/error-codes/E0161.rs b/src/test/ui/error-codes/E0161.rs
index 2ca17050ae2..58217ff74b8 100644
--- a/src/test/ui/error-codes/E0161.rs
+++ b/src/test/ui/error-codes/E0161.rs
@@ -20,14 +20,8 @@
 
 fn foo(x: Box<[i32]>) {
     box *x;
-    //[migrate]~^ ERROR E0161
-    //[nll]~^^ ERROR E0161
-    //[zflags]~^^^ ERROR E0161
-    //[edition]~^^^^ ERROR E0161
-    //[migrateul]~^^^^^ ERROR E0161
-    //[nllul]~^^^^^^ ERROR E0161
-    //[zflagsul]~^^^^^^^ ERROR E0161
-    //[editionul]~^^^^^^^^ ERROR E0161
+    //[migrate,nll,zflags,edition]~^ ERROR E0161
+    //[migrateul,nllul,zflagsul,editionul]~^^ ERROR E0161
 }
 
 fn main() {}
diff --git a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs
index b50cce335bd..38189816da8 100644
--- a/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs
+++ b/src/test/ui/underscore-lifetime/where-clause-inherent-impl-underscore.rs
@@ -11,8 +11,7 @@ struct Foo<T> {
 impl<T> Foo<T>
 where
     T: WithRegion<'_>
-//[rust2015]~^ ERROR `'_` cannot be used here
-//[rust2018]~^^ ERROR `'_` cannot be used here
+//[rust2015,rust2018]~^ ERROR `'_` cannot be used here
 { }
 
 fn main() {}
diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs
index f2d483e66e0..09e5bbd846d 100644
--- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs
+++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-region.rs
@@ -9,8 +9,7 @@ trait Foo { }
 impl<T> Foo for Vec<T>
 where
     T: WithType<&u32>
-//[rust2015]~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[rust2018]~^^ ERROR `&` without an explicit lifetime name cannot be used here
+//[rust2015,rust2018]~^ ERROR `&` without an explicit lifetime name cannot be used here
 { }
 
 fn main() {}
diff --git a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs
index 94e4426e822..371d2e4ba43 100644
--- a/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs
+++ b/src/test/ui/underscore-lifetime/where-clause-trait-impl-underscore.rs
@@ -9,8 +9,7 @@ trait Foo { }
 impl<T> Foo for Vec<T>
 where
     T: WithRegion<'_>
-//[rust2015]~^ ERROR `'_` cannot be used here
-//[rust2018]~^^ ERROR `'_` cannot be used here
+//[rust2015,rust2018]~^ ERROR `'_` cannot be used here
 { }
 
 fn main() {}
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index 5b3936ffc1e..0ec2738181e 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -7,7 +7,9 @@ use std::io::BufReader;
 use std::path::Path;
 use std::str::FromStr;
 
+use lazy_static::lazy_static;
 use log::*;
+use regex::Regex;
 
 #[derive(Clone, Debug, PartialEq)]
 pub enum ErrorKind {
@@ -85,20 +87,16 @@ pub fn load_errors(testfile: &Path, cfg: Option<&str>) -> Vec<Error> {
     // updating it in the map callback below.)
     let mut last_nonfollow_error = None;
 
-    let tag = match cfg {
-        Some(rev) => format!("//[{}]~", rev),
-        None => "//~".to_string(),
-    };
-
     rdr.lines()
         .enumerate()
         .filter_map(|(line_num, line)| {
-            parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), &tag).map(
+            parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), cfg).map(
                 |(which, error)| {
                     match which {
                         FollowPrevious(_) => {}
                         _ => last_nonfollow_error = Some(error.line_num),
                     }
+
                     error
                 },
             )
@@ -110,46 +108,54 @@ fn parse_expected(
     last_nonfollow_error: Option<usize>,
     line_num: usize,
     line: &str,
-    tag: &str,
+    cfg: Option<&str>,
 ) -> Option<(WhichLine, Error)> {
-    let start = line.find(tag)?;
-    let (follow, adjusts) = if line[start + tag.len()..].chars().next().unwrap() == '|' {
-        (true, 0)
-    } else {
-        (
-            false,
-            line[start + tag.len()..]
-                .chars()
-                .take_while(|c| *c == '^')
-                .count(),
-        )
+    // Matches comments like:
+    //     //~
+    //     //~|
+    //     //~^
+    //     //~^^^^^
+    //     //[cfg1]~
+    //     //[cfg1,cfg2]~^^
+    lazy_static! {
+        static ref RE: Regex =
+            Regex::new(r"//(?:\[(?P<cfgs>[\w,]+)])?~(?P<adjust>\||\^*)").unwrap();
+    }
+
+    let captures = RE.captures(line)?;
+
+    match (cfg, captures.name("cfgs")) {
+        // Only error messages that contain our `cfg` betweeen the square brackets apply to us.
+        (Some(cfg), Some(filter)) if !filter.as_str().split(',').any(|s| s == cfg)
+            => return None,
+        (Some(_), Some(_)) => {}
+
+        (None, Some(_)) => panic!("Only tests with revisions should use `//[X]~`"),
+
+        // If an error has no list of revisions, it applies to all revisions.
+        (Some(_), None) | (None, None) => {}
+    }
+
+    let (follow, adjusts) = match &captures["adjust"] {
+        "|" => (true, 0),
+        circumflexes => (false, circumflexes.len()),
     };
-    let kind_start = start + tag.len() + adjusts + (follow as usize);
-    let (kind, msg);
-    match line[kind_start..]
+
+    // Get the part of the comment after the sigil (e.g. `~^^` or ~|).
+    let whole_match = captures.get(0).unwrap();
+    let (_, mut msg) = line.split_at(whole_match.end());
+
+    let first_word = msg
         .split_whitespace()
         .next()
-        .expect("Encountered unexpected empty comment")
-        .parse::<ErrorKind>()
-    {
-        Ok(k) => {
-            // If we find `//~ ERROR foo` or something like that:
-            kind = Some(k);
-            let letters = line[kind_start..].chars();
-            msg = letters
-                .skip_while(|c| c.is_whitespace())
-                .skip_while(|c| !c.is_whitespace())
-                .collect::<String>();
-        }
-        Err(_) => {
-            // Otherwise we found `//~ foo`:
-            kind = None;
-            let letters = line[kind_start..].chars();
-            msg = letters
-                .skip_while(|c| c.is_whitespace())
-                .collect::<String>();
-        }
+        .expect("Encountered unexpected empty comment");
+
+    // If we find `//~ ERROR foo` or something like that, skip the first word.
+    let kind = first_word.parse::<ErrorKind>().ok();
+    if let Some(_) = kind {
+        msg = &msg.trim_start().split_at(first_word.len()).1;
     }
+
     let msg = msg.trim().to_owned();
 
     let (which, line_num) = if follow {
@@ -171,7 +177,7 @@ fn parse_expected(
 
     debug!(
         "line={} tag={:?} which={:?} kind={:?} msg={:?}",
-        line_num, tag, which, kind, msg
+        line_num, whole_match.as_str(), which, kind, msg
     );
     Some((
         which,