]> git.proxmox.com Git - rustc.git/blobdiff - src/tools/compiletest/src/runtest.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / src / tools / compiletest / src / runtest.rs
index 424bac88c8531f1623858cf268440e451312134c..61a7d8ee5c948984940880f835795414dfa22829 100644 (file)
@@ -11,6 +11,7 @@ use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT};
 use crate::errors::{self, Error, ErrorKind};
 use crate::header::TestProps;
 use crate::json;
+use crate::util::get_pointer_width;
 use crate::util::{logv, PathBufExt};
 use diff;
 use regex::{Captures, Regex};
@@ -20,7 +21,6 @@ use std::collections::hash_map::DefaultHasher;
 use std::collections::{HashMap, HashSet, VecDeque};
 use std::env;
 use std::ffi::{OsStr, OsString};
-use std::fmt;
 use std::fs::{self, create_dir_all, File, OpenOptions};
 use std::hash::{Hash, Hasher};
 use std::io::prelude::*;
@@ -178,6 +178,29 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma
     results
 }
 
+fn print_diff(expected: &str, actual: &str, context_size: usize) {
+    let diff_results = make_diff(expected, actual, context_size);
+    for result in diff_results {
+        let mut line_number = result.line_number;
+        for line in result.lines {
+            match line {
+                DiffLine::Expected(e) => {
+                    println!("-\t{}", e);
+                    line_number += 1;
+                }
+                DiffLine::Context(c) => {
+                    println!("{}\t{}", line_number, c);
+                    line_number += 1;
+                }
+                DiffLine::Resulting(r) => {
+                    println!("+\t{}", r);
+                }
+            }
+        }
+        println!();
+    }
+}
+
 pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
     match &*config.target {
         "arm-linux-androideabi"
@@ -334,14 +357,15 @@ impl<'test> TestCx<'test> {
             Ui if pm == Some(PassMode::Run) || self.props.fail_mode == Some(FailMode::Run) => {
                 WillExecute::Yes
             }
-            Ui => WillExecute::No,
+            MirOpt if pm == Some(PassMode::Run) => WillExecute::Yes,
+            Ui | MirOpt => WillExecute::No,
             mode => panic!("unimplemented for mode {:?}", mode),
         }
     }
 
     fn should_run_successfully(&self, pm: Option<PassMode>) -> bool {
         match self.config.mode {
-            Ui => pm == Some(PassMode::Run),
+            Ui | MirOpt => pm == Some(PassMode::Run),
             mode => panic!("unimplemented for mode {:?}", mode),
         }
     }
