Skip to content

Commit bc315aa

Browse files
Evaulate cfg props for the real target in compiletest
1 parent cbb3b03 commit bc315aa

File tree

4 files changed

+129
-74
lines changed

4 files changed

+129
-74
lines changed

src/tools/compiletest/src/common.rs

-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
pub use self::Mode::*;
22

3-
use std::collections::HashMap;
43
use std::ffi::OsString;
54
use std::fmt;
65
use std::path::{Path, PathBuf};
@@ -276,10 +275,6 @@ pub struct Config {
276275
/// not vice versa.
277276
pub target_panic: PanicStrategy,
278277

279-
/// A map from target cfg keys to their values. If the key is present with no value,
280-
/// the vector will contain the empty string.
281-
pub target_cfg: HashMap<String, Vec<String>>,
282-
283278
/// Target system to be tested
284279
pub target: String,
285280

src/tools/compiletest/src/header.rs

+106-42
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ use crate::{extract_cdb_version, extract_gdb_version};
1616
#[cfg(test)]
1717
mod tests;
1818

19-
/// The result of parse_cfg_name_directive.
19+
/// Whether a given property holds true of this test instance. Usually,
20+
/// a property is something about the target (e.g. whether the target is Windows),
21+
/// but it could also be something more general (e.g. whether this test is being
22+
/// cross-compiled.)
2023
#[derive(Clone, Copy, PartialEq, Debug)]
21-
enum ParsedNameDirective {
24+
enum EvaluatedProp {
2225
/// No match.
2326
NoMatch,
2427
/// Match.
@@ -228,6 +231,10 @@ impl TestProps {
228231
if !testfile.is_dir() {
229232
let file = File::open(testfile).unwrap();
230233

234+
let mut target = config.target.clone();
235+
let mut per_prop_normalize_stdout: Vec<(String, (String, String))> = Vec::new();
236+
let mut per_prop_normalize_stderr: Vec<(String, (String, String))> = Vec::new();
237+
231238
iter_header(testfile, file, &mut |revision, ln| {
232239
if revision.is_some() && revision != cfg {
233240
return;
@@ -340,11 +347,16 @@ impl TestProps {
340347
self.ignore_pass = config.parse_ignore_pass(ln);
341348
}
342349

350+
if let Some(target_override) = config.parse_target_override(ln) {
351+
target = target_override;
352+
}
353+
343354
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stdout") {
344-
self.normalize_stdout.push(rule);
355+
per_prop_normalize_stdout.push(rule);
345356
}
357+
346358
if let Some(rule) = config.parse_custom_normalization(ln, "normalize-stderr") {
347-
self.normalize_stderr.push(rule);
359+
per_prop_normalize_stderr.push(rule);
348360
}
349361

350362
if let Some(code) = config.parse_failure_status(ln) {
@@ -372,6 +384,17 @@ impl TestProps {
372384
self.incremental = config.parse_incremental(ln);
373385
}
374386
});
387+
for (prop, normalization) in per_prop_normalize_stdout {
388+
if config.evaluate_prop_for_target(&prop, &target) == EvaluatedProp::Match {
389+
self.normalize_stdout.push(normalization);
390+
}
391+
}
392+
393+
for (prop, normalization) in per_prop_normalize_stderr {
394+
if config.evaluate_prop_for_target(&prop, &target) == EvaluatedProp::Match {
395+
self.normalize_stderr.push(normalization);
396+
}
397+
}
375398
}
376399

377400
if self.failure_status == -1 {
@@ -650,14 +673,15 @@ impl Config {
650673
}
651674
}
652675

653-
fn parse_custom_normalization(&self, mut line: &str, prefix: &str) -> Option<(String, String)> {
654-
if self.parse_cfg_name_directive(line, prefix) == ParsedNameDirective::Match {
655-
let from = parse_normalization_string(&mut line)?;
656-
let to = parse_normalization_string(&mut line)?;
657-
Some((from, to))
658-
} else {
659-
None
660-
}
676+
fn parse_custom_normalization(
677+
&self,
678+
mut line: &str,
679+
prefix: &str,
680+
) -> Option<(String, (String, String))> {
681+
let prop = self.parse_prop_directive(line, prefix)?;
682+
let from = parse_normalization_string(&mut line)?;
683+
let to = parse_normalization_string(&mut line)?;
684+
Some((prop, (from, to)))
661685
}
662686

663687
fn parse_needs_matching_clang(&self, line: &str) -> bool {
@@ -670,7 +694,19 @@ impl Config {
670694

671695
/// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86`
672696
/// or `normalize-stderr-32bit`.
673-
fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective {
697+
fn parse_prop_directive(&self, line: &str, prefix: &str) -> Option<String> {
698+
if !line.as_bytes().starts_with(prefix.as_bytes()) {
699+
return None;
700+
}
701+
if line.as_bytes().get(prefix.len()) != Some(&b'-') {
702+
return None;
703+
}
704+
705+
let config = &line[&prefix.len() + 1..].to_string();
706+
Some(config.to_string())
707+
}
708+
709+
fn evaluate_prop_for_target(&self, prop: &str, target: &str) -> EvaluatedProp {
674710
// This matches optional whitespace, followed by a group containing a series of word
675711
// characters (including '_' and '-'), followed optionally by a sequence consisting
676712
// of a colon, optional whitespace, and another group containing word characters.
@@ -697,28 +733,21 @@ impl Config {
697733
static ref CFG_REGEX: Regex = Regex::new(r"^\s*([\w-]+)(?::\s*([\w-]+))?").unwrap();
698734
}
699735

700-
if !line.as_bytes().starts_with(prefix.as_bytes()) {
701-
return ParsedNameDirective::NoMatch;
702-
}
703-
if line.as_bytes().get(prefix.len()) != Some(&b'-') {
704-
return ParsedNameDirective::NoMatch;
705-
}
706-
707-
let captures = CFG_REGEX.captures(&line[&prefix.len() + 1..]).unwrap();
736+
let captures = CFG_REGEX.captures(&prop).unwrap();
708737
let name = captures.get(1).unwrap().as_str();
709738
let maybe_value = captures.get(2).map(|v| v.as_str().trim());
710739

711740
let is_match = name == "test" ||
712-
self.target == name || // triple
713-
util::matches_os(&self.target, name) || // target
714-
util::matches_env(&self.target, name) || // env
715-
self.target.ends_with(name) || // target and env
716-
name == util::get_arch(&self.target) || // architecture
717-
name == util::get_pointer_width(&self.target) || // pointer width
741+
target == name || // triple
742+
util::matches_os(target, name) || // target
743+
util::matches_env(target, name) || // env
744+
target.ends_with(name) || // target and env
745+
name == util::get_arch(target) || // architecture
746+
name == util::get_pointer_width(target) || // pointer width
718747
name == self.stage_id.split('-').next().unwrap() || // stage
719748
name == self.channel || // channel
720-
(self.target != self.host && name == "cross-compile") ||
721-
(name == "endian-big" && util::is_big_endian(&self.target)) ||
749+
(target != self.host && name == "cross-compile") ||
750+
(name == "endian-big" && util::is_big_endian(target)) ||
722751
(self.remote_test_client.is_some() && name == "remote") ||
723752
match self.compare_mode {
724753
Some(CompareMode::Nll) => name == "compare-mode-nll",
@@ -736,14 +765,17 @@ impl Config {
736765
None => false,
737766
} ||
738767
match name.strip_prefix("cfg-") {
739-
Some(rustc_cfg_name) => util::cfg_has(&self.target_cfg, rustc_cfg_name, maybe_value),
768+
Some(rustc_cfg_name) => {
769+
let cfg_data = util::fetch_cfg_from_rustc_for_target(&self.rustc_path, target);
770+
util::cfg_has(&cfg_data, rustc_cfg_name, maybe_value)
771+
},
740772
None => false
741773
};
742774

743-
if is_match { ParsedNameDirective::Match } else { ParsedNameDirective::NoMatch }
775+
if is_match { EvaluatedProp::Match } else { EvaluatedProp::NoMatch }
744776
}
745777

746-
fn has_cfg_prefix(&self, line: &str, prefix: &str) -> bool {
778+
fn has_prop_prefix(&self, line: &str, prefix: &str) -> bool {
747779
// returns whether this line contains this prefix or not. For prefix
748780
// "ignore", returns true if line says "ignore-x86_64", "ignore-arch",
749781
// "ignore-android" etc.
@@ -768,6 +800,21 @@ impl Config {
768800
}
769801
}
770802

803+
pub fn parse_target_override(&self, line: &str) -> Option<String> {
804+
let flags = self.parse_name_value_directive(line, "compile-flags")?;
805+
let (_, tail) = flags.split_once("--target")?;
806+
if tail.starts_with(|c: char| c.is_whitespace() || c == '=') {
807+
let tail = &tail[1..];
808+
let target = match tail.split_once(|c: char| c.is_whitespace()) {
809+
Some((target, _)) => target,
810+
None => &tail,
811+
};
812+
Some(target.to_string())
813+
} else {
814+
None
815+
}
816+
}
817+
771818
pub fn find_rust_src_root(&self) -> Option<PathBuf> {
772819
let mut path = self.src_base.clone();
773820
let path_postfix = Path::new("src/etc/lldb_batchmode.py");
@@ -900,6 +947,10 @@ pub fn make_test_description<R: Read>(
900947
let mut ignore = false;
901948
let mut should_fail = false;
902949

950+
let mut target = config.target.clone();
951+
let mut ignored_props: Vec<String> = Vec::new();
952+
let mut only_test_on_props: Vec<String> = Vec::new();
953+
903954
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
904955
let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
905956
let has_asm_support = util::has_asm_support(&config.target);
@@ -908,7 +959,6 @@ pub fn make_test_description<R: Read>(
908959
let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target);
909960
let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target);
910961
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
911-
// for `-Z gcc-ld=lld`
912962
let has_rust_lld = config
913963
.compile_lib_path
914964
.join("rustlib")
@@ -921,15 +971,16 @@ pub fn make_test_description<R: Read>(
921971
if revision.is_some() && revision != cfg {
922972
return;
923973
}
924-
ignore = match config.parse_cfg_name_directive(ln, "ignore") {
925-
ParsedNameDirective::Match => true,
926-
ParsedNameDirective::NoMatch => ignore,
927-
};
928-
if config.has_cfg_prefix(ln, "only") {
929-
ignore = match config.parse_cfg_name_directive(ln, "only") {
930-
ParsedNameDirective::Match => ignore,
931-
ParsedNameDirective::NoMatch => true,
932-
};
974+
if let Some(target_override) = config.parse_target_override(ln) {
975+
target = target_override;
976+
}
977+
if let Some(prop) = config.parse_prop_directive(ln, "ignore") {
978+
ignored_props.push(prop);
979+
}
980+
if config.has_prop_prefix(ln, "only") {
981+
if let Some(prop) = config.parse_prop_directive(ln, "only") {
982+
only_test_on_props.push(prop);
983+
}
933984
}
934985
ignore |= ignore_llvm(config, ln);
935986
ignore |=
@@ -954,6 +1005,19 @@ pub fn make_test_description<R: Read>(
9541005
should_fail |= config.parse_name_directive(ln, "should-fail");
9551006
});
9561007

1008+
for prop in ignored_props {
1009+
ignore = match config.evaluate_prop_for_target(&prop, &target) {
1010+
EvaluatedProp::Match => true,
1011+
EvaluatedProp::NoMatch => ignore,
1012+
};
1013+
}
1014+
for prop in only_test_on_props {
1015+
ignore = match config.evaluate_prop_for_target(&prop, &target) {
1016+
EvaluatedProp::Match => ignore,
1017+
EvaluatedProp::NoMatch => true,
1018+
};
1019+
}
1020+
9571021
// The `should-fail` annotation doesn't apply to pretty tests,
9581022
// since we run the pretty printer across all tests by default.
9591023
// If desired, we could add a `should-fail-pretty` annotation.

src/tools/compiletest/src/main.rs

-14
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::common::{
1111
use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths};
1212
use crate::util::logv;
1313
use getopts::Options;
14-
use std::collections::HashMap;
1514
use std::env;
1615
use std::ffi::OsString;
1716
use std::fs;
@@ -217,18 +216,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
217216
false
218217
};
219218

220-
let target_cfg = if cfg!(test) {
221-
HashMap::new()
222-
} else {
223-
let rustc_cfg_data = Command::new(&rustc_path)
224-
.args(&["--target", &target])
225-
.args(&["--print", "cfg"])
226-
.output()
227-
.unwrap()
228-
.stdout;
229-
util::parse_rustc_cfg(String::from_utf8(rustc_cfg_data).unwrap())
230-
};
231-
232219
Config {
233220
bless: matches.opt_present("bless"),
234221
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
@@ -272,7 +259,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
272259
Some("abort") => PanicStrategy::Abort,
273260
_ => panic!("unknown `--target-panic` option `{}` given", mode),
274261
},
275-
target_cfg,
276262
target,
277263
host: opt_str2(matches.opt_str("host")),
278264
cdb,

src/tools/compiletest/src/util.rs

+23-13
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::collections::HashMap;
44
use std::env;
55
use std::ffi::OsStr;
66
use std::path::PathBuf;
7+
use std::process::Command;
78

89
use tracing::*;
910

@@ -217,22 +218,31 @@ pub fn logv(config: &Config, s: String) {
217218
}
218219
}
219220

220-
/// Parses the output of `rustc --print cfg` into a [`HashMap`] containing
221-
/// the cfg values for each name. If the name is present with no value,
222-
/// it is treated as having a value of "".
223-
pub fn parse_rustc_cfg(rustc_output: String) -> HashMap<String, Vec<String>> {
224-
let mut map = HashMap::new();
221+
pub fn fetch_cfg_from_rustc_for_target<P: AsRef<OsStr>>(
222+
rustc_path: &P,
223+
target: &str,
224+
) -> HashMap<String, Vec<String>> {
225+
let mut target_cfg = HashMap::new();
225226

226-
for line in rustc_output.lines() {
227-
if let Some((name, value)) = line.split_once('=') {
228-
let normalized_value = value.trim_matches('"');
229-
cfg_add(&mut map, name, normalized_value);
230-
} else {
231-
cfg_add(&mut map, line, "");
227+
if !cfg!(test) {
228+
let rustc_output = Command::new(&rustc_path)
229+
.args(&["--target", &target])
230+
.args(&["--print", "cfg"])
231+
.output()
232+
.unwrap()
233+
.stdout;
234+
let rustc_output = String::from_utf8(rustc_output).unwrap();
235+
236+
for line in rustc_output.lines() {
237+
if let Some((name, value)) = line.split_once('=') {
238+
let normalized_value = value.trim_matches('"');
239+
cfg_add(&mut target_cfg, name, normalized_value);
240+
} else {
241+
cfg_add(&mut target_cfg, line, "");
242+
}
232243
}
233244
}
234-
235-
return map;
245+
target_cfg
236246
}
237247

238248
/// Adds the given name and value to the provided cfg [`HashMap`]. If the `name` already

0 commit comments

Comments
 (0)