Auto merge of #61778 - petrochenkov:pass, r=Mark-Simulacrum

compiletest: Introduce `// {check,build,run}-pass` pass modes

Pass UI tests now have three modes
```
// check-pass
// build-pass
// run-pass
```
mirroring equivalent well-known `cargo` commands.

`// check-pass` will compile the test skipping codegen (which is expensive and isn't supposed to fail in most cases).
`// build-pass` will compile and link the test without running it.
`// run-pass` will compile, link and run the test.
Tests without a "pass" annotation are still considered "fail" tests.

Most UI tests would probably want to switch to `check-pass`.
Tests validating codegen would probably want to run the generated code as well and use `run-pass`.
`build-pass` should probably be rare (linking tests?).

https://github.com/rust-lang/rust/pull/61755 will provide a way to run the tests with any mode, e.g. bump `check-pass` tests to `run-pass` to satisfy especially suspicious people, and be able to make sure that codegen doesn't breaks in some entirely unexpected way.
Tests marked with any mode are expected to pass with any other mode, if that's not the case for some legitimate reason, then the test should be made a "fail" test rather than a "pass" test.
Perhaps some secondary CI can verify this invariant, but that's not super urgent.

`// compile-pass` still works and is equivalent to `build-pass`.
Why is `// compile-pass` bad - 1) it gives an impression that the test is only compiled, but not linked, 2) it doesn't mirror a cargo command.
It can be removed some time in the future in a separate PR.

cc https://github.com/rust-lang/rust/issues/61712
This commit is contained in:
bors 2019-06-23 17:16:22 +00:00
commit 2cd5ed495c
67 changed files with 390 additions and 479 deletions

View File

@ -2,7 +2,7 @@
// rustc_on_unimplemented, but with this bug we are seeing it fire (on
// subsequent runs) if incremental compilation is enabled.
// revisions: rpass1 rpass2
// revisions: cfail1 cfail2
// compile-pass
#![feature(on_unimplemented)]

View File

@ -3,7 +3,7 @@
// seeing it fire (on subsequent runs) if incremental compilation is
// enabled.
// revisions: rpass1 rpass2
// revisions: cfail1 cfail2
// compile-pass
#![feature(rustc_attrs)]

View File

@ -1,6 +1,6 @@
// revisions:rpass1 rpass2
// revisions:cfail1 cfail2
// check-pass
// compile-flags: --crate-type cdylib
// skip-codegen
#![deny(unused_attributes)]

View File

@ -1,4 +1,4 @@
// compile-pass
// error-pattern:returned Box<dyn Error> from main()
// failure-status: 1
use std::error::Error;

View File

@ -1,4 +1,4 @@
// compile-pass
// error-pattern:returned Box<Error> from main()
// failure-status: 1
use std::io::{Error, ErrorKind};

View File

@ -1,7 +0,0 @@
// Test that with the `skip-codegen` option the test isn't executed.
// skip-codegen
fn main() {
unreachable!();
}

View File

@ -1,3 +1,4 @@
// check-pass
// ignore-android
// ignore-arm
// ignore-aarch64
@ -11,14 +12,11 @@
// ignore-mips
// ignore-mips64
// compile-pass
// skip-codegen
#![feature(asm)]
#![allow(dead_code, non_upper_case_globals)]
#[cfg(any(target_arch = "x86",
target_arch = "x86_64"))]
pub fn main() {
fn main() {
// assignment not dead
let mut x: isize = 0;
unsafe {

View File

@ -1,11 +1,11 @@
warning: unrecognized option
--> $DIR/asm-misplaced-option.rs:26:64
--> $DIR/asm-misplaced-option.rs:24:64
|
LL | asm!("mov $1, $0" : "=r"(x) : "r"(5_usize), "0"(x) : : "cc");
| ^^^^
warning: expected a clobber, found an option
--> $DIR/asm-misplaced-option.rs:33:80
--> $DIR/asm-misplaced-option.rs:31:80
|
LL | asm!("add $2, $1; mov $1, $0" : "=r"(x) : "r"(x), "r"(8_usize) : "cc", "volatile");
| ^^^^^^^^^^

View File

@ -1,10 +1,10 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
pub type ParseResult<T> = Result<T, ()>;
pub enum Item<'a> { Literal(&'a str),
}
pub enum Item<'a> {
Literal(&'a str)
}
pub fn colon_or_space(s: &str) -> ParseResult<&str> {
unimplemented!()
@ -20,10 +20,9 @@ pub fn parse<'a, I>(mut s: &str, items: I) -> ParseResult<()>
macro_rules! try_consume {
($e:expr) => ({ let (s_, v) = try!($e); s = s_; v })
}
let offset = try_consume!(timezone_offset_zulu(s.trim_left(), colon_or_space));
let offset = try_consume!(timezone_offset_zulu(s.trim_left(), colon_or_space));
let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space));
let offset = try_consume!(timezone_offset_zulu(s.trim_start(), colon_or_space));
Ok(())
}
fn main() { }
fn main() {}

