Skip to content

Commit fab8996

Browse files
committed
compiletest: use precise cfg matching instead of hard-coded tables
1 parent 9ee22ff commit fab8996

File tree

9 files changed

+302
-208
lines changed

9 files changed

+302
-208
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,7 @@ dependencies = [
816816
"getopts",
817817
"glob",
818818
"lazy_static",
819+
"lazycell",
819820
"libc",
820821
"miow",
821822
"regex",

src/tools/compiletest/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ rustfix = "0.6.0"
1717
lazy_static = "1.0"
1818
walkdir = "2"
1919
glob = "0.3.0"
20+
lazycell = "1.3.0"
2021

2122
[target.'cfg(unix)'.dependencies]
2223
libc = "0.2"

src/tools/compiletest/src/common.rs

+121
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ pub use self::Mode::*;
33
use std::ffi::OsString;
44
use std::fmt;
55
use std::path::{Path, PathBuf};
6+
use std::process::Command;
67
use std::str::FromStr;
78

89
use crate::util::PathBufExt;
10+
use lazycell::LazyCell;
911
use test::ColorConfig;
1012

1113
#[derive(Clone, Copy, PartialEq, Debug)]
@@ -371,6 +373,8 @@ pub struct Config {
371373

372374
/// Whether to rerun tests even if the inputs are unchanged.
373375
pub force_rerun: bool,
376+
377+
pub target_cfg: LazyCell<TargetCfg>,
374378
}
375379

376380
impl Config {
@@ -380,6 +384,123 @@ impl Config {
380384
!self.target.ends_with("-fuchsia")
381385
})
382386
}
387+
388+
fn target_cfg(&self) -> &TargetCfg {
389+
self.target_cfg.borrow_with(|| TargetCfg::new(&self.rustc_path, &self.target))
390+
}
391+
392+
pub fn matches_arch(&self, arch: &str) -> bool {
393+
self.target_cfg().arch == arch ||
394+
// Shorthand for convenience. The arch for
395+
// asmjs-unknown-emscripten is actually wasm32.
396+
(arch == "asmjs" && self.target.starts_with("asmjs")) ||
397+
// Matching all the thumb variants as one can be convenient.
398+
// (thumbv6m, thumbv7em, thumbv7m, etc.)
399+
(arch == "thumb" && self.target.starts_with("thumb"))
400+
}
401+
402+
pub fn matches_os(&self, os: &str) -> bool {
403+
self.target_cfg().os == os
404+
}
405+
406+
pub fn matches_env(&self, env: &str) -> bool {
407+
self.target_cfg().env == env
408+
}
409+
410+
pub fn matches_abi(&self, abi: &str) -> bool {
411+
self.target_cfg().abi == abi
412+
}
413+
414+
pub fn is_big_endian(&self) -> bool {
415+
self.target_cfg().endian == Endian::Big
416+
}
417+
418+
pub fn get_pointer_width(&self) -> u32 {
419+
*&self.target_cfg().pointer_width
420+
}
421+
422+
pub fn has_asm_support(&self) -> bool {
423+
static ASM_SUPPORTED_ARCHS: &[&str] = &[
424+
"x86", "x86_64", "arm", "aarch64", "riscv32",
425+
"riscv64",
426+
// These targets require an additional asm_experimental_arch feature.
427+
// "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
428+
];
429+
ASM_SUPPORTED_ARCHS.contains(&self.target_cfg().arch.as_str())
430+
}
431+
}
432+
433+
#[derive(Clone, Debug)]
434+
pub struct TargetCfg {
435+
arch: String,
436+
os: String,
437+
env: String,
438+
abi: String,
439+
pointer_width: u32,
440+
endian: Endian,
441+
}
442+
443+
#[derive(Eq, PartialEq, Clone, Debug)]
444+
pub enum Endian {
445+
Little,
446+
Big,
447+
}
448+
449+
impl TargetCfg {
450+
fn new(rustc_path: &Path, target: &str) -> TargetCfg {
451+
let output = match Command::new(rustc_path)
452+
.arg("--print=cfg")
453+
.arg("--target")
454+
.arg(target)
455+
.output()
456+
{
457+
Ok(output) => output,
458+
Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", rustc_path),
459+
};
460+
if !output.status.success() {
461+
panic!(
462+
"error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}",
463+
rustc_path,
464+
String::from_utf8(output.stdout).unwrap(),
465+
String::from_utf8(output.stderr).unwrap(),
466+
);
467+
}
468+
let print_cfg = String::from_utf8(output.stdout).unwrap();
469+
let mut arch = None;
470+
let mut os = None;
471+
let mut env = None;
472+
let mut abi = None;
473+
let mut pointer_width = None;
474+
let mut endian = None;
475+
for line in print_cfg.lines() {
476+
if let Some((name, value)) = line.split_once('=') {
477+
let value = value.trim_matches('"');
478+
match name {
479+
"target_arch" => arch = Some(value),
480+
"target_os" => os = Some(value),
481+
"target_env" => env = Some(value),
482+
"target_abi" => abi = Some(value),
483+
"target_pointer_width" => pointer_width = Some(value.parse().unwrap()),
484+
"target_endian" => {
485+
endian = Some(match value {
486+
"little" => Endian::Little,
487+
"big" => Endian::Big,
488+
s => panic!("unexpected {s}"),
489+
})
490+
}
491+
_ => {}
492+
}
493+
}
494+
}
495+
TargetCfg {
496+
arch: arch.unwrap().to_string(),
497+
os: os.unwrap().to_string(),
498+
env: env.unwrap().to_string(),
499+
abi: abi.unwrap().to_string(),
500+
pointer_width: pointer_width.unwrap(),
501+
endian: endian.unwrap(),
502+
}
503+
}
383504
}
384505

