]> git.lizzy.rs Git - rust.git/blobdiff - src/tools/compiletest/src/header.rs
compiletest: Derive Default for EarlyProps
[rust.git] / src / tools / compiletest / src / header.rs
index a9be7ba5f96dcd81d9ea2a70841c0a887cf9b339..684e19f99b58b2077b2dd21606e6a876242c0a94 100644 (file)
@@ -6,52 +6,13 @@
 
 use log::*;
 
-use crate::common::{self, CompareMode, Config, Mode, PassMode, FailMode};
-use crate::util;
+use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode};
 use crate::extract_gdb_version;
+use crate::util;
 
 #[cfg(test)]
 mod tests;
 
-/// Whether to ignore the test.
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub enum Ignore {
-    /// Runs it.
-    Run,
-    /// Ignore it totally.
-    Ignore,
-    /// Ignore only the gdb test, but run the lldb test.
-    IgnoreGdb,
-    /// Ignore only the lldb test, but run the gdb test.
-    IgnoreLldb,
-}
-
-impl Ignore {
-    pub fn can_run_gdb(&self) -> bool {
-        *self == Ignore::Run || *self == Ignore::IgnoreLldb
-    }
-
-    pub fn can_run_lldb(&self) -> bool {
-        *self == Ignore::Run || *self == Ignore::IgnoreGdb
-    }
-
-    pub fn no_gdb(&self) -> Ignore {
-        match *self {
-            Ignore::Run => Ignore::IgnoreGdb,
-            Ignore::IgnoreGdb => Ignore::IgnoreGdb,
-            _ => Ignore::Ignore,
-        }
-    }
-
-    pub fn no_lldb(&self) -> Ignore {
-        match *self {
-            Ignore::Run => Ignore::IgnoreLldb,
-            Ignore::IgnoreLldb => Ignore::IgnoreLldb,
-            _ => Ignore::Ignore,
-        }
-    }
-}
-
 /// The result of parse_cfg_name_directive.
 #[derive(Clone, Copy, PartialEq, Debug)]
 enum ParsedNameDirective {
@@ -59,16 +20,13 @@ enum ParsedNameDirective {
     NoMatch,
     /// Match.
     Match,
-    /// Mode was DebugInfoGdbLldb and this matched gdb.
-    MatchGdb,
-    /// Mode was DebugInfoGdbLldb and this matched lldb.
-    MatchLldb,
 }
 
 /// Properties which must be known very early, before actually running
 /// the test.
+#[derive(Default)]
 pub struct EarlyProps {
-    pub ignore: Ignore,
+    pub ignore: bool,
     pub should_fail: bool,
     pub aux: Vec<String>,
     pub aux_crate: Vec<(String, String)>,
@@ -77,82 +35,60 @@ pub struct EarlyProps {
 
 impl EarlyProps {
     pub fn from_file(config: &Config, testfile: &Path) -> Self {
-        let mut props = EarlyProps {
-            ignore: Ignore::Run,
-            should_fail: false,
-            aux: Vec::new(),
-            aux_crate: Vec::new(),
-            revisions: vec![],
-        };
-
-        if config.mode == common::DebugInfoGdbLldb {
-            if config.lldb_python_dir.is_none() {
-                props.ignore = props.ignore.no_lldb();
-            }
-            if config.gdb_version.is_none() {
-                props.ignore = props.ignore.no_gdb();
-            }
-        } else if config.mode == common::DebugInfoCdb {
-            if config.cdb.is_none() {
-                props.ignore = Ignore::Ignore;
-            }
-        }
+        let file = File::open(testfile).unwrap();
+        Self::from_reader(config, testfile, file)
+    }
 
+    pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
+        let mut props = EarlyProps::default();
         let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
         let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
 
-        iter_header(testfile, None, &mut |ln| {
+        iter_header(testfile, None, rdr, &mut |ln| {
             // we should check if any only-<platform> exists and if it exists
             // and does not matches the current platform, skip the test
-            if props.ignore != Ignore::Ignore {
+            if !props.ignore {
                 props.ignore = match config.parse_cfg_name_directive(ln, "ignore") {
-                    ParsedNameDirective::Match => Ignore::Ignore,
+                    ParsedNameDirective::Match => true,
                     ParsedNameDirective::NoMatch => props.ignore,
-                    ParsedNameDirective::MatchGdb => props.ignore.no_gdb(),
-                    ParsedNameDirective::MatchLldb => props.ignore.no_lldb(),
                 };
 
                 if config.has_cfg_prefix(ln, "only") {
                     props.ignore = match config.parse_cfg_name_directive(ln, "only") {
                         ParsedNameDirective::Match => props.ignore,
-                        ParsedNameDirective::NoMatch => Ignore::Ignore,
-                        ParsedNameDirective::MatchLldb => props.ignore.no_gdb(),
-                        ParsedNameDirective::MatchGdb => props.ignore.no_lldb(),
+                        ParsedNameDirective::NoMatch => true,
                     };
                 }
 
                 if ignore_llvm(config, ln) {
-                    props.ignore = Ignore::Ignore;
+                    props.ignore = true;
                 }
 
-                if config.run_clang_based_tests_with.is_none() &&
-                   config.parse_needs_matching_clang(ln) {
-                    props.ignore = Ignore::Ignore;
+                if config.run_clang_based_tests_with.is_none()
+                    && config.parse_needs_matching_clang(ln)
+                {
+                    props.ignore = true;
                 }
 
-                if !rustc_has_profiler_support &&
-                   config.parse_needs_profiler_support(ln) {
-                    props.ignore = Ignore::Ignore;
+                if !rustc_has_profiler_support && config.parse_needs_profiler_support(ln) {
+                    props.ignore = true;
                 }
 
-                if !rustc_has_sanitizer_support &&
-                   config.parse_needs_sanitizer_support(ln) {
-                    props.ignore = Ignore::Ignore;
+                if !rustc_has_sanitizer_support && config.parse_needs_sanitizer_support(ln) {
+                    props.ignore = true;
                 }
 
                 if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
-                    props.ignore = Ignore::Ignore;
+                    props.ignore = true;
                 }
-            }
 
-            if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoGdbLldb) &&
-                props.ignore.can_run_gdb() && ignore_gdb(config, ln) {
-                props.ignore = props.ignore.no_gdb();
-            }
+                if config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln) {
+                    props.ignore = true;
+                }
 
-            if (config.mode == common::DebugInfoLldb || config.mode == common::DebugInfoGdbLldb) &&
-                props.ignore.can_run_lldb() && ignore_lldb(config, ln) {
-                props.ignore = props.ignore.no_lldb();
+                if config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln) {
+                    props.ignore = true;
+                }
             }
 
             if let Some(s) = config.parse_aux_build(ln) {
@@ -207,12 +143,13 @@ fn ignore_gdb(config: &Config, line: &str) -> bool {
         fn extract_gdb_version_range(line: &str) -> (u32, u32) {
             const ERROR_MESSAGE: &'static str = "Malformed GDB version directive";
 
-            let range_components = line.split(&[' ', '-'][..])
-                                       .filter(|word| !word.is_empty())
-                                       .map(extract_gdb_version)
-                                       .skip_while(Option::is_none)
-                                       .take(3) // 3 or more = invalid, so take at most 3.
-                                       .collect::<Vec<Option<u32>>>();
+            let range_components = line
+                .split(&[' ', '-'][..])
+                .filter(|word| !word.is_empty())
+                .map(extract_gdb_version)
+                .skip_while(Option::is_none)
+                .take(3) // 3 or more = invalid, so take at most 3.
+                .collect::<Vec<Option<u32>>>();
 
             match range_components.len() {
                 1 => {
@@ -231,7 +168,8 @@ fn extract_gdb_version_range(line: &str) -> (u32, u32) {
         fn ignore_lldb(config: &Config, line: &str) -> bool {
             if let Some(ref actual_version) = config.lldb_version {
                 if line.starts_with("min-lldb-version") {
-                    let min_version = line.trim_end()
+                    let min_version = line
+                        .trim_end()
                         .rsplit(' ')
                         .next()
                         .expect("Malformed lldb version directive");
@@ -254,7 +192,8 @@ fn ignore_llvm(config: &Config, line: &str) -> bool {
             }
             if let Some(ref actual_version) = config.llvm_version {
                 if line.starts_with("min-llvm-version") {
-                    let min_version = line.trim_end()
+                    let min_version = line
+                        .trim_end()
                         .rsplit(' ')
                         .next()
                         .expect("Malformed llvm version directive");
@@ -262,7 +201,8 @@ fn ignore_llvm(config: &Config, line: &str) -> bool {
                     // version
                     &actual_version[..] < min_version
                 } else if line.starts_with("min-system-llvm-version") {
-                    let min_version = line.trim_end()
+                    let min_version = line
+                        .trim_end()
                         .rsplit(' ')
                         .next()
                         .expect("Malformed llvm version directive");
@@ -271,16 +211,15 @@ fn ignore_llvm(config: &Config, line: &str) -> bool {
                     config.system_llvm && &actual_version[..] < min_version
                 } else if line.starts_with("ignore-llvm-version") {
                     // Syntax is: "ignore-llvm-version <version1> [- <version2>]"
-                    let range_components = line.split(' ')
+                    let range_components = line
+                        .split(' ')
                         .skip(1) // Skip the directive.
                         .map(|s| s.trim())
                         .filter(|word| !word.is_empty() && word != &"-")
                         .take(3) // 3 or more = invalid, so take at most 3.
                         .collect::<Vec<&str>>();
                     match range_components.len() {
-                        1 => {
-                            &actual_version[..] == range_components[0]
-                        }
+                        1 => &actual_version[..] == range_components[0],
                         2 => {
                             let v_min = range_components[0];
                             let v_max = range_components[1];
@@ -370,8 +309,6 @@ pub struct TestProps {
     pub fail_mode: Option<FailMode>,
     // rustdoc will test the output of the `--test` option
     pub check_test_line_numbers_match: bool,
-    // Do not pass `-Z ui-testing` to UI tests
-    pub disable_ui_testing_normalization: bool,
     // customized normalization rules
     pub normalize_stdout: Vec<(String, String)>,
     pub normalize_stderr: Vec<(String, String)>,
@@ -416,7 +353,6 @@ pub fn new() -> Self {
             fail_mode: None,
             ignore_pass: false,
             check_test_line_numbers_match: false,
-            disable_ui_testing_normalization: false,
             normalize_stdout: vec![],
             normalize_stderr: vec![],
             failure_status: -1,
@@ -455,14 +391,14 @@ pub fn from_file(testfile: &Path, cfg: Option<&str>, config: &Config) -> Self {
     /// `//[foo]`), then the property is ignored unless `cfg` is
     /// `Some("foo")`.
     fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
-        iter_header(testfile, cfg, &mut |ln| {
+        let file = File::open(testfile).unwrap();
+        iter_header(testfile, cfg, file, &mut |ln| {
             if let Some(ep) = config.parse_error_pattern(ln) {
                 self.error_patterns.push(ep);
             }
 
             if let Some(flags) = config.parse_compile_flags(ln) {
-                self.compile_flags
-                    .extend(flags.split_whitespace().map(|s| s.to_owned()));
+                self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned()));
             }
 
             if let Some(edition) = config.parse_edition(ln) {
@@ -564,11 +500,6 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
                 self.ignore_pass = config.parse_ignore_pass(ln);
             }
 
-            if !self.disable_ui_testing_normalization {
-                self.disable_ui_testing_normalization =
-                    config.parse_disable_ui_testing_normalization(ln);
-            }
-
             if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") {
                 self.normalize_stdout.push(rule);
             }
@@ -614,8 +545,10 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
     }
 
     fn update_fail_mode(&mut self, ln: &str, config: &Config) {
-        let check_ui = |mode: &str| if config.mode != Mode::Ui {
-            panic!("`{}-fail` header is only supported in UI tests", mode);
+        let check_ui = |mode: &str| {
+            if config.mode != Mode::Ui {
+                panic!("`{}-fail` header is only supported in UI tests", mode);
+            }
         };
         let fail_mode = if config.parse_name_directive(ln, "check-fail") {
             check_ui("check");
@@ -641,9 +574,10 @@ fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config
             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")) {
+            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);
             }
         };
@@ -683,27 +617,29 @@ pub fn local_pass_mode(&self) -> Option<PassMode> {
     }
 }
 
-fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
+fn iter_header<R: Read>(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn FnMut(&str)) {
     if testfile.is_dir() {
         return;
     }
 
-    let comment = if testfile.to_string_lossy().ends_with(".rs") {
-        "//"
-    } else {
-        "#"
-    };
+    let comment = if testfile.to_string_lossy().ends_with(".rs") { "//" } else { "#" };
 
     // FIXME: would be nice to allow some whitespace between comment and brace :)
     // It took me like 2 days to debug why compile-flags weren’t taken into account for my test :)
     let comment_with_brace = comment.to_string() + "[";
 
-    let rdr = BufReader::new(File::open(testfile).unwrap());
-    for ln in rdr.lines() {
+    let mut rdr = BufReader::new(rdr);
+    let mut ln = String::new();
+
+    loop {
+        ln.clear();
+        if rdr.read_line(&mut ln).unwrap() == 0 {
+            break;
+        }
+
         // Assume that any directives will be found before the first
         // module or function. This doesn't seem to be an optimization
         // with a warm page cache. Maybe with a cold one.
-        let ln = ln.unwrap();
         let ln = ln.trim();
         if ln.starts_with("fn") || ln.starts_with("mod") {
             return;
@@ -711,7 +647,7 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
             // A comment like `//[foo]` is specific to revision `foo`
             if let Some(close_brace) = ln.find(']') {
                 let open_brace = ln.find('[').unwrap();
-                let lncfg = &ln[open_brace + 1 .. close_brace];
+                let lncfg = &ln[open_brace + 1..close_brace];
                 let matches = match cfg {
                     Some(s) => s == &lncfg[..],
                     None => false,
@@ -720,11 +656,13 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
                     it(ln[(close_brace + 1)..].trim_start());
                 }
             } else {
-                panic!("malformed condition directive: expected `{}foo]`, found `{}`",
-                        comment_with_brace, ln)
+                panic!(
+                    "malformed condition directive: expected `{}foo]`, found `{}`",
+                    comment_with_brace, ln
+                )
             }
         } else if ln.starts_with(comment) {
-            it(ln[comment.len() ..].trim_start());
+            it(ln[comment.len()..].trim_start());
         }
     }
     return;
@@ -743,8 +681,7 @@ fn parse_forbid_output(&self, line: &str) -> Option<String> {
     }
 
     fn parse_aux_build(&self, line: &str) -> Option<String> {
-        self.parse_name_value_directive(line, "aux-build")
-            .map(|r| r.trim().to_string())
+        self.parse_name_value_directive(line, "aux-build").map(|r| r.trim().to_string())
     }
 
     fn parse_aux_crate(&self, line: &str) -> Option<(String, String)> {
@@ -821,10 +758,6 @@ fn parse_failure_status(&self, line: &str) -> Option<i32> {
         }
     }
 
-    fn parse_disable_ui_testing_normalization(&self, line: &str) -> bool {
-        self.parse_name_directive(line, "disable-ui-testing-normalization")
-    }
-
     fn parse_check_test_line_numbers_match(&self, line: &str) -> bool {
         self.parse_name_directive(line, "check-test-line-numbers-match")
     }
@@ -834,8 +767,7 @@ fn parse_ignore_pass(&self, line: &str) -> bool {
     }
 
     fn parse_assembly_output(&self, line: &str) -> Option<String> {
-        self.parse_name_value_directive(line, "assembly-output")
-            .map(|r| r.trim().to_string())
+        self.parse_name_value_directive(line, "assembly-output").map(|r| r.trim().to_string())
     }
 
     fn parse_env(&self, line: &str, name: &str) -> Option<(String, String)> {
@@ -889,63 +821,37 @@ fn parse_needs_sanitizer_support(&self, line: &str) -> bool {
     /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
     /// or `normalize-stderr-32bit`.
     fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective {
-        if line.starts_with(prefix) && line.as_bytes().get(prefix.len()) == Some(&b'-') {
-            let name = line[prefix.len() + 1..]
-                .split(&[':', ' '][..])
-                .next()
-                .unwrap();
-
-            if name == "test" ||
-                util::matches_os(&self.target, name) ||             // target
-                util::matches_env(&self.target, name) ||            // env
-                name == util::get_arch(&self.target) ||             // architecture
-                name == util::get_pointer_width(&self.target) ||    // pointer width
-                name == self.stage_id.split('-').next().unwrap() || // stage
-                (self.target != self.host && name == "cross-compile") ||
-                match self.compare_mode {
-                    Some(CompareMode::Nll) => name == "compare-mode-nll",
-                    Some(CompareMode::Polonius) => name == "compare-mode-polonius",
-                    None => false,
-                } ||
-                (cfg!(debug_assertions) && name == "debug") {
-                ParsedNameDirective::Match
-            } else {
-                match self.mode {
-                    common::DebugInfoGdbLldb => {
-                        if name == "gdb" {
-                            ParsedNameDirective::MatchGdb
-                        } else if name == "lldb" {
-                            ParsedNameDirective::MatchLldb
-                        } else {
-                            ParsedNameDirective::NoMatch
-                        }
-                    },
-                    common::DebugInfoCdb => if name == "cdb" {
-                        ParsedNameDirective::Match
-                    } else {
-                        ParsedNameDirective::NoMatch
-                    },
-                    common::DebugInfoGdb => if name == "gdb" {
-                        ParsedNameDirective::Match
-                    } else {
-                        ParsedNameDirective::NoMatch
-                    },
-                    common::DebugInfoLldb => if name == "lldb" {
-                        ParsedNameDirective::Match
-                    } else {
-                        ParsedNameDirective::NoMatch
-                    },
-                    common::Pretty => if name == "pretty" {
-                        ParsedNameDirective::Match
-                    } else {
-                        ParsedNameDirective::NoMatch
-                    },
-                    _ => ParsedNameDirective::NoMatch,
-                }
-            }
-        } else {
-            ParsedNameDirective::NoMatch
+        if !line.as_bytes().starts_with(prefix.as_bytes()) {
+            return ParsedNameDirective::NoMatch;
         }
+        if line.as_bytes().get(prefix.len()) != Some(&b'-') {
+            return ParsedNameDirective::NoMatch;
+        }
+
+        let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap();
+
+        let is_match = name == "test" ||
+            &self.target == name ||                             // triple
+            util::matches_os(&self.target, name) ||             // target
+            util::matches_env(&self.target, name) ||            // env
+            name == util::get_arch(&self.target) ||             // architecture
+            name == util::get_pointer_width(&self.target) ||    // pointer width
+            name == self.stage_id.split('-').next().unwrap() || // stage
+            (self.target != self.host && name == "cross-compile") ||
+            match self.compare_mode {
+                Some(CompareMode::Nll) => name == "compare-mode-nll",
+                Some(CompareMode::Polonius) => name == "compare-mode-polonius",
+                None => false,
+            } ||
+            (cfg!(debug_assertions) && name == "debug") ||
+            match self.debugger {
+                Some(Debugger::Cdb) => name == "cdb",
+                Some(Debugger::Gdb) => name == "gdb",
+                Some(Debugger::Lldb) => name == "lldb",
+                None => false,
+            };
+
+        if is_match { ParsedNameDirective::Match } else { ParsedNameDirective::NoMatch }
     }
 
     fn has_cfg_prefix(&self, line: &str, prefix: &str) -> bool {
@@ -958,10 +864,11 @@ fn has_cfg_prefix(&self, line: &str, prefix: &str) -> bool {
     fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
         // Ensure the directive is a whole word. Do not match "ignore-x86" when
         // the line says "ignore-x86_64".
-        line.starts_with(directive) && match line.as_bytes().get(directive.len()) {
-            None | Some(&b' ') | Some(&b':') => true,
-            _ => false,
-        }
+        line.starts_with(directive)
+            && match line.as_bytes().get(directive.len()) {
+                None | Some(&b' ') | Some(&b':') => true,
+                _ => false,
+            }
     }
 
     pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option<String> {
@@ -1002,10 +909,8 @@ fn parse_edition(&self, line: &str) -> Option<String> {
 }
 
 pub fn lldb_version_to_int(version_string: &str) -> isize {
-    let error_string = format!(
-        "Encountered LLDB version string with unexpected format: {}",
-        version_string
-    );
+    let error_string =
+        format!("Encountered LLDB version string with unexpected format: {}", version_string);
     version_string.parse().expect(&error_string)
 }