View File

@ -1,10 +1,9 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// Check that you are allowed to implement using elision but write
// trait without elision (a bug in this cropped up during
// bootstrapping, so this is a regression test).
// check-pass
pub struct SplitWhitespace<'a> {
x: &'a u8
}

View File

@ -1,10 +1,9 @@
// check-pass
// compile-flags: --cap-lints warn
#![warn(unused)]
#![deny(warnings)]
// compile-pass
// skip-codegen
use std::option; //~ WARN
fn main() {}

View File

@ -5,7 +5,7 @@ LL | use std::option;
| ^^^^^^^^^^^
|
note: lint level defined here
--> $DIR/bad-lint-cap3.rs:4:9
--> $DIR/bad-lint-cap3.rs:5:9
|
LL | #![deny(warnings)]
| ^^^^^^^^

View File

@ -1,11 +1,10 @@
// compile-pass
// skip-codegen
// Here we do not get a coherence conflict because `Baz: Iterator`
// does not hold and (due to the orphan rules), we can rely on that.
// check-pass
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
#![allow(dead_code)]
// Here we do not get a coherence conflict because `Baz: Iterator`
// does not hold and (due to the orphan rules), we can rely on that.
pub trait Foo<P> {}
@ -18,5 +17,4 @@ impl Foo<i32> for Baz { }
impl<A:Iterator> Foo<A::Item> for A { }
fn main() {}

View File