385506
#[derive(Debug, Clone)]

src/tools/compiletest/src/header.rs

+24-6
Original file line numberDiff line numberDiff line change
@@ -661,17 +661,35 @@ impl Config {
661661

662662
let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap();
663663

664+
let matches_pointer_width = || {
665+
name.strip_suffix("bit")
666+
.and_then(|width| width.parse::<u32>().ok())
667+
.map(|width| self.get_pointer_width() == width)
668+
.unwrap_or(false)
669+
};
670+
671+
// If something is ignored for emscripten, it likely also needs to be
672+
// ignored for wasm32-unknown-unknown.
673+
// `wasm32-bare` is an alias to refer to just wasm32-unknown-unknown
674+
// (in contrast to `wasm32` which also matches non-bare targets like
675+
// asmjs-unknown-emscripten).
676+
let matches_wasm32_alias = || {
677+
self.target == "wasm32-unknown-unknown" && matches!(name, "emscripten" | "wasm32-bare")
678+
};
679+
664680
let is_match = name == "test" ||
665681
self.target == name || // triple
666-
util::matches_os(&self.target, name) || // target
667-
util::matches_env(&self.target, name) || // env
682+
self.matches_os(name) ||
683+
self.matches_env(name) ||
684+
self.matches_abi(name) ||
668685
self.target.ends_with(name) || // target and env
669-
name == util::get_arch(&self.target) || // architecture
670-
name == util::get_pointer_width(&self.target) || // pointer width
686+
self.matches_arch(name) ||
687+
matches_wasm32_alias() ||
688+
matches_pointer_width() ||
671689
name == self.stage_id.split('-').next().unwrap() || // stage
672690
name == self.channel || // channel
673691
(self.target != self.host && name == "cross-compile") ||
674-
(name == "endian-big" && util::is_big_endian(&self.target)) ||
692+
(name == "endian-big" && self.is_big_endian()) ||
675693
(self.remote_test_client.is_some() && name == "remote") ||
676694
match self.compare_mode {
677695
Some(CompareMode::Polonius) => name == "compare-mode-polonius",
@@ -869,7 +887,7 @@ pub fn make_test_description<R: Read>(
869887

870888
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
871889
let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
872-
let has_asm_support = util::has_asm_support(&config.target);
890+
let has_asm_support = config.has_asm_support();
873891
let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
874892
let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target);
875893
let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);

src/tools/compiletest/src/header/tests.rs

+149-9
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ fn config() -> Config {
4242
"--suite=ui",
4343
"--compile-lib-path=",
4444
"--run-lib-path=",
45-
"--rustc-path=",
4645
"--python=",
4746
"--jsondocck-path=",
4847
"--src-base=",
@@ -57,7 +56,9 @@ fn config() -> Config {
5756
"--target=x86_64-unknown-linux-gnu",
5857
"--channel=nightly",
5958
];
60-
let args = args.iter().map(ToString::to_string).collect();
59+
let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
60+
args.push("--rustc-path".to_string());
61+
args.push(std::env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string()));
6162
crate::parse_config(args)
6263
}
6364