@@ -1852,7 +1876,6 @@ impl<'test> TestCx<'test> {
             if let Some(ref incremental_dir) = self.props.incremental_dir {
                 rustc.args(&["-C", &format!("incremental={}", incremental_dir.display())]);
                 rustc.args(&["-Z", "incremental-verify-ich"]);
-                rustc.args(&["-Z", "incremental-queries"]);
             }
 
             if self.config.mode == CodegenUnits {
@@ -1936,6 +1959,12 @@ impl<'test> TestCx<'test> {
             None => {}
         }
 
+        // Add `-A unused` before `config` flags and in-test (`props`) flags, so that they can
+        // overwrite this.
+        if let AllowUnused::Yes = allow_unused {
+            rustc.args(&["-A", "unused"]);
+        }
+
         if self.props.force_host {
             self.maybe_add_external_args(
                 &mut rustc,
@@ -1958,10 +1987,6 @@ impl<'test> TestCx<'test> {
             rustc.arg("-Ctarget-feature=-crt-static");
         }
 
-        if let AllowUnused::Yes = allow_unused {
-            rustc.args(&["-A", "unused"]);
-        }
-
         rustc.args(&self.props.compile_flags);
 
         rustc
@@ -2490,7 +2515,7 @@ impl<'test> TestCx<'test> {
                     .filter(|s| !s.is_empty())
                     .map(|s| {
                         if cgu_has_crate_disambiguator {
-                            remove_crate_disambiguator_from_cgu(s)
+                            remove_crate_disambiguators_from_set_of_cgu_names(s)
                         } else {
                             s.to_string()
                         }
@@ -2540,6 +2565,16 @@ impl<'test> TestCx<'test> {
 
             new_name
         }
+
+        // The name of merged CGUs is constructed as the names of the original
+        // CGUs joined with "--". This function splits such composite CGU names
+        // and handles each component individually.
+        fn remove_crate_disambiguators_from_set_of_cgu_names(cgus: &str) -> String {
+            cgus.split("--")
+                .map(|cgu| remove_crate_disambiguator_from_cgu(cgu))
+                .collect::<Vec<_>>()
+                .join("--")
+        }
     }
 
     fn init_incremental_test(&self) {
@@ -2571,12 +2606,12 @@ impl<'test> TestCx<'test> {
         //   - if `cfail`, expect compilation to fail
         //   - if `rfail`, expect execution to fail
         // - create a directory build/foo/bar.incremental
-        // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C rpass1
+        // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1
         //   - because name of revision starts with "rpass", expect success
-        // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C cfail2
+        // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C cfail2
         //   - because name of revision starts with "cfail", expect an error
         //   - load expected errors as usual, but filter for those that end in `[rfail2]`
-        // - compile foo/bar.rs with -Z incremental=.../foo/bar.incremental and -C rpass3
+        // - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass3
         //   - because name of revision starts with "rpass", expect success
         // - execute build/foo/bar.exe and save output
         //
@@ -2775,11 +2810,17 @@ impl<'test> TestCx<'test> {
             self.document(&out_dir);
 
             let root = self.config.find_rust_src_root().unwrap();
+            let file_stem =
+                self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem");
             let res = self.cmd2procres(
                 Command::new(&nodejs)
                     .arg(root.join("src/tools/rustdoc-js/tester.js"))
-                    .arg(out_dir.parent().expect("no parent"))
-                    .arg(&self.testpaths.file.file_stem().expect("couldn't get file stem")),
+                    .arg("--doc-folder")
+                    .arg(out_dir)
+                    .arg("--crate-name")
+                    .arg(file_stem.replace("-", "_"))
+                    .arg("--test-file")
+                    .arg(self.testpaths.file.with_extension("js")),
             );
             if !res.status.success() {
                 self.fatal_proc_rec("rustdoc-js test failed!", &res);
@@ -3025,48 +3066,107 @@ impl<'test> TestCx<'test> {
     }
 
     fn run_mir_opt_test(&self) {
-        let proc_res = self.compile_test(WillExecute::Yes, EmitMetadata::No);
+        let pm = self.pass_mode();
+        let should_run = self.should_run(pm);
+        let emit_metadata = self.should_emit_metadata(pm);
+        let proc_res = self.compile_test(should_run, emit_metadata);
 
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
-        let proc_res = self.exec_compiled_test();
+        self.check_mir_dump();
 
-        if !proc_res.status.success() {
-            self.fatal_proc_rec("test run failed!", &proc_res);
+        if let WillExecute::Yes = should_run {
+            let proc_res = self.exec_compiled_test();
+
+            if !proc_res.status.success() {
+                self.fatal_proc_rec("test run failed!", &proc_res);
+            }
         }
-        self.check_mir_dump();
     }
 
     fn check_mir_dump(&self) {
         let test_file_contents = fs::read_to_string(&self.testpaths.file).unwrap();
-        if let Some(idx) = test_file_contents.find("// END RUST SOURCE") {
-            let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len());
-            let tests_text_str = String::from(tests_text);
-            let mut curr_test: Option<&str> = None;
-            let mut curr_test_contents = vec![ExpectedLine::Elision];
-            for l in tests_text_str.lines() {
-                debug!("line: {:?}", l);
-                if l.starts_with("// START ") {
-                    let (_, t) = l.split_at("// START ".len());
-                    curr_test = Some(t);
-                } else if l.starts_with("// END") {
-                    let (_, t) = l.split_at("// END ".len());
-                    if Some(t) != curr_test {
-                        panic!("mismatched START END test name");
+
+        let mut test_dir = self.testpaths.file.with_extension("");
+
+        if test_file_contents.lines().any(|l| l == "// EMIT_MIR_FOR_EACH_BIT_WIDTH") {
+            test_dir.push(get_pointer_width(&self.config.target))
+        }
+
+        if self.config.bless {
+            let _ = std::fs::remove_dir_all(&test_dir);
+        }
+        for l in test_file_contents.lines() {
+            if l.starts_with("// EMIT_MIR ") {
+                let test_name = l.trim_start_matches("// EMIT_MIR ");
+                let expected_file = test_dir.join(test_name);
+
+                let dumped_string = if test_name.ends_with(".diff") {
+                    let test_name = test_name.trim_end_matches(".diff");
+                    let before = format!("{}.before.mir", test_name);
+                    let after = format!("{}.after.mir", test_name);
+                    let before = self.get_mir_dump_dir().join(before);
+                    let after = self.get_mir_dump_dir().join(after);
+                    debug!(
+                        "comparing the contents of: {} with {}",
+                        before.display(),
+                        after.display()
+                    );
+                    let before = fs::read_to_string(before).unwrap();
+                    let after = fs::read_to_string(after).unwrap();
+                    let before = self.normalize_output(&before, &[]);
+                    let after = self.normalize_output(&after, &[]);
+                    let mut dumped_string = String::new();
+                    for result in diff::lines(&before, &after) {
+                        use std::fmt::Write;
+                        match result {
+                            diff::Result::Left(s) => writeln!(dumped_string, "- {}", s).unwrap(),
+                            diff::Result::Right(s) => writeln!(dumped_string, "+ {}", s).unwrap(),
+                            diff::Result::Both(s, _) => writeln!(dumped_string, "  {}", s).unwrap(),
+                        }
+                    }
+                    dumped_string
+                } else {
+                    let mut output_file = PathBuf::new();
+                    output_file.push(self.get_mir_dump_dir());
+                    output_file.push(test_name);
+                    debug!(
+                        "comparing the contents of: {} with {}",
+                        output_file.display(),
+                        expected_file.display()
+                    );
+                    if !output_file.exists() {
+                        panic!(
+                            "Output file `{}` from test does not exist, available files are in `{}`",
+                            output_file.display(),
+                            output_file.parent().unwrap().display()
+                        );
+                    }
+                    self.check_mir_test_timestamp(test_name, &output_file);
+                    let dumped_string = fs::read_to_string(&output_file).unwrap();
+                    self.normalize_output(&dumped_string, &[])
+                };
+                if self.config.bless {
+                    let _ = std::fs::create_dir_all(&test_dir);
+                    let _ = std::fs::remove_file(&expected_file);
+                    std::fs::write(expected_file, dumped_string.as_bytes()).unwrap();
+                } else {
+                    if !expected_file.exists() {
+                        panic!(
+                            "Output file `{}` from test does not exist",
+                            expected_file.display()
+                        );
+                    }
+                    let expected_string = fs::read_to_string(&expected_file).unwrap();
+                    if dumped_string != expected_string {
+                        print_diff(&expected_string, &dumped_string, 3);
+                        panic!(
+                            "Actual MIR output differs from expected MIR output {}",
+                            expected_file.display()
+                        );
                     }
-                    self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents);
-                    curr_test = None;
-                    curr_test_contents.clear();
-                    curr_test_contents.push(ExpectedLine::Elision);
-                } else if l.is_empty() {
-                    // ignore
-                } else if l.starts_with("//") && l.split_at("//".len()).1.trim() == "..." {
-                    curr_test_contents.push(ExpectedLine::Elision)
-                } else if l.starts_with("// ") {
-                    let (_, test_content) = l.split_at("// ".len());
-                    curr_test_contents.push(ExpectedLine::Text(test_content));
                 }
             }
         }
@@ -3087,110 +3187,6 @@ impl<'test> TestCx<'test> {
         }
     }
 
-    fn compare_mir_test_output(&self, test_name: &str, expected_content: &[ExpectedLine<&str>]) {
-        let mut output_file = PathBuf::new();
-        output_file.push(self.get_mir_dump_dir());
-        output_file.push(test_name);
-        debug!("comparing the contests of: {:?}", output_file);
-        debug!("with: {:?}", expected_content);
-        if !output_file.exists() {
-            panic!(
-                "Output file `{}` from test does not exist",
-                output_file.into_os_string().to_string_lossy()
-            );
-        }
-        self.check_mir_test_timestamp(test_name, &output_file);
-
-        let dumped_string = fs::read_to_string(&output_file).unwrap();
-        let mut dumped_lines =
-            dumped_string.lines().map(|l| nocomment_mir_line(l)).filter(|l| !l.is_empty());
-        let mut expected_lines = expected_content
-            .iter()
-            .filter(|&l| if let &ExpectedLine::Text(l) = l { !l.is_empty() } else { true })
-            .peekable();
-
-        let compare = |expected_line, dumped_line| {
-            let e_norm = normalize_mir_line(expected_line);
-            let d_norm = normalize_mir_line(dumped_line);
-            debug!("found: {:?}", d_norm);
-            debug!("expected: {:?}", e_norm);
-            e_norm == d_norm
-        };
-
-        let error = |expected_line, extra_msg| {
-            let normalize_all = dumped_string
-                .lines()
-                .map(nocomment_mir_line)
-                .filter(|l| !l.is_empty())
-                .collect::<Vec<_>>()
-                .join("\n");
-            let f = |l: &ExpectedLine<_>| match l {
-                &ExpectedLine::Elision => "... (elided)".into(),
-                &ExpectedLine::Text(t) => t,
-            };
-            let expected_content =
-                expected_content.iter().map(|l| f(l)).collect::<Vec<_>>().join("\n");
-            panic!(
-                "Did not find expected line, error: {}\n\
-                 Expected Line: {:?}\n\
-                 Test Name: {}\n\
-                 Expected:\n{}\n\
-                 Actual:\n{}",
-                extra_msg, expected_line, test_name, expected_content, normalize_all
-            );
-        };
-
-        // We expect each non-empty line to appear consecutively, non-consecutive lines
-        // must be separated by at least one Elision
-        let mut start_block_line = None;
-        while let Some(dumped_line) = dumped_lines.next() {
-            match expected_lines.next() {
-                Some(&ExpectedLine::Text(expected_line)) => {
-                    let normalized_expected_line = normalize_mir_line(expected_line);
-                    if normalized_expected_line.contains(":{") {
-                        start_block_line = Some(expected_line);
-                    }
-
-                    if !compare(expected_line, dumped_line) {
-                        error!("{:?}", start_block_line);
-                        error(
-                            expected_line,
-                            format!(
-                                "Mismatch in lines\n\
-                                 Current block: {}\n\
-                                 Actual Line: {:?}",
-                                start_block_line.unwrap_or("None"),
-                                dumped_line
-                            ),
-                        );
-                    }
-                }
-                Some(&ExpectedLine::Elision) => {
-                    // skip any number of elisions in a row.
-                    while let Some(&&ExpectedLine::Elision) = expected_lines.peek() {
-                        expected_lines.next();
-                    }
-                    if let Some(&ExpectedLine::Text(expected_line)) = expected_lines.next() {
-                        let mut found = compare(expected_line, dumped_line);
-                        if found {
-                            continue;
-                        }
-                        while let Some(dumped_line) = dumped_lines.next() {
-                            found = compare(expected_line, dumped_line);
-                            if found {
-                                break;
-                            }
-                        }
-                        if !found {
-                            error(expected_line, "ran out of mir dump to match against".into());
-                        }
-                    }
-                }
-                None => {}
-            }
-        }
-    }
-
     fn get_mir_dump_dir(&self) -> PathBuf {
         let mut mir_dump_dir = PathBuf::from(self.config.build_base.as_path());
         debug!("input_file: {:?}", self.testpaths.file);
@@ -3204,7 +3200,9 @@ impl<'test> TestCx<'test> {
         let json = cflags.contains("--error-format json")
             || cflags.contains("--error-format pretty-json")
             || cflags.contains("--error-format=json")
-            || cflags.contains("--error-format=pretty-json");
+            || cflags.contains("--error-format=pretty-json")
+            || cflags.contains("--output-format json")
+            || cflags.contains("--output-format=json");
 
         let mut normalized = output.to_string();
 
@@ -3247,7 +3245,7 @@ impl<'test> TestCx<'test> {
         // with placeholders as we do not want tests needing updated when compiler source code
         // changes.
         // eg. $SRC_DIR/libcore/mem.rs:323:14 becomes $SRC_DIR/libcore/mem.rs:LL:COL
-        normalized = Regex::new("SRC_DIR(.+):\\d+:\\d+")
+        normalized = Regex::new("SRC_DIR(.+):\\d+:\\d+(: \\d+:\\d+)?")
             .unwrap()
             .replace_all(&normalized, "SRC_DIR$1:LL:COL")
             .into_owned();
@@ -3355,26 +3353,7 @@ impl<'test> TestCx<'test> {
                 println!("normalized {}:\n{}\n", kind, actual);
             } else {
                 println!("diff of {}:\n", kind);
-                let diff_results = make_diff(expected, actual, 3);
-                for result in diff_results {
-                    let mut line_number = result.line_number;
-                    for line in result.lines {
-                        match line {
-                            DiffLine::Expected(e) => {
-                                println!("-\t{}", e);
-                                line_number += 1;
-                            }
-                            DiffLine::Context(c) => {
-                                println!("{}\t{}", line_number, c);
-                                line_number += 1;
-                            }
-                            DiffLine::Resulting(r) => {
-                                println!("+\t{}", r);
-                            }
-                        }
-                    }
-                    println!();
-                }
+                print_diff(expected, actual, 3);
             }
         }
 
@@ -3493,43 +3472,11 @@ enum TargetLocation {
     ThisDirectory(PathBuf),
 }
 
-#[derive(Clone, PartialEq, Eq)]
-enum ExpectedLine<T: AsRef<str>> {
-    Elision,
-    Text(T),
-}
-
 enum AllowUnused {
     Yes,
     No,
 }
 
-impl<T> fmt::Debug for ExpectedLine<T>
-where
-    T: AsRef<str> + fmt::Debug,
-{
-    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let &ExpectedLine::Text(ref t) = self {
-            write!(formatter, "{:?}", t)
-        } else {
-            write!(formatter, "\"...\" (Elision)")
-        }
-    }
-}
-
-fn normalize_mir_line(line: &str) -> String {
-    nocomment_mir_line(line).replace(char::is_whitespace, "")
-}
-
-fn nocomment_mir_line(line: &str) -> &str {
-    if let Some(idx) = line.find("//") {
-        let (l, _) = line.split_at(idx);
-        l.trim_end()
-    } else {
-        line
-    }
-}
-
 fn read2_abbreviated(mut child: Child) -> io::Result<Output> {
     use crate::read2::read2;
     use std::mem::replace;