diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 1d8cef05b7d..41fc67a66f4 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -95,6 +95,26 @@ impl fmt::Display for Mode { } } +#[derive(Clone)] +pub enum CompareMode { + Nll +} + +impl CompareMode { + fn to_str(&self) -> &'static str { + match *self { + CompareMode::Nll => "nll" + } + } + + pub fn parse(s: String) -> CompareMode { + match s.as_str() { + "nll" => CompareMode::Nll, + x => panic!("unknown --compare-mode option: {}", x), + } + } +} + #[derive(Clone)] pub struct Config { /// The library paths required for running the compiler @@ -210,6 +230,9 @@ pub struct Config { /// where to find the remote test client process, if we're using it pub remote_test_client: Option, + /// mode describing what file the actual ui output will be compared to + pub compare_mode: Option, + // Configuration for various run-make tests frobbing things like C compilers // or querying about various LLVM component information. pub cc: String, @@ -230,12 +253,19 @@ pub struct TestPaths { } /// Used by `ui` tests to generate things like `foo.stderr` from `foo.rs`. -pub fn expected_output_path(testpaths: &TestPaths, revision: Option<&str>, kind: &str) -> PathBuf { +pub fn expected_output_path(testpaths: &TestPaths, + revision: Option<&str>, + compare_mode: &Option, + kind: &str) -> PathBuf { + assert!(UI_EXTENSIONS.contains(&kind)); - let extension = match revision { - Some(r) => format!("{}.{}", r, kind), - None => kind.to_string(), - }; + let mut parts = Vec::new(); + + if let Some(x) = revision { parts.push(x); } + if let Some(ref x) = *compare_mode { parts.push(x.to_str()); } + parts.push(kind); + + let extension = parts.join("."); testpaths.file.with_extension(extension) } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index e65c03a6e57..80cab96434b 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -38,6 +38,7 @@ use getopts::Options; use common::{Config, TestPaths}; use common::{DebugInfoGdb, DebugInfoLldb, Mode, Pretty}; use common::{expected_output_path, UI_EXTENSIONS}; +use common::CompareMode; use test::ColorConfig; use util::logv; @@ -227,6 +228,12 @@ pub fn parse_config(args: Vec) -> Config { "path to the remote test client", "PATH", ) + .optopt( + "", + "compare-mode", + "mode describing what file the actual ui output will be compared to", + "COMPARE MODE" + ) .optflag("h", "help", "show this message"); let (argv0, args_) = args.split_first().unwrap(); @@ -320,6 +327,7 @@ pub fn parse_config(args: Vec) -> Config { quiet: matches.opt_present("quiet"), color, remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), + compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse), cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), @@ -615,7 +623,8 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn }; // Debugging emscripten code doesn't make sense today - let ignore = early_props.ignore || !up_to_date(config, testpaths, &early_props) + let ignore = early_props.ignore + || (!up_to_date(config, testpaths, &early_props) && config.compare_mode.is_none()) || (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb) && config.target.contains("emscripten"); @@ -688,12 +697,15 @@ fn up_to_date(config: &Config, testpaths: &TestPaths, props: &EarlyProps) -> boo // UI test files. for extension in UI_EXTENSIONS { for revision in &props.revisions { - let path = &expected_output_path(testpaths, Some(revision), extension); + let path = &expected_output_path(testpaths, + Some(revision), + &config.compare_mode, + extension); inputs.push(mtime(path)); } if props.revisions.is_empty() { - let path = &expected_output_path(testpaths, None, extension); + let path = &expected_output_path(testpaths, None, &config.compare_mode, extension); inputs.push(mtime(path)); } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e826c5366a8..0081c0ae69d 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -13,6 +13,7 @@ use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, CodegenUnits, DebugInfoGdb, DebugInfoLldb, Rustdoc}; use common::{Incremental, MirOpt, RunMake, Ui}; use common::{expected_output_path, UI_STDERR, UI_STDOUT}; +use common::CompareMode; use diff; use errors::{self, Error, ErrorKind}; use filetime::FileTime; @@ -1683,6 +1684,13 @@ impl<'test> TestCx<'test> { } } + match self.config.compare_mode { + Some(CompareMode::Nll) => { + rustc.args(&["-Znll", "-Zborrowck=mir", "-Ztwo-phase-borrows"]); + }, + None => {}, + } + if self.props.force_host { rustc.args(self.split_maybe_args(&self.config.host_rustcflags)); } else { @@ -2505,11 +2513,8 @@ impl<'test> TestCx<'test> { let proc_res = self.compile_test(); self.check_if_test_should_compile(&proc_res); - let expected_stderr_path = self.expected_output_path(UI_STDERR); - let expected_stderr = self.load_expected_output(&expected_stderr_path); - - let expected_stdout_path = self.expected_output_path(UI_STDOUT); - let expected_stdout = self.load_expected_output(&expected_stdout_path); + let expected_stderr = self.load_expected_output(UI_STDERR); + let expected_stdout = self.load_expected_output(UI_STDOUT); let normalized_stdout = self.normalize_output(&proc_res.stdout, &self.props.normalize_stdout); @@ -2552,7 +2557,7 @@ impl<'test> TestCx<'test> { self.fatal_proc_rec("test run failed!", &proc_res); } } - if !explicit { + if !explicit && self.config.compare_mode.is_none() { if !expected_errors.is_empty() || !proc_res.status.success() { // "// error-pattern" comments self.check_expected_errors(expected_errors, &proc_res); @@ -2795,19 +2800,32 @@ impl<'test> TestCx<'test> { normalized } - fn expected_output_path(&self, kind: &str) -> PathBuf { - expected_output_path(&self.testpaths, self.revision, kind) - } + fn load_expected_output(&self, kind: &str) -> String { + let mut path = expected_output_path(&self.testpaths, + self.revision, + &self.config.compare_mode, + kind); - fn load_expected_output(&self, path: &Path) -> String { - if !path.exists() { - return String::new(); + if !path.exists() && self.config.compare_mode.is_some() { + // fallback! + path = expected_output_path(&self.testpaths, self.revision, &None, kind); } + if path.exists() { + match self.load_expected_output_from_path(&path) { + Ok(x) => x, + Err(x) => self.fatal(&x), + } + } else { + String::new() + } + } + + fn load_expected_output_from_path(&self, path: &Path) -> Result { let mut result = String::new(); match File::open(path).and_then(|mut f| f.read_to_string(&mut result)) { - Ok(_) => result, - Err(e) => self.fatal(&format!( + Ok(_) => Ok(result), + Err(e) => Err(format!( "failed to load expected output from `{}`: {}", path.display(), e