diff options
Diffstat (limited to 'src/tools/compiletest')
-rw-r--r-- | src/tools/compiletest/Cargo.toml | 1 | ||||
-rw-r--r-- | src/tools/compiletest/src/common.rs | 156 | ||||
-rw-r--r-- | src/tools/compiletest/src/header.rs | 69 | ||||
-rw-r--r-- | src/tools/compiletest/src/header/tests.rs | 193 | ||||
-rw-r--r-- | src/tools/compiletest/src/main.rs | 38 | ||||
-rw-r--r-- | src/tools/compiletest/src/runtest.rs | 61 | ||||
-rw-r--r-- | src/tools/compiletest/src/util.rs | 158 | ||||
-rw-r--r-- | src/tools/compiletest/src/util/tests.rs | 37 |
8 files changed, 441 insertions, 272 deletions
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 23e495399..41f97e432 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -17,6 +17,7 @@ rustfix = "0.6.0" lazy_static = "1.0" walkdir = "2" glob = "0.3.0" +lazycell = "1.3.0" [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index be81ff881..0260f6848 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -3,9 +3,11 @@ pub use self::Mode::*; use std::ffi::OsString; use std::fmt; use std::path::{Path, PathBuf}; +use std::process::Command; use std::str::FromStr; use crate::util::PathBufExt; +use lazycell::LazyCell; use test::ColorConfig; #[derive(Clone, Copy, PartialEq, Debug)] @@ -201,6 +203,9 @@ pub struct Config { /// The jsondocck executable. pub jsondocck_path: Option<String>, + /// The jsondoclint executable. + pub jsondoclint_path: Option<String>, + /// The LLVM `FileCheck` binary path. pub llvm_filecheck: Option<PathBuf>, @@ -264,19 +269,15 @@ pub struct Config { pub runtool: Option<String>, /// Flags to pass to the compiler when building for the host - pub host_rustcflags: Option<String>, + pub host_rustcflags: Vec<String>, /// Flags to pass to the compiler when building for the target - pub target_rustcflags: Option<String>, + pub target_rustcflags: Vec<String>, /// Whether tests should be optimized by default. Individual test-suites and test files may /// override this setting. pub optimize_tests: bool, - /// What panic strategy the target is built with. Unwind supports Abort, but - /// not vice versa. - pub target_panic: PanicStrategy, - /// Target system to be tested pub target: String, @@ -371,6 +372,8 @@ pub struct Config { /// Whether to rerun tests even if the inputs are unchanged. pub force_rerun: bool, + + pub target_cfg: LazyCell<TargetCfg>, } impl Config { @@ -380,6 +383,147 @@ impl Config { !self.target.ends_with("-fuchsia") }) } + + fn target_cfg(&self) -> &TargetCfg { + self.target_cfg + .borrow_with(|| TargetCfg::new(&self.rustc_path, &self.target, &self.target_rustcflags)) + } + + pub fn matches_arch(&self, arch: &str) -> bool { + self.target_cfg().arch == arch || + // Shorthand for convenience. The arch for + // asmjs-unknown-emscripten is actually wasm32. + (arch == "asmjs" && self.target.starts_with("asmjs")) || + // Matching all the thumb variants as one can be convenient. + // (thumbv6m, thumbv7em, thumbv7m, etc.) + (arch == "thumb" && self.target.starts_with("thumb")) + } + + pub fn matches_os(&self, os: &str) -> bool { + self.target_cfg().os == os + } + + pub fn matches_env(&self, env: &str) -> bool { + self.target_cfg().env == env + } + + pub fn matches_abi(&self, abi: &str) -> bool { + self.target_cfg().abi == abi + } + + pub fn matches_family(&self, family: &str) -> bool { + self.target_cfg().families.iter().any(|f| f == family) + } + + pub fn is_big_endian(&self) -> bool { + self.target_cfg().endian == Endian::Big + } + + pub fn get_pointer_width(&self) -> u32 { + *&self.target_cfg().pointer_width + } + + pub fn can_unwind(&self) -> bool { + self.target_cfg().panic == PanicStrategy::Unwind + } + + pub fn has_asm_support(&self) -> bool { + static ASM_SUPPORTED_ARCHS: &[&str] = &[ + "x86", "x86_64", "arm", "aarch64", "riscv32", + "riscv64", + // These targets require an additional asm_experimental_arch feature. + // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32", + ]; + ASM_SUPPORTED_ARCHS.contains(&self.target_cfg().arch.as_str()) + } +} + +#[derive(Clone, Debug)] +pub struct TargetCfg { + arch: String, + os: String, + env: String, + abi: String, + families: Vec<String>, + pointer_width: u32, + endian: Endian, + panic: PanicStrategy, +} + +#[derive(Eq, PartialEq, Clone, Debug)] +pub enum Endian { + Little, + Big, +} + +impl TargetCfg { + fn new(rustc_path: &Path, target: &str, target_rustcflags: &Vec<String>) -> TargetCfg { + let output = match Command::new(rustc_path) + .arg("--print=cfg") + .arg("--target") + .arg(target) + .args(target_rustcflags) + .output() + { + Ok(output) => output, + Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", rustc_path), + }; + if !output.status.success() { + panic!( + "error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}", + rustc_path, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap(), + ); + } + let print_cfg = String::from_utf8(output.stdout).unwrap(); + let mut arch = None; + let mut os = None; + let mut env = None; + let mut abi = None; + let mut families = Vec::new(); + let mut pointer_width = None; + let mut endian = None; + let mut panic = None; + for line in print_cfg.lines() { + if let Some((name, value)) = line.split_once('=') { + let value = value.trim_matches('"'); + match name { + "target_arch" => arch = Some(value), + "target_os" => os = Some(value), + "target_env" => env = Some(value), + "target_abi" => abi = Some(value), + "target_family" => families.push(value.to_string()), + "target_pointer_width" => pointer_width = Some(value.parse().unwrap()), + "target_endian" => { + endian = Some(match value { + "little" => Endian::Little, + "big" => Endian::Big, + s => panic!("unexpected {s}"), + }) + } + "panic" => { + panic = match value { + "abort" => Some(PanicStrategy::Abort), + "unwind" => Some(PanicStrategy::Unwind), + s => panic!("unexpected {s}"), + } + } + _ => {} + } + } + } + TargetCfg { + arch: arch.unwrap().to_string(), + os: os.unwrap().to_string(), + env: env.unwrap().to_string(), + abi: abi.unwrap().to_string(), + families, + pointer_width: pointer_width.unwrap(), + endian: endian.unwrap(), + panic: panic.unwrap(), + } + } } #[derive(Debug, Clone)] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index f8f193ddf..0d9a629e1 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -4,10 +4,11 @@ use std::fs::File; use std::io::prelude::*; use std::io::BufReader; use std::path::{Path, PathBuf}; +use std::process::Command; use tracing::*; -use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PanicStrategy, PassMode}; +use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode}; use crate::util; use crate::{extract_cdb_version, extract_gdb_version}; @@ -661,17 +662,36 @@ impl Config { let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap(); + let matches_pointer_width = || { + name.strip_suffix("bit") + .and_then(|width| width.parse::<u32>().ok()) + .map(|width| self.get_pointer_width() == width) + .unwrap_or(false) + }; + + // If something is ignored for emscripten, it likely also needs to be + // ignored for wasm32-unknown-unknown. + // `wasm32-bare` is an alias to refer to just wasm32-unknown-unknown + // (in contrast to `wasm32` which also matches non-bare targets like + // asmjs-unknown-emscripten). + let matches_wasm32_alias = || { + self.target == "wasm32-unknown-unknown" && matches!(name, "emscripten" | "wasm32-bare") + }; + let is_match = name == "test" || self.target == name || // triple - util::matches_os(&self.target, name) || // target - util::matches_env(&self.target, name) || // env + self.matches_os(name) || + self.matches_env(name) || + self.matches_abi(name) || + self.matches_family(name) || self.target.ends_with(name) || // target and env - name == util::get_arch(&self.target) || // architecture - name == util::get_pointer_width(&self.target) || // pointer width + self.matches_arch(name) || + matches_wasm32_alias() || + matches_pointer_width() || name == self.stage_id.split('-').next().unwrap() || // stage name == self.channel || // channel (self.target != self.host && name == "cross-compile") || - (name == "endian-big" && util::is_big_endian(&self.target)) || + (name == "endian-big" && self.is_big_endian()) || (self.remote_test_client.is_some() && name == "remote") || match self.compare_mode { Some(CompareMode::Polonius) => name == "compare-mode-polonius", @@ -824,6 +844,20 @@ pub fn extract_llvm_version(version: &str) -> Option<u32> { Some(version) } +pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> { + let output = Command::new(binary_path).arg("--version").output().ok()?; + if !output.status.success() { + return None; + } + let version = String::from_utf8(output.stdout).ok()?; + for line in version.lines() { + if let Some(version) = line.split("LLVM version ").skip(1).next() { + return extract_llvm_version(version); + } + } + None +} + /// Takes a directive of the form "<version1> [- <version2>]", /// returns the numeric representation of <version1> and <version2> as /// tuple: (<version1> as u32, <version2> as u32) @@ -869,7 +903,7 @@ pub fn make_test_description<R: Read>( 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(); - let has_asm_support = util::has_asm_support(&config.target); + let has_asm_support = config.has_asm_support(); let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target); let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target); @@ -878,15 +912,27 @@ pub fn make_test_description<R: Read>( let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target); let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target); - // for `-Z gcc-ld=lld` + + // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find + // whether `rust-lld` is present in the compiler under test. + // + // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For + // example: + // - on linux, it can be <sysroot>/lib + // - on windows, it can be <sysroot>/bin + // + // However, `rust-lld` is only located under the lib path, so we look for it there. let has_rust_lld = config .compile_lib_path + .parent() + .expect("couldn't traverse to the parent of the specified --compile-lib-path") + .join("lib") .join("rustlib") .join(&config.target) .join("bin") - .join("gcc-ld") - .join(if config.host.contains("windows") { "ld.exe" } else { "ld" }) + .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) .exists(); + iter_header(path, src, &mut |revision, ln| { if revision.is_some() && revision != cfg { return; @@ -918,8 +964,7 @@ pub fn make_test_description<R: Read>( ignore |= !has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag"); ignore |= !has_shadow_call_stack && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack"); - ignore |= config.target_panic == PanicStrategy::Abort - && config.parse_name_directive(ln, "needs-unwind"); + ignore |= !config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"); ignore |= config.target == "wasm32-unknown-unknown" && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS); ignore |= config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln); diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index a8fd4880f..bcd222b5a 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -42,7 +42,6 @@ fn config() -> Config { "--suite=ui", "--compile-lib-path=", "--run-lib-path=", - "--rustc-path=", "--python=", "--jsondocck-path=", "--src-base=", @@ -57,7 +56,24 @@ fn config() -> Config { "--target=x86_64-unknown-linux-gnu", "--channel=nightly", ]; - let args = args.iter().map(ToString::to_string).collect(); + let mut args: Vec<String> = args.iter().map(ToString::to_string).collect(); + args.push("--rustc-path".to_string()); + // This is a subtle/fragile thing. On rust-lang CI, there is no global + // `rustc`, and Cargo doesn't offer a convenient way to get the path to + // `rustc`. Fortunately bootstrap sets `RUSTC` for us, which is pointing + // to the stage0 compiler. + // + // Otherwise, if you are running compiletests's tests manually, you + // probably don't have `RUSTC` set, in which case this falls back to the + // global rustc. If your global rustc is too far out of sync with stage0, + // then this may cause confusing errors. Or if for some reason you don't + // have rustc in PATH, that would also fail. + args.push(std::env::var("RUSTC").unwrap_or_else(|_| { + eprintln!( + "warning: RUSTC not set, using global rustc (are you not running via bootstrap?)" + ); + "rustc".to_string() + })); crate::parse_config(args) } @@ -237,13 +253,20 @@ fn sanitizers() { #[test] fn asm_support() { - let mut config = config(); - - config.target = "avr-unknown-gnu-atmega328".to_owned(); - assert!(check_ignore(&config, "// needs-asm-support")); - - config.target = "i686-unknown-netbsd".to_owned(); - assert!(!check_ignore(&config, "// needs-asm-support")); + let asms = [ + ("avr-unknown-gnu-atmega328", false), + ("i686-unknown-netbsd", true), + ("riscv32gc-unknown-linux-gnu", true), + ("riscv64imac-unknown-none-elf", true), + ("x86_64-unknown-linux-gnu", true), + ("i686-unknown-netbsd", true), + ]; + for (target, has_asm) in asms { + let mut config = config(); + config.target = target.to_string(); + assert_eq!(config.has_asm_support(), has_asm); + assert_eq!(check_ignore(&config, "// needs-asm-support"), !has_asm) + } } #[test] @@ -281,3 +304,155 @@ fn test_duplicate_revisions() { let config = config(); parse_rs(&config, "// revisions: rpass1 rpass1"); } + +#[test] +fn ignore_arch() { + let archs = [ + ("x86_64-unknown-linux-gnu", "x86_64"), + ("i686-unknown-linux-gnu", "x86"), + ("nvptx64-nvidia-cuda", "nvptx64"), + ("asmjs-unknown-emscripten", "wasm32"), + ("asmjs-unknown-emscripten", "asmjs"), + ("thumbv7m-none-eabi", "thumb"), + ]; + for (target, arch) in archs { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_arch(arch), "{target} {arch}"); + assert!(check_ignore(&config, &format!("// ignore-{arch}"))); + } +} + +#[test] +fn matches_os() { + let oss = [ + ("x86_64-unknown-linux-gnu", "linux"), + ("x86_64-fortanix-unknown-sgx", "unknown"), + ("wasm32-unknown-unknown", "unknown"), + ("x86_64-unknown-none", "none"), + ]; + for (target, os) in oss { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_os(os), "{target} {os}"); + assert!(check_ignore(&config, &format!("// ignore-{os}"))); + } +} + +#[test] +fn matches_env() { + let envs = [ + ("x86_64-unknown-linux-gnu", "gnu"), + ("x86_64-fortanix-unknown-sgx", "sgx"), + ("arm-unknown-linux-musleabi", "musl"), + ]; + for (target, env) in envs { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_env(env), "{target} {env}"); + assert!(check_ignore(&config, &format!("// ignore-{env}"))); + } +} + +#[test] +fn matches_abi() { + let abis = [ + ("aarch64-apple-ios-macabi", "macabi"), + ("x86_64-unknown-linux-gnux32", "x32"), + ("arm-unknown-linux-gnueabi", "eabi"), + ]; + for (target, abi) in abis { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_abi(abi), "{target} {abi}"); + assert!(check_ignore(&config, &format!("// ignore-{abi}"))); + } +} + +#[test] +fn is_big_endian() { + let endians = [ + ("x86_64-unknown-linux-gnu", false), + ("bpfeb-unknown-none", true), + ("m68k-unknown-linux-gnu", true), + ("aarch64_be-unknown-linux-gnu", true), + ("powerpc64-unknown-linux-gnu", true), + ]; + for (target, is_big) in endians { + let mut config = config(); + config.target = target.to_string(); + assert_eq!(config.is_big_endian(), is_big, "{target} {is_big}"); + assert_eq!(check_ignore(&config, "// ignore-endian-big"), is_big); + } +} + +#[test] +fn pointer_width() { + let widths = [ + ("x86_64-unknown-linux-gnu", 64), + ("i686-unknown-linux-gnu", 32), + ("arm64_32-apple-watchos", 32), + ("msp430-none-elf", 16), + ]; + for (target, width) in widths { + let mut config = config(); + config.target = target.to_string(); + assert_eq!(config.get_pointer_width(), width, "{target} {width}"); + assert_eq!(check_ignore(&config, "// ignore-16bit"), width == 16); + assert_eq!(check_ignore(&config, "// ignore-32bit"), width == 32); + assert_eq!(check_ignore(&config, "// ignore-64bit"), width == 64); + } +} + +#[test] +fn wasm_special() { + let ignores = [ + ("wasm32-unknown-unknown", "emscripten", true), + ("wasm32-unknown-unknown", "wasm32", true), + ("wasm32-unknown-unknown", "wasm32-bare", true), + ("wasm32-unknown-unknown", "wasm64", false), + ("asmjs-unknown-emscripten", "emscripten", true), + ("asmjs-unknown-emscripten", "wasm32", true), + ("asmjs-unknown-emscripten", "wasm32-bare", false), + ("wasm32-unknown-emscripten", "emscripten", true), + ("wasm32-unknown-emscripten", "wasm32", true), + ("wasm32-unknown-emscripten", "wasm32-bare", false), + ("wasm32-wasi", "emscripten", false), + ("wasm32-wasi", "wasm32", true), + ("wasm32-wasi", "wasm32-bare", false), + ("wasm32-wasi", "wasi", true), + ("wasm64-unknown-unknown", "emscripten", false), + ("wasm64-unknown-unknown", "wasm32", false), + ("wasm64-unknown-unknown", "wasm32-bare", false), + ("wasm64-unknown-unknown", "wasm64", true), + ]; + for (target, pattern, ignore) in ignores { + let mut config = config(); + config.target = target.to_string(); + assert_eq!( + check_ignore(&config, &format!("// ignore-{pattern}")), + ignore, + "{target} {pattern}" + ); + } +} + +#[test] +fn families() { + let families = [ + ("x86_64-unknown-linux-gnu", "unix"), + ("x86_64-pc-windows-gnu", "windows"), + ("wasm32-unknown-unknown", "wasm"), + ("wasm32-unknown-emscripten", "wasm"), + ("wasm32-unknown-emscripten", "unix"), + ]; + for (target, family) in families { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_family(family)); + let other = if family == "windows" { "unix" } else { "windows" }; + assert!(!config.matches_family(other)); + assert!(check_ignore(&config, &format!("// ignore-{family}"))); + assert!(!check_ignore(&config, &format!("// ignore-{other}"))); + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index a8a151ca1..19cf54780 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -5,12 +5,11 @@ extern crate test; -use crate::common::{ - expected_output_path, output_base_dir, output_relative_path, PanicStrategy, UI_EXTENSIONS, -}; +use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths}; use crate::util::logv; use getopts::Options; +use lazycell::LazyCell; use std::env; use std::ffi::OsString; use std::fs; @@ -63,6 +62,7 @@ pub fn parse_config(args: Vec<String>) -> Config { .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") .reqopt("", "python", "path to python to use for doc tests", "PATH") .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") + .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") @@ -103,7 +103,6 @@ pub fn parse_config(args: Vec<String>) -> Config { .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") .optflag("", "optimize-tests", "run tests with optimizations enabled") - .optopt("", "target-panic", "what panic strategy the target supports", "unwind | abort") .optflag("", "verbose", "run tests verbosely, showing all output") .optflag( "", @@ -201,7 +200,9 @@ pub fn parse_config(args: Vec<String>) -> Config { Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; let llvm_version = - matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version); + matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( + || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), + ); let src_base = opt_path(matches, "src-base"); let run_ignored = matches.opt_present("ignored"); @@ -225,6 +226,7 @@ pub fn parse_config(args: Vec<String>) -> Config { rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), python: matches.opt_str("python").unwrap(), jsondocck_path: matches.opt_str("jsondocck-path"), + jsondoclint_path: matches.opt_str("jsondoclint-path"), valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), @@ -252,14 +254,9 @@ pub fn parse_config(args: Vec<String>) -> Config { }), logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), runtool: matches.opt_str("runtool"), - host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")), - target_rustcflags: Some(matches.opt_strs("target-rustcflags").join(" ")), + host_rustcflags: matches.opt_strs("host-rustcflags"), + target_rustcflags: matches.opt_strs("target-rustcflags"), optimize_tests: matches.opt_present("optimize-tests"), - target_panic: match matches.opt_str("target-panic").as_deref() { - Some("unwind") | None => PanicStrategy::Unwind, - Some("abort") => PanicStrategy::Abort, - _ => panic!("unknown `--target-panic` option `{}` given", mode), - }, target, host: opt_str2(matches.opt_str("host")), cdb, @@ -299,6 +296,8 @@ pub fn parse_config(args: Vec<String>) -> Config { npm: matches.opt_str("npm"), force_rerun: matches.opt_present("force-rerun"), + + target_cfg: LazyCell::new(), } } @@ -323,8 +322,8 @@ pub fn log_config(config: &Config) { format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), ); logv(c, format!("runtool: {}", opt_str(&config.runtool))); - logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags))); - logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags))); + logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); + logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); logv(c, format!("target: {}", config.target)); logv(c, format!("host: {}", config.host)); logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); @@ -398,6 +397,8 @@ pub fn run_tests(config: Config) { make_tests(c, &mut tests); } + tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice())); + let res = test::run_tests_console(&opts, tests); match res { Ok(true) => {} @@ -441,7 +442,7 @@ fn configure_cdb(config: &Config) -> Option<Config> { fn configure_gdb(config: &Config) -> Option<Config> { config.gdb_version?; - if util::matches_env(&config.target, "msvc") { + if config.matches_env("msvc") { return None; } @@ -542,6 +543,8 @@ fn common_inputs_stamp(config: &Config) -> Stamp { stamp.add_path(&path); } + stamp.add_dir(&rust_src_dir.join("src/etc/natvis")); + stamp.add_dir(&config.run_lib_path); if let Some(ref rustdoc_path) = config.rustdoc_path { @@ -798,7 +801,10 @@ fn make_test_closure( let config = config.clone(); let testpaths = testpaths.clone(); let revision = revision.cloned(); - test::DynTestFn(Box::new(move || runtest::run(config, &testpaths, revision.as_deref()))) + test::DynTestFn(Box::new(move || { + runtest::run(config, &testpaths, revision.as_deref()); + Ok(()) + })) } /// Returns `true` if the given target is an Android target for the diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index d3e5a2dd6..8af5f1da6 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -13,7 +13,6 @@ use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; use crate::read2::read2_abbreviated; -use crate::util::get_pointer_width; use crate::util::{logv, PathBufExt}; use crate::ColorConfig; use regex::{Captures, Regex}; @@ -559,10 +558,7 @@ impl<'test> TestCx<'test> { .arg(&aux_dir) .args(&self.props.compile_flags) .envs(self.props.rustc_env.clone()); - self.maybe_add_external_args( - &mut rustc, - self.split_maybe_args(&self.config.target_rustcflags), - ); + self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags); let src = match read_from { ReadFrom::Stdin(src) => Some(src), @@ -630,10 +626,7 @@ impl<'test> TestCx<'test> { .arg("-L") .arg(aux_dir); self.set_revision_flags(&mut rustc); - self.maybe_add_external_args( - &mut rustc, - self.split_maybe_args(&self.config.target_rustcflags), - ); + self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags); rustc.args(&self.props.compile_flags); self.compose_and_run_compiler(rustc, Some(src)) @@ -1104,6 +1097,7 @@ impl<'test> TestCx<'test> { "^(core::([a-z_]+::)+)Ref<.+>$", "^(core::([a-z_]+::)+)RefMut<.+>$", "^(core::([a-z_]+::)+)RefCell<.+>$", + "^core::num::([a-z_]+::)*NonZero.+$", ]; script_str @@ -1186,23 +1180,14 @@ impl<'test> TestCx<'test> { ProcRes { status, stdout: out, stderr: err, cmdline: format!("{:?}", cmd) } } - fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> { - if options.is_none() { - return None; - } - + fn cleanup_debug_info_options(&self, options: &Vec<String>) -> Vec<String> { // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS. let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()]; - let new_options = self - .split_maybe_args(options) - .into_iter() - .filter(|x| !options_to_remove.contains(x)) - .collect::<Vec<String>>(); - Some(new_options.join(" ")) + options.iter().filter(|x| !options_to_remove.contains(x)).map(|x| x.clone()).collect() } - fn maybe_add_external_args(&self, cmd: &mut Command, args: Vec<String>) { + fn maybe_add_external_args(&self, cmd: &mut Command, args: &Vec<String>) { // Filter out the arguments that should not be added by runtest here. // // Notable use-cases are: do not add our optimisation flag if @@ -1703,7 +1688,7 @@ impl<'test> TestCx<'test> { fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes { let aux_dir = self.build_all_auxiliary(&mut rustc); - self.props.unset_rustc_env.clone().iter().fold(&mut rustc, |rustc, v| rustc.env_remove(v)); + self.props.unset_rustc_env.iter().fold(&mut rustc, Command::env_remove); rustc.envs(self.props.rustc_env.clone()); self.compose_and_run( rustc, @@ -2016,11 +2001,14 @@ impl<'test> TestCx<'test> { Some(CompareMode::Chalk) => { rustc.args(&["-Zchalk"]); } - Some(CompareMode::SplitDwarf) => { + Some(CompareMode::SplitDwarf) if self.config.target.contains("windows") => { rustc.args(&["-Csplit-debuginfo=unpacked", "-Zunstable-options"]); } + Some(CompareMode::SplitDwarf) => { + rustc.args(&["-Csplit-debuginfo=unpacked"]); + } Some(CompareMode::SplitDwarfSingle) => { - rustc.args(&["-Csplit-debuginfo=packed", "-Zunstable-options"]); + rustc.args(&["-Csplit-debuginfo=packed"]); } None => {} } @@ -2032,15 +2020,9 @@ impl<'test> TestCx<'test> { } if self.props.force_host { - self.maybe_add_external_args( - &mut rustc, - self.split_maybe_args(&self.config.host_rustcflags), - ); + self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags); } else { - self.maybe_add_external_args( - &mut rustc, - self.split_maybe_args(&self.config.target_rustcflags), - ); + self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags); if !is_rustdoc { if let Some(ref linker) = self.config.linker { rustc.arg(format!("-Clinker={}", linker)); @@ -2560,14 +2542,13 @@ impl<'test> TestCx<'test> { let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); json_out.set_extension("json"); + let res = self.cmd2procres( - Command::new(&self.config.python) - .arg(root.join("src/etc/check_missing_items.py")) - .arg(&json_out), + Command::new(self.config.jsondoclint_path.as_ref().unwrap()).arg(&json_out), ); if !res.status.success() { - self.fatal_proc_rec("check_missing_items failed!", &res); + self.fatal_proc_rec("jsondoclint failed!", &res); } } @@ -2591,7 +2572,7 @@ impl<'test> TestCx<'test> { } None } else { - let sline = line.split("///").last().unwrap_or(""); + let sline = line.rsplit("///").next().unwrap(); let line = sline.trim_start(); if line.starts_with("```") { if ignore { @@ -3127,7 +3108,7 @@ impl<'test> TestCx<'test> { output_kind: TestOutput, explicit_format: bool, ) -> usize { - let stderr_bits = format!("{}.stderr", get_pointer_width(&self.config.target)); + let stderr_bits = format!("{}bit.stderr", self.config.get_pointer_width()); let (stderr_kind, stdout_kind) = match output_kind { TestOutput::Compile => ( { @@ -3402,7 +3383,7 @@ impl<'test> TestCx<'test> { let mut bit_width = String::new(); if test_file_contents.lines().any(|l| l == "// EMIT_MIR_FOR_EACH_BIT_WIDTH") { - bit_width = format!(".{}", get_pointer_width(&self.config.target)); + bit_width = format!(".{}bit", self.config.get_pointer_width()); } if self.config.bless { @@ -3762,7 +3743,7 @@ impl<'test> TestCx<'test> { fn delete_file(&self, file: &PathBuf) { if !file.exists() { - // Deleting a nonexistant file would error. + // Deleting a nonexistent file would error. return; } if let Err(e) = fs::remove_file(file) { diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 22df18ee9..e5ff0906b 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -8,90 +8,18 @@ use tracing::*; #[cfg(test)] mod tests; -/// Conversion table from triple OS name to Rust SYSNAME -const OS_TABLE: &[(&str, &str)] = &[ - ("android", "android"), - ("androideabi", "android"), - ("cuda", "cuda"), - ("darwin", "macos"), - ("dragonfly", "dragonfly"), - ("emscripten", "emscripten"), - ("freebsd", "freebsd"), - ("fuchsia", "fuchsia"), - ("haiku", "haiku"), - ("hermit", "hermit"), - ("illumos", "illumos"), - ("ios", "ios"), - ("l4re", "l4re"), - ("linux", "linux"), - ("mingw32", "windows"), - ("none", "none"), - ("netbsd", "netbsd"), - ("openbsd", "openbsd"), - ("redox", "redox"), - ("sgx", "sgx"), - ("solaris", "solaris"), - ("watchos", "watchos"), - ("win32", "windows"), - ("windows", "windows"), - ("vxworks", "vxworks"), -]; - -const ARCH_TABLE: &[(&str, &str)] = &[ - ("aarch64", "aarch64"), - ("aarch64_be", "aarch64"), - ("amd64", "x86_64"), - ("arm", "arm"), - ("arm64", "aarch64"), - ("armv4t", "arm"), - ("armv5te", "arm"), - ("armv7", "arm"), - ("armv7s", "arm"), - ("asmjs", "asmjs"), - ("avr", "avr"), - ("bpfeb", "bpf"), - ("bpfel", "bpf"), - ("hexagon", "hexagon"), - ("i386", "x86"), - ("i586", "x86"), - ("i686", "x86"), - ("m68k", "m68k"), - ("mips", "mips"), - ("mips64", "mips64"), - ("mips64el", "mips64"), - ("mipsisa32r6", "mips"), - ("mipsisa32r6el", "mips"), - ("mipsisa64r6", "mips64"), - ("mipsisa64r6el", "mips64"), - ("mipsel", "mips"), - ("mipsisa32r6", "mips"), - ("mipsisa32r6el", "mips"), - ("mipsisa64r6", "mips64"), - ("mipsisa64r6el", "mips64"), - ("msp430", "msp430"), - ("nvptx64", "nvptx64"), - ("powerpc", "powerpc"), - ("powerpc64", "powerpc64"), - ("powerpc64le", "powerpc64"), - ("riscv64gc", "riscv64"), - ("s390x", "s390x"), - ("sparc", "sparc"), - ("sparc64", "sparc64"), - ("sparcv9", "sparc64"), - ("thumbv6m", "thumb"), - ("thumbv7em", "thumb"), - ("thumbv7m", "thumb"), - ("wasm32", "wasm32"), - ("x86_64", "x86_64"), - ("xcore", "xcore"), -]; - pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[ "aarch64-apple-darwin", "aarch64-fuchsia", + "aarch64-linux-android", "aarch64-unknown-linux-gnu", + "arm-linux-androideabi", + "armv7-linux-androideabi", + "i686-linux-android", + "i686-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-fuchsia", + "x86_64-linux-android", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu", ]; @@ -140,80 +68,6 @@ pub const MEMTAG_SUPPORTED_TARGETS: &[&str] = pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"]; -const BIG_ENDIAN: &[&str] = &[ - "aarch64_be", - "armebv7r", - "mips", - "mips64", - "mipsisa32r6", - "mipsisa64r6", - "powerpc", - "powerpc64", - "s390x", - "sparc", - "sparc64", - "sparcv9", -]; - -static ASM_SUPPORTED_ARCHS: &[&str] = &[ - "x86", "x86_64", "arm", "aarch64", "riscv32", - "riscv64", - // These targets require an additional asm_experimental_arch feature. - // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32", -]; - -pub fn has_asm_support(triple: &str) -> bool { - ASM_SUPPORTED_ARCHS.contains(&get_arch(triple)) -} - -pub fn matches_os(triple: &str, name: &str) -> bool { - // For the wasm32 bare target we ignore anything also ignored on emscripten - // and then we also recognize `wasm32-bare` as the os for the target - if triple == "wasm32-unknown-unknown" { - return name == "emscripten" || name == "wasm32-bare"; - } - let triple: Vec<_> = triple.split('-').collect(); - for &(triple_os, os) in OS_TABLE { - if triple.contains(&triple_os) { - return os == name; - } - } - panic!("Cannot determine OS from triple"); -} - -/// Determine the architecture from `triple` -pub fn get_arch(triple: &str) -> &'static str { - let triple: Vec<_> = triple.split('-').collect(); - for &(triple_arch, arch) in ARCH_TABLE { - if triple.contains(&triple_arch) { - return arch; - } - } - panic!("Cannot determine Architecture from triple"); -} - -/// Determine the endianness from `triple` -pub fn is_big_endian(triple: &str) -> bool { - let triple_arch = triple.split('-').next().unwrap(); - BIG_ENDIAN.contains(&triple_arch) -} - -pub fn matches_env(triple: &str, name: &str) -> bool { - if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false } -} - -pub fn get_pointer_width(triple: &str) -> &'static str { - if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32")) - || triple.starts_with("s390x") - { - "64bit" - } else if triple.starts_with("avr") { - "16bit" - } else { - "32bit" - } -} - pub fn make_new_path(path: &str) -> String { assert!(cfg!(windows)); // Windows just uses PATH as the library search path, so we have to diff --git a/src/tools/compiletest/src/util/tests.rs b/src/tools/compiletest/src/util/tests.rs index 663027173..b09a183b1 100644 --- a/src/tools/compiletest/src/util/tests.rs +++ b/src/tools/compiletest/src/util/tests.rs @@ -1,43 +1,6 @@ use super::*; #[test] -#[should_panic(expected = "Cannot determine Architecture from triple")] -fn test_get_arch_failure() { - get_arch("abc"); -} - -#[test] -fn test_get_arch() { - assert_eq!("x86_64", get_arch("x86_64-unknown-linux-gnu")); - assert_eq!("x86_64", get_arch("amd64")); - assert_eq!("nvptx64", get_arch("nvptx64-nvidia-cuda")); -} - -#[test] -#[should_panic(expected = "Cannot determine OS from triple")] -fn test_matches_os_failure() { - matches_os("abc", "abc"); -} - -#[test] -fn test_matches_os() { - assert!(matches_os("x86_64-unknown-linux-gnu", "linux")); - assert!(matches_os("wasm32-unknown-unknown", "emscripten")); - assert!(matches_os("wasm32-unknown-unknown", "wasm32-bare")); - assert!(!matches_os("wasm32-unknown-unknown", "windows")); - assert!(matches_os("thumbv6m0-none-eabi", "none")); - assert!(matches_os("riscv32imc-unknown-none-elf", "none")); - assert!(matches_os("nvptx64-nvidia-cuda", "cuda")); - assert!(matches_os("x86_64-fortanix-unknown-sgx", "sgx")); -} - -#[test] -fn is_big_endian_test() { - assert!(!is_big_endian("no")); - assert!(is_big_endian("sparc-unknown-unknown")); -} - -#[test] fn path_buf_with_extra_extension_test() { assert_eq!( PathBuf::from("foo.rs.stderr"), |