@ -1,8 +1,8 @@
// compile-pass
// skip-codegen
// check-pass
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
pub trait Foo<P> {}
pub trait Bar {
@ -17,5 +17,4 @@ impl Bar for i32 {
type Output = u32;
}
fn main() {}

View File

@ -1,13 +1,11 @@
// Test that we are able to introduce a negative constraint that
// `MyType: !MyTrait` along with other "fundamental" wrappers.
// check-pass
// aux-build:coherence_copy_like_lib.rs
// compile-pass
// skip-codegen
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
#![allow(dead_code)]
extern crate coherence_copy_like_lib as lib;
@ -23,5 +21,4 @@ impl<T: lib::MyCopy> MyTrait for T { }
// Huzzah.
impl<'a> MyTrait for lib::MyFundamentalStruct<&'a MyType> { }
fn main() { }

View File

@ -1,13 +1,11 @@
// Test that we are able to introduce a negative constraint that
// `MyType: !MyTrait` along with other "fundamental" wrappers.
// check-pass
// aux-build:coherence_copy_like_lib.rs
// compile-pass
// skip-codegen
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
#![allow(dead_code)]
extern crate coherence_copy_like_lib as lib;
@ -22,5 +20,4 @@ impl lib::MyCopy for Box<MyType> { }
impl lib::MyCopy for lib::MyFundamentalStruct<MyType> { }
impl lib::MyCopy for lib::MyFundamentalStruct<Box<MyType>> { }
fn main() { }
fn main() {}

View File

@ -1,13 +1,11 @@
// Test that we are able to introduce a negative constraint that
// `MyType: !MyTrait` along with other "fundamental" wrappers.
// check-pass
// aux-build:coherence_copy_like_lib.rs
// compile-pass
// skip-codegen
// revisions: old re
#![cfg_attr(re, feature(re_rebalance_coherence))]
#![allow(dead_code)]
extern crate coherence_copy_like_lib as lib;
@ -16,5 +14,4 @@ struct MyType { x: i32 }
// naturally, legal
impl lib::MyCopy for MyType { }
fn main() { }

View File

@ -1,13 +1,12 @@
// compile-pass
// skip-codegen
#![allow(dead_code)]
// check-pass
#![deny(unused_attributes)] // c.f #35584
mod auxiliary {
#[cfg_attr(any(), path = "nonexistent_file.rs")] pub mod namespaced_enums;
#[cfg_attr(all(), path = "namespaced_enums.rs")] pub mod nonexistent_file;
}
fn main() {
let _ = auxiliary::namespaced_enums::Foo::A;
let _ = auxiliary::nonexistent_file::Foo::A;

View File

@ -1,4 +1,3 @@
// compile-pass
// run-pass
#![feature(const_fn_union)]

View File

@ -1,4 +1,3 @@
// compile-pass
// run-pass
enum Foo {

View File

@ -1,15 +1,12 @@
// Test use of const fn from another crate without a feature gate.
// compile-pass
// skip-codegen
#![allow(unused_variables)]
// check-pass
// aux-build:const_fn_lib.rs
extern crate const_fn_lib;
use const_fn_lib::foo;
fn main() {
let x = foo(); // use outside a constant is ok
}

View File

@ -1,5 +1,4 @@
// skip-codegen
// compile-pass
// check-pass
macro_rules! mac {
{} => {
@ -19,5 +18,4 @@ macro_rules! mac {
mac! {}
fn main() {}

View File

@ -30,8 +30,9 @@
// inputs are handled by each, and (2.) to ease searching for related
// occurrences in the source text.
// check-pass
#![warn(unused_attributes, unknown_lints)]
#![allow(stable_features)]
// UNGATED WHITE-LISTED BUILT-IN ATTRIBUTES
@ -75,7 +76,7 @@
// see issue-43106-gating-of-stable.rs
// see issue-43106-gating-of-unstable.rs
// see issue-43106-gating-of-deprecated.rs
#![windows_subsystem = "1000"]
#![windows_subsystem = "windows"]
// UNGATED CRATE-LEVEL BUILT-IN ATTRIBUTES
@ -539,7 +540,7 @@ mod export_name {
#[export_name = "2200"] impl S { }
}
// Note that this test has a `skip-codegen`, so it
// Note that this is a `check-pass` test, so it
// will never invoke the linker. These are here nonetheless to point
// out that we allow them at non-crate-level (though I do not know
// whether they have the same effect here as at crate-level).
@ -611,17 +612,17 @@ mod must_use {
#[must_use] impl S { }
}
#[windows_subsystem = "1000"]
#[windows_subsystem = "windows"]
mod windows_subsystem {
mod inner { #![windows_subsystem="1000"] }
mod inner { #![windows_subsystem="windows"] }
#[windows_subsystem = "1000"] fn f() { }
#[windows_subsystem = "windows"] fn f() { }
#[windows_subsystem = "1000"] struct S;
#[windows_subsystem = "windows"] struct S;
#[windows_subsystem = "1000"] type T = S;
#[windows_subsystem = "windows"] type T = S;
#[windows_subsystem = "1000"] impl S { }
#[windows_subsystem = "windows"] impl S { }
}
// BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES

View File

@ -5,8 +5,7 @@
//
// (For non-crate-level cases, see issue-43106-gating-of-builtin-attrs.rs)
// compile-pass
// skip-codegen
// check-pass
#![deprecated]

View File

@ -1,5 +1,5 @@
// compile-pass
// skip-codegen
// check-pass
mod foo {
pub use bar::*;
pub use main as f;
@ -15,5 +15,4 @@ mod baz {
pub use super::*;
}
pub fn main() {}

View File

@ -1,8 +1,8 @@
// check-pass
// ignore-pretty pretty-printing is unhygienic
#![feature(decl_macro, associated_type_defaults)]
// compile-pass
// skip-codegen
trait Base {
type AssocTy;
fn f();
@ -35,5 +35,4 @@ macro mac() {
mac!();
fn main() {}

View File

@ -1,10 +1,8 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
// This used to ICE because the "if" being unreachable was not handled correctly
fn err() {
if loop {} {}
}
fn main() {}

View File

@ -1,10 +1,8 @@
// check-pass
// aux-build:import_crate_var.rs
// compile-pass
// skip-codegen
#[macro_use] extern crate import_crate_var;
fn main() {
m!();
//~^ WARN `$crate` may not be imported

View File

@ -1,5 +1,5 @@
warning: `$crate` may not be imported
--> $DIR/import-crate-var.rs:9:5
--> $DIR/import-crate-var.rs:7:5
|
LL | m!();
| ^^^^^

View File

@ -1,6 +1,5 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
struct Attr {
name: String,
value: String,
@ -21,7 +20,6 @@ impl Element {
}
}
fn main() {
let element = Element { attrs: Vec::new() };
let _ = unsafe { element.get_attr("foo") };

View File

@ -1,10 +1,9 @@
// compile-pass
// skip-codegen
// check-pass
fn cb<'a,T>(_x: Box<dyn Fn((&'a i32, &'a (Vec<&'static i32>, bool))) -> T>) -> T {
panic!()
}
fn main() {
cb(Box::new(|(k, &(ref v, b))| (*k, v.clone(), b)));
}

View File

@ -1,9 +1,6 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
trait A<T> {}
struct B<T> where B<T>: A<B<T>> { t: T }
fn main() {
}
fn main() {}

View File

@ -1,6 +1,7 @@
// skip-codegen
// compile-pass
// check-pass
#![feature(unboxed_closures, fn_traits)]
struct Foo;
impl<A> FnOnce<(A,)> for Foo {

View File

@ -1,6 +1,7 @@
// compile-pass
// skip-codegen
// check-pass
#![feature(unboxed_closures, fn_traits)]
fn main() {
let k = |x: i32| { x + 1 };
Fn::call(&k, (0,));

View File

@ -1,6 +1,5 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
struct CNFParser {
token: char,
}
@ -14,12 +13,11 @@ impl CNFParser {
self.consume_while(&(CNFParser::is_whitespace))
}
fn consume_while(&mut self, p: &Fn(char) -> bool) {
fn consume_while(&mut self, p: &dyn Fn(char) -> bool) {
while p(self.token) {
return
}
}
}
fn main() {}

View File

@ -1,5 +1,5 @@
// compile-pass
// skip-codegen
// check-pass
mod a {
pub mod b { pub struct Foo; }
@ -11,7 +11,6 @@ mod a {
pub use self::c::*;
}
fn main() {
let _ = a::c::Bar(a::b::Foo);
let _ = a::Bar(a::b::Foo);

View File

@ -1,6 +1,5 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
trait Mirror {
type It;
}
@ -9,8 +8,6 @@ impl<T> Mirror for T {
type It = Self;
}
fn main() {
let c: <u32 as Mirror>::It = 5;
const CCCC: <u32 as Mirror>::It = 5;

View File

@ -1,10 +1,8 @@
// compile-pass
// skip-codegen
#![allow(unused)]
// check-pass
extern crate core;
use core as core_export;
use self::x::*;
mod x {}
fn main() {}

View File

@ -1,5 +1,4 @@
// compile-pass
// skip-codegen
// check-pass
use std::marker::PhantomData;
@ -17,5 +16,4 @@ pub trait Bar {
impl<T: 'static, W: Bar<Output = T>> Foo<*mut T> for W {}
fn main() {}

View File

@ -1,8 +1,8 @@
// compile-pass
// skip-codegen
#![deny(non_snake_case)]
#[no_mangle]
pub extern "C" fn SparklingGenerationForeignFunctionInterface() {}
// check-pass
#![deny(non_snake_case)]
#[no_mangle]
pub extern "C" fn SparklingGenerationForeignFunctionInterface() {} // OK
fn main() {}

View File

@ -1,6 +1,5 @@
// compile-pass
// skip-codegen
#![allow(dead_code)]
// check-pass
pub type T = ();
mod foo { pub use super::T; }
mod bar { pub use super::T; }
@ -15,5 +14,4 @@ mod baz {
pub use self::bar::*;
}
fn main() {}

View File

@ -1,6 +1,4 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
mod foo {
pub fn bar() {}
@ -21,5 +19,4 @@ mod b {
pub use a::bar;
}
fn main() {}

View File

@ -1,5 +1,4 @@
// compile-pass
// skip-codegen
// check-pass
pub use bar::*;
mod bar {
@ -11,5 +10,4 @@ mod baz {
pub use main as f;
}
pub fn main() {}

View File

@ -1,6 +1,4 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
macro_rules! foo { () => {
let x = 1;
@ -22,7 +20,6 @@ macro_rules! baz {
}
}
fn main() {
foo! {};
bar! {};

View File

@ -1,5 +1,4 @@
// compile-pass
// skip-codegen
// check-pass
use std::fmt;
@ -7,7 +6,6 @@ use std::fmt;
// an unsized tuple by transmuting a trait object.
fn any<T>() -> T { unreachable!() }
fn main() {
let t: &(u8, dyn fmt::Debug) = any();
println!("{:?}", &t.1);

View File

@ -1,5 +1,4 @@
// compile-pass
// skip-codegen
// check-pass
macro_rules! m {
() => { #[cfg(any())] fn f() {} }
@ -8,5 +7,4 @@ macro_rules! m {
trait T {}
impl T for () { m!(); }
fn main() {}

View File

@ -1,12 +1,10 @@
// compile-pass
// skip-codegen
// check-pass
macro_rules! null { ($i:tt) => {} }
macro_rules! apply_null {
($i:item) => { null! { $i } }
}
fn main() {
apply_null!(#[cfg(all())] fn f() {});
}

View File

@ -1,6 +1,4 @@
// compile-pass
// skip-codegen
#![allow(unused)]
// check-pass
macro_rules! make_item {
() => { fn f() {} }
@ -18,5 +16,4 @@ fn g() {
make_stmt! {}
}
fn main() {}

View File

@ -1,6 +1,4 @@
// compile-pass
// skip-codegen
#![allow(dead_code)]
// check-pass
trait RegularExpression: Sized {
type Text;
@ -18,5 +16,4 @@ enum FindCapturesInner<'r, 't> {
Dynamic(FindCaptures<'t, ExecNoSyncStr<'r>>),
}
fn main() {}

View File

@ -1,5 +1,4 @@
// compile-pass
// skip-codegen
// check-pass
use std::mem;
@ -25,7 +24,6 @@ fn foo<'a>(x: &'a ()) -> <() as Lifetime<'a>>::Out {
fn takes_lifetime(_f: for<'a> fn(&'a ()) -> <() as Lifetime<'a>>::Out) {
}
fn main() {
takes_lifetime(foo);
}

View File

@ -1,8 +1,7 @@
// Unnecessary path disambiguator is ok
// compile-pass
// skip-codegen
#![allow(unused)]
// check-pass
macro_rules! m {
($p: path) => {
let _ = $p(0);
@ -23,5 +22,4 @@ fn f() {
m!(S::<u8>);
}
fn main() {}

View File

@ -1,7 +1,5 @@
// compile-pass
// skip-codegen
// check-pass
fn _test() -> impl Default { }
fn main() { }
fn main() {}

View File

@ -1,5 +1,4 @@
// compile-pass
// skip-codegen
// check-pass
pub trait Foo {
type Bar;
@ -17,7 +16,6 @@ impl<T> Broken for T {
}
}
fn main() {
let _m: &dyn Broken<Assoc=()> = &();
}

View File

@ -1,7 +1,7 @@
// compile-pass
// skip-codegen
// check-pass
#![feature(associated_type_defaults)]
#![allow(warnings)]
trait State: Sized {
type NextState: State = StateMachineEnded;
fn execute(self) -> Option<Self::NextState>;
@ -15,6 +15,4 @@ impl State for StateMachineEnded {
}
}
fn main() {
}
fn main() {}

View File

@ -1,6 +1,6 @@
// check-pass
// ignore-emscripten
// compile-pass
// skip-codegen
#![feature(asm)]
macro_rules! interrupt_handler {
@ -12,6 +12,4 @@ macro_rules! interrupt_handler {
}
interrupt_handler!{}
fn main() {
}
fn main() {}

View File

@ -1,9 +1,7 @@
// compile-pass
// skip-codegen
// check-pass
fn foo(_: &mut i32) -> bool { true }
fn main() {
let opt = Some(92);
let mut x = 62;

View File

@ -1,10 +1,8 @@
// skip-codegen
// compile-pass
// check-pass
#![warn(unused)]
type Z = dyn for<'x> Send;
//~^ WARN type alias is never used
fn main() {
}
fn main() {}

View File

@ -1,7 +1,5 @@
// compile-pass
// skip-codegen
#![feature(associated_consts)]
#![allow(warnings)]
// check-pass
trait MyTrait {
const MY_CONST: &'static str;
}
@ -18,5 +16,4 @@ macro_rules! my_macro {
my_macro!();
fn main() {}

View File

@ -1,9 +1,7 @@
// compile-pass
// skip-codegen
// check-pass
use std::ops::Deref;
fn main() {
let _x: fn(&i32) -> <&i32 as Deref>::Target = unimplemented!();
}

View File

@ -1,6 +1,4 @@
// compile-pass
// skip-codegen
#![allow(warnings)]
// check-pass
enum E {
A = {
@ -9,5 +7,4 @@ enum E {
}
}
fn main() {}

View File

@ -1,12 +1,11 @@
// Basic test for free regions in the NLL code. This test does not
// report an error because of the (implied) bound that `'b: 'a`.
// check-pass
// compile-flags:-Zborrowck=mir -Zverbose
// compile-pass
// skip-codegen
fn foo<'a, 'b>(x: &'a &'b u32) -> &'a u32 {
&**x
}
fn main() { }
fn main() {}

View File

@ -1,5 +1,5 @@
// compile-pass
// skip-codegen
// check-pass
#![deny(unreachable_patterns)]
#![feature(exhaustive_patterns)]
#![feature(never_type)]

View File

@ -1,5 +1,5 @@
// compile-pass
// skip-codegen
// check-pass
#![deny(unreachable_patterns)]
#![feature(exhaustive_patterns)]
#![feature(never_type)]

View File

@ -1,20 +1,16 @@
// compile-pass
#![deny(single_use_lifetimes)]
#![allow(dead_code)]
#![allow(unused_variables)]
// Test that we DO NOT warn when lifetime name is used only
// once in a fn return type -- using `'_` is not legal there,
// as it must refer back to an argument.
//
// (Normally, using `'static` would be preferred, but there are
// times when that is not what you want.)
//
// run-pass
// compile-pass
#![deny(single_use_lifetimes)]
fn b<'a>() -> &'a u32 { // OK: used only in return type
&22
}
fn main() { }
fn main() {}

View File

@ -290,6 +290,13 @@ impl EarlyProps {
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum PassMode {
Check,
Build,
Run,
}
#[derive(Clone, Debug)]
pub struct TestProps {
// Lines that should be expected, in order, on standard out
@ -349,14 +356,10 @@ pub struct TestProps {
// testing harness and used when generating compilation
// arguments. (In particular, it propagates to the aux-builds.)
pub incremental_dir: Option<PathBuf>,
// Specifies that a test must actually compile without errors.
pub compile_pass: bool,
// How far should the test proceed while still passing.
pub pass_mode: Option<PassMode>,
// rustdoc will test the output of the `--test` option
pub check_test_line_numbers_match: bool,
// The test must be compiled and run successfully. Only used in UI tests for now.
pub run_pass: bool,
// Skip any codegen step and running the executable. Only for run-pass.
pub skip_codegen: bool,
// Do not pass `-Z ui-testing` to UI tests
pub disable_ui_testing_normalization: bool,
// customized normalization rules
@ -396,10 +399,8 @@ impl TestProps {
pretty_compare_only: false,
forbid_output: vec![],
incremental_dir: None,
compile_pass: false,
pass_mode: None,
check_test_line_numbers_match: false,
run_pass: false,
skip_codegen: false,
disable_ui_testing_normalization: false,
normalize_stdout: vec![],
normalize_stderr: vec![],
@ -525,18 +526,7 @@ impl TestProps {
self.check_test_line_numbers_match = config.parse_check_test_line_numbers_match(ln);
}
if !self.run_pass {
self.run_pass = config.parse_run_pass(ln);
}
if !self.compile_pass {
// run-pass implies compile_pass
self.compile_pass = config.parse_compile_pass(ln) || self.run_pass;
}
if !self.skip_codegen {
self.skip_codegen = config.parse_skip_codegen(ln);
}
self.update_pass_mode(ln, cfg, config);
if !self.disable_ui_testing_normalization {
self.disable_ui_testing_normalization =
@ -583,6 +573,41 @@ impl TestProps {
}
}
}
fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) {
let check_no_run = |s| {
if config.mode != Mode::Ui && config.mode != Mode::Incremental {
panic!("`{}` header is only supported in UI and incremental tests", s);
}
if config.mode == Mode::Incremental &&
!revision.map_or(false, |r| r.starts_with("cfail")) &&
!self.revisions.iter().all(|r| r.starts_with("cfail")) {
panic!("`{}` header is only supported in `cfail` incremental tests", s);
}
};
let pass_mode = if config.parse_name_directive(ln, "check-pass") {
check_no_run("check-pass");
Some(PassMode::Check)
} else if config.parse_name_directive(ln, "build-pass") {
check_no_run("build-pass");
Some(PassMode::Build)
} else if config.parse_name_directive(ln, "compile-pass") /* compatibility */ {
check_no_run("compile-pass");
Some(PassMode::Build)
} else if config.parse_name_directive(ln, "run-pass") {
if config.mode != Mode::Ui && config.mode != Mode::RunPass /* compatibility */ {
panic!("`run-pass` header is only supported in UI tests")
}
Some(PassMode::Run)
} else {
None
};
match (self.pass_mode, pass_mode) {
(None, Some(_)) => self.pass_mode = pass_mode,
(Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"),
(_, None) => {}
}
}
}
fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
@ -710,10 +735,6 @@ impl Config {
}
}
fn parse_compile_pass(&self, line: &str) -> bool {
self.parse_name_directive(line, "compile-pass")
}
fn parse_disable_ui_testing_normalization(&self, line: &str) -> bool {
self.parse_name_directive(line, "disable-ui-testing-normalization")
}
@ -722,14 +743,6 @@ impl Config {
self.parse_name_directive(line, "check-test-line-numbers-match")
}
fn parse_run_pass(&self, line: &str) -> bool {
self.parse_name_directive(line, "run-pass")
}
fn parse_skip_codegen(&self, line: &str) -> bool {
self.parse_name_directive(line, "skip-codegen")
}
fn parse_assembly_output(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "assembly-output")
.map(|r| r.trim().to_string())

View File

@ -10,7 +10,7 @@ use crate::common::{Config, TestPaths};
use crate::common::{Incremental, MirOpt, RunMake, Ui, JsDocTest, Assembly};
use diff;
use crate::errors::{self, Error, ErrorKind};
use crate::header::TestProps;
use crate::header::{TestProps, PassMode};
use crate::json;
use regex::{Captures, Regex};
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
@ -310,20 +310,19 @@ impl<'test> TestCx<'test> {
}
fn should_run_successfully(&self) -> bool {
let run_pass = match self.config.mode {
match self.config.mode {
RunPass => true,
Ui => self.props.run_pass,
_ => unimplemented!(),
};
return run_pass && !self.props.skip_codegen;
Ui => self.props.pass_mode == Some(PassMode::Run),
mode => panic!("unimplemented for mode {:?}", mode),
}
}
fn should_compile_successfully(&self) -> bool {
match self.config.mode {
CompileFail => self.props.compile_pass,
CompileFail => false,
RunPass => true,
JsDocTest => true,
Ui => self.props.compile_pass,
Ui => self.props.pass_mode.is_some(),
Incremental => {
let revision = self.revision
.expect("incremental tests require a list of revisions");
@ -331,7 +330,7 @@ impl<'test> TestCx<'test> {
true
} else if revision.starts_with("cfail") {
// FIXME: would be nice if incremental revs could start with "cpass"
self.props.compile_pass
self.props.pass_mode.is_some()
} else {
panic!("revision name must begin with rpass, rfail, or cfail");
}
@ -433,11 +432,9 @@ impl<'test> TestCx<'test> {
"run-pass tests with expected warnings should be moved to ui/"
);
if !self.props.skip_codegen {
let proc_res = self.exec_compiled_test();
if !proc_res.status.success() {
self.fatal_proc_rec("test run failed!", &proc_res);
}
let proc_res = self.exec_compiled_test();
if !proc_res.status.success() {
self.fatal_proc_rec("test run failed!", &proc_res);
}
}
@ -1344,7 +1341,7 @@ impl<'test> TestCx<'test> {
fn check_error_patterns(&self, output_to_check: &str, proc_res: &ProcRes) {
debug!("check_error_patterns");
if self.props.error_patterns.is_empty() {
if self.props.compile_pass {
if self.props.pass_mode.is_some() {
return;
} else {
self.fatal(&format!(
@ -1971,7 +1968,7 @@ impl<'test> TestCx<'test> {
}
}
if self.props.skip_codegen {
if self.props.pass_mode == Some(PassMode::Check) {
assert!(
!self
.props