@@ -237,13 +238,20 @@ fn sanitizers() {
237238

238239
#[test]
239240
fn asm_support() {
240-
let mut config = config();
241-
242-
config.target = "avr-unknown-gnu-atmega328".to_owned();
243-
assert!(check_ignore(&config, "// needs-asm-support"));
244-
245-
config.target = "i686-unknown-netbsd".to_owned();
246-
assert!(!check_ignore(&config, "// needs-asm-support"));
241+
let asms = [
242+
("avr-unknown-gnu-atmega328", false),
243+
("i686-unknown-netbsd", true),
244+
("riscv32gc-unknown-linux-gnu", true),
245+
("riscv64imac-unknown-none-elf", true),
246+
("x86_64-unknown-linux-gnu", true),
247+
("i686-unknown-netbsd", true),
248+
];
249+
for (target, has_asm) in asms {
250+
let mut config = config();
251+
config.target = target.to_string();
252+
assert_eq!(config.has_asm_support(), has_asm);
253+
assert_eq!(check_ignore(&config, "// needs-asm-support"), !has_asm)
254+
}
247255
}
248256

249257
#[test]
@@ -281,3 +289,135 @@ fn test_duplicate_revisions() {
281289
let config = config();
282290
parse_rs(&config, "// revisions: rpass1 rpass1");
283291
}
292+
293+
#[test]
294+
fn ignore_arch() {
295+
let archs = [
296+
("x86_64-unknown-linux-gnu", "x86_64"),
297+
("i686-unknown-linux-gnu", "x86"),
298+
("nvptx64-nvidia-cuda", "nvptx64"),
299+
("asmjs-unknown-emscripten", "wasm32"),
300+
("asmjs-unknown-emscripten", "asmjs"),
301+
("thumbv7m-none-eabi", "thumb"),
302+
];
303+
for (target, arch) in archs {
304+
let mut config = config();
305+
config.target = target.to_string();
306+
assert!(config.matches_arch(arch), "{target} {arch}");
307+
assert!(check_ignore(&config, &format!("// ignore-{arch}")));
308+
}
309+
}
310+
311+
#[test]
312+
fn matches_os() {
313+
let oss = [
314+
("x86_64-unknown-linux-gnu", "linux"),
315+
("x86_64-fortanix-unknown-sgx", "unknown"),
316+
("wasm32-unknown-unknown", "unknown"),
317+
("x86_64-unknown-none", "none"),
318+
];
319+
for (target, os) in oss {
320+
let mut config = config();
321+
config.target = target.to_string();
322+
assert!(config.matches_os(os), "{target} {os}");
323+
assert!(check_ignore(&config, &format!("// ignore-{os}")));
324+
}
325+
}
326+
327+
#[test]
328+
fn matches_env() {
329+
let envs = [
330+
("x86_64-unknown-linux-gnu", "gnu"),
331+
("x86_64-fortanix-unknown-sgx", "sgx"),
332+
("arm-unknown-linux-musleabi", "musl"),
333+
];
334+
for (target, env) in envs {
335+
let mut config = config();
336+
config.target = target.to_string();
337+
assert!(config.matches_env(env), "{target} {env}");
338+
assert!(check_ignore(&config, &format!("// ignore-{env}")));
339+
}
340+
}
341+
342+
#[test]
343+
fn matches_abi() {
344+
let abis = [
345+
("aarch64-apple-ios-macabi", "macabi"),
346+
("x86_64-unknown-linux-gnux32", "x32"),
347+
("arm-unknown-linux-gnueabi", "eabi"),
348+
];
349+
for (target, abi) in abis {
350+
let mut config = config();
351+
config.target = target.to_string();
352+
assert!(config.matches_abi(abi), "{target} {abi}");
353+
assert!(check_ignore(&config, &format!("// ignore-{abi}")));
354+
}
355+
}
356+
357+
#[test]
358+
fn is_big_endian() {
359+
let endians = [
360+
("x86_64-unknown-linux-gnu", false),
361+
("bpfeb-unknown-none", true),
362+
("m68k-unknown-linux-gnu", true),
363+
("aarch64_be-unknown-linux-gnu", true),
364+
("powerpc64-unknown-linux-gnu", true),
365+
];
366+
for (target, is_big) in endians {
367+
let mut config = config();
368+
config.target = target.to_string();
369+
assert_eq!(config.is_big_endian(), is_big, "{target} {is_big}");
370+
assert_eq!(check_ignore(&config, "// ignore-endian-big"), is_big);
371+
}
372+
}
373+
374+
#[test]
375+
fn pointer_width() {
376+
let widths = [
377+
("x86_64-unknown-linux-gnu", 64),
378+
("i686-unknown-linux-gnu", 32),
379+
("arm64_32-apple-watchos", 32),
380+
("msp430-none-elf", 16),
381+
];
382+
for (target, width) in widths {
383+
let mut config = config();
384+
config.target = target.to_string();
385+
assert_eq!(config.get_pointer_width(), width, "{target} {width}");
386+
assert_eq!(check_ignore(&config, "// ignore-16bit"), width == 16);
387+
assert_eq!(check_ignore(&config, "// ignore-32bit"), width == 32);
388+
assert_eq!(check_ignore(&config, "// ignore-64bit"), width == 64);
389+
}
390+
}
391+
392+
#[test]
393+
fn wasm_special() {
394+
let ignores = [
395+
("wasm32-unknown-unknown", "emscripten", true),
396+
("wasm32-unknown-unknown", "wasm32", true),
397+
("wasm32-unknown-unknown", "wasm32-bare", true),
398+
("wasm32-unknown-unknown", "wasm64", false),
399+
("asmjs-unknown-emscripten", "emscripten", true),
400+
("asmjs-unknown-emscripten", "wasm32", true),
401+
("asmjs-unknown-emscripten", "wasm32-bare", false),
402+
("wasm32-unknown-emscripten", "emscripten", true),
403+
("wasm32-unknown-emscripten", "wasm32", true),
404+
("wasm32-unknown-emscripten", "wasm32-bare", false),
405+
("wasm32-wasi", "emscripten", false),
406+
("wasm32-wasi", "wasm32", true),
407+
("wasm32-wasi", "wasm32-bare", false),
408+
("wasm32-wasi", "wasi", true),
409+
("wasm64-unknown-unknown", "emscripten", false),
410+
("wasm64-unknown-unknown", "wasm32", false),
411+
("wasm64-unknown-unknown", "wasm32-bare", false),
412+
("wasm64-unknown-unknown", "wasm64", true),
413+
];
414+
for (target, pattern, ignore) in ignores {
415+
let mut config = config();
416+
config.target = target.to_string();
417+
assert_eq!(
418+
check_ignore(&config, &format!("// ignore-{pattern}")),
419+
ignore,
420+
"{target} {pattern}"
421+
);
422+
}
423+
}

0 commit comments

Comments
 (0)