Skip to content

Commit 9bc8bb9

Browse files
committed
validate ignore-FOO/only-FOO directives and output only-FOO reasoning
1 parent 4e2a982 commit 9bc8bb9

File tree

3 files changed

+178
-38
lines changed

3 files changed

+178
-38
lines changed

src/tools/compiletest/src/common.rs

Lines changed: 95 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::str::FromStr;
99

1010
use crate::util::{add_dylib_path, PathBufExt};
1111
use lazycell::LazyCell;
12+
use std::collections::HashSet;
1213
use test::{ColorConfig, OutputFormat};
1314

1415
#[derive(Clone, Copy, PartialEq, Debug)]
@@ -129,6 +130,14 @@ pub enum CompareMode {
129130
}
130131

131132
impl CompareMode {
133+
pub(crate) const VARIANTS: &'static [CompareMode] = &[
134+
CompareMode::Polonius,
135+
CompareMode::Chalk,
136+
CompareMode::NextSolver,
137+
CompareMode::SplitDwarf,
138+
CompareMode::SplitDwarfSingle,
139+
];
140+
132141
pub(crate) fn to_str(&self) -> &'static str {
133142
match *self {
134143
CompareMode::Polonius => "polonius",
@@ -159,6 +168,9 @@ pub enum Debugger {
159168
}
160169

161170
impl Debugger {
171+
pub(crate) const VARIANTS: &'static [Debugger] =
172+
&[Debugger::Cdb, Debugger::Gdb, Debugger::Lldb];
173+
162174
pub(crate) fn to_str(&self) -> &'static str {
163175
match self {
164176
Debugger::Cdb => "cdb",
@@ -396,8 +408,12 @@ impl Config {
396408
})
397409
}
398410

411+
pub fn target_cfgs(&self) -> &TargetCfgs {
412+
self.target_cfgs.borrow_with(|| TargetCfgs::new(self))
413+
}
414+
399415
pub fn target_cfg(&self) -> &TargetCfg {
400-
self.target_cfg.borrow_with(|| TargetCfg::new(self))
416+
&self.target_cfgs().current
401417
}
402418

403419
pub fn matches_arch(&self, arch: &str) -> bool {
@@ -449,6 +465,63 @@ impl Config {
449465
}
450466
}
451467

468+
#[derive(Debug, Clone)]
469+
pub struct TargetCfgs {
470+
pub current: TargetCfg,
471+
pub all_targets: HashSet<String>,
472+
pub all_archs: HashSet<String>,
473+
pub all_oses: HashSet<String>,
474+
pub all_envs: HashSet<String>,
475+
pub all_abis: HashSet<String>,
476+
pub all_families: HashSet<String>,
477+
pub all_pointer_widths: HashSet<String>,
478+
}
479+
480+
impl TargetCfgs {
481+
fn new(config: &Config) -> TargetCfgs {
482+
// Gather list of all targets
483+
let targets = rustc_output(config, &["--print=target-list"]);
484+
485+
let mut current = None;
486+
let mut all_targets = HashSet::new();
487+
let mut all_archs = HashSet::new();
488+
let mut all_oses = HashSet::new();
489+
let mut all_envs = HashSet::new();
490+
let mut all_abis = HashSet::new();
491+
let mut all_families = HashSet::new();
492+
let mut all_pointer_widths = HashSet::new();
493+
494+
for target in targets.trim().lines() {
495+
let cfg = TargetCfg::new(config, target);
496+
497+
all_archs.insert(cfg.arch.clone());
498+
all_oses.insert(cfg.os.clone());
499+
all_envs.insert(cfg.env.clone());
500+
all_abis.insert(cfg.abi.clone());
501+
for family in &cfg.families {
502+
all_families.insert(family.clone());
503+
}
504+
all_pointer_widths.insert(format!("{}bit", cfg.pointer_width));
505+
506+
if target == config.target {
507+
current = Some(cfg);
508+
}
509+
all_targets.insert(target.into());
510+
}
511+
512+
Self {
513+
current: current.expect("current target not found"),
514+
all_targets,
515+
all_archs,
516+
all_oses,
517+
all_envs,
518+
all_abis,
519+
all_families,
520+
all_pointer_widths,
521+
}
522+
}
523+
}
524+
452525
#[derive(Clone, Debug)]
453526
pub struct TargetCfg {
454527
pub(crate) arch: String,
@@ -468,28 +541,8 @@ pub enum Endian {
468541
}
469542

470543
impl TargetCfg {
471-
fn new(config: &Config) -> TargetCfg {
472-
let mut command = Command::new(&config.rustc_path);
473-
add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
474-
let output = match command
475-
.arg("--print=cfg")
476-
.arg("--target")
477-
.arg(&config.target)
478-
.args(&config.target_rustcflags)
479-
.output()
480-
{
481-
Ok(output) => output,
482-
Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", config.rustc_path),
483-
};
484-
if !output.status.success() {
485-
panic!(
486-
"error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}",
487-
config.rustc_path,
488-
String::from_utf8(output.stdout).unwrap(),
489-
String::from_utf8(output.stderr).unwrap(),
490-
);
491-
}
492-
let print_cfg = String::from_utf8(output.stdout).unwrap();
544+
fn new(config: &Config, target: &str) -> TargetCfg {
545+
let print_cfg = rustc_output(config, &["--print=cfg", "--target", target]);
493546
let mut arch = None;
494547
let mut os = None;
495548
let mut env = None;
@@ -539,6 +592,25 @@ impl TargetCfg {
539592
}
540593
}
541594

595+
fn rustc_output(config: &Config, args: &[&str]) -> String {
596+
let mut command = Command::new(&config.rustc_path);
597+
add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
598+
command.args(&config.target_rustcflags).args(args);
599+
600+
let output = match command.output() {
601+
Ok(output) => output,
602+
Err(e) => panic!("error: failed to run {command:?}: {e}"),
603+
};
604+
if !output.status.success() {
605+
panic!(
606+
"error: failed to run {command:?}\n--- stdout\n{}\n--- stderr\n{}",
607+
String::from_utf8(output.stdout).unwrap(),
608+
String::from_utf8(output.stderr).unwrap(),
609+
);
610+
}
611+
String::from_utf8(output.stdout).unwrap()
612+
}
613+
542614
#[derive(Debug, Clone)]
543615
pub struct TestPaths {
544616
pub file: PathBuf, // e.g., compile-test/foo/bar/baz.rs

src/tools/compiletest/src/header.rs

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::process::Command;
88

99
use tracing::*;
1010

11+
use crate::common::CompareMode;
1112
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
1213
use crate::util;
1314
use crate::{extract_cdb_version, extract_gdb_version};
@@ -36,6 +37,10 @@ enum MatchOutcome {
3637
NoMatch,
3738
/// Match.
3839
Match,
40+
/// The directive was invalid.
41+
Invalid,
42+
/// The directive is handled by other parts of our tooling.
43+
External,
3944
}
4045

4146
/// Properties which must be known very early, before actually running
@@ -692,60 +697,99 @@ impl Config {
692697
let (name, comment) =
693698
line.split_once(&[':', ' ']).map(|(l, c)| (l, Some(c))).unwrap_or((line, None));
694699

695-
let mut is_match = None;
700+
let mut outcome = MatchOutcome::Invalid;
701+
let mut message = None;
696702

697703
macro_rules! maybe_condition {
698-
(name: $name:expr, $(condition: $condition:expr,)? message: $($message:tt)*) => {
699-
if let Some(expected) = $name {
700-
if name == expected $(&& $condition)? {
701-
is_match = Some(format!($($message)*));
704+
(
705+
name: $name:expr,
706+
$(allowed_names: $allowed_names:expr,)?
707+
$(condition: $condition:expr,)?
708+
message: $($message:tt)*
709+
) => {{
710+
// This is not inlined to avoid problems with macro repetitions.
711+
let format_message = || format!($($message)*);
712+
713+
if outcome != MatchOutcome::Invalid {
714+
// Ignore all other matches if we already found one
715+
} else if $name.as_ref().map(|n| n == &name).unwrap_or(false) {
716+
message = Some(format_message());
717+
if true $(&& $condition)? {
718+
outcome = MatchOutcome::Match;
719+
} else {
720+
outcome = MatchOutcome::NoMatch;
702721
}
703722
}
704-
};
723+
$(else if $allowed_names.contains(name) {
724+
message = Some(format_message());
725+
outcome = MatchOutcome::NoMatch;
726+
})?
727+
}};
705728
}
706729
macro_rules! condition {
707-
(name: $name:expr, $(condition: $condition:expr,)? message: $($message:tt)*) => {
730+
(
731+
name: $name:expr,
732+
$(allowed_names: $allowed_names:expr,)?
733+
$(condition: $condition:expr,)?
734+
message: $($message:tt)*
735+
) => {
708736
maybe_condition! {
709737
name: Some($name),
738+
$(allowed_names: $allowed_names,)*
710739
$(condition: $condition,)*
711740
message: $($message)*
712741
}
713742
};
714743
}
744+
macro_rules! hashset {
745+
($($value:expr),* $(,)?) => {{
746+
let mut set = HashSet::new();
747+
$(set.insert($value);)*
748+
set
749+
}}
750+
}
751+
752+
let target_cfgs = self.target_cfgs();
753+
let target_cfg = self.target_cfg();
715754

716755
condition! {
717756
name: "test",
718757
message: "always"
719758
}
720759
condition! {
721760
name: &self.target,
761+
allowed_names: &target_cfgs.all_targets,
722762
message: "when the target is {name}"
723763
}
724-
725-
let target_cfg = self.target_cfg();
726764
condition! {
727765
name: &target_cfg.os,
766+
allowed_names: &target_cfgs.all_oses,
728767
message: "when the operative system is {name}"
729768
}
730769
condition! {
731770
name: &target_cfg.env,
771+
allowed_names: &target_cfgs.all_envs,
732772
message: "when the target environment is {name}"
733773
}
734774
condition! {
735775
name: &target_cfg.abi,
776+
allowed_names: &target_cfgs.all_abis,
736777
message: "when the ABI is {name}"
737778
}
738779
condition! {
739780
name: &target_cfg.arch,
781+
allowed_names: &target_cfgs.all_archs,
740782
message: "when the architecture is {name}"
741783
}
742784
condition! {
743785
name: format!("{}bit", target_cfg.pointer_width),
786+
allowed_names: &target_cfgs.all_pointer_widths,
744787
message: "when the pointer width is {name}"
745788
}
746789
for family in &target_cfg.families {
747790
condition! {
748791
name: family,
792+
allowed_names: &target_cfgs.all_families,
749793
message: "when the target family is {name}"
750794
}
751795
}
@@ -768,6 +812,7 @@ impl Config {
768812

769813
condition! {
770814
name: &self.channel,
815+
allowed_names: hashset!["stable", "beta", "nightly"],
771816
message: "when the release channel is {name}",
772817
}
773818
condition! {
@@ -782,6 +827,7 @@ impl Config {
782827
}
783828
condition! {
784829
name: self.stage_id.split('-').next().unwrap(),
830+
allowed_names: hashset!["stable", "beta", "nightly"],
785831
message: "when the bootstrapping stage is {name}",
786832
}
787833
condition! {
@@ -796,20 +842,38 @@ impl Config {
796842
}
797843
maybe_condition! {
798844
name: self.debugger.as_ref().map(|d| d.to_str()),
845+
allowed_names: Debugger::VARIANTS
846+
.iter()
847+
.map(|v| v.to_str())
848+
.collect::<HashSet<_>>(),
799849
message: "when the debugger is {name}",
800850
}
801851
maybe_condition! {
802852
name: self.compare_mode
803853
.as_ref()
804854
.map(|d| format!("compare-mode-{}", d.to_str())),
855+
allowed_names: CompareMode::VARIANTS
856+
.iter()
857+
.map(|cm| format!("compare-mode-{}", cm.to_str()))
858+
.collect::<HashSet<_>>(),
805859
message: "when comparing with {name}",
806860
}
807861

862+
// Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest.
863+
if prefix == "ignore" && name.starts_with("tidy-") && outcome == MatchOutcome::Invalid {
864+
outcome = MatchOutcome::External;
865+
}
866+
867+
// Don't error out for ignore-pass, as that is handled elsewhere.
868+
if prefix == "ignore" && name == "pass" && outcome == MatchOutcome::Invalid {
869+
outcome = MatchOutcome::External;
870+
}
871+
808872
ParsedNameDirective {
809873
name: Some(name),
810874
comment: comment.map(|c| c.trim().trim_start_matches('-').trim()),
811-
outcome: if is_match.is_some() { MatchOutcome::Match } else { MatchOutcome::NoMatch },
812-
pretty_reason: is_match,
875+
outcome,
876+
pretty_reason: message,
813877
}
814878
}
815879

@@ -1095,6 +1159,8 @@ pub fn make_test_description<R: Read>(
10951159
true
10961160
}
10971161
MatchOutcome::NoMatch => ignore,
1162+
MatchOutcome::External => ignore,
1163+
MatchOutcome::Invalid => panic!("invalid line in {}: {ln}", path.display()),
10981164
};
10991165
}
11001166

@@ -1103,16 +1169,18 @@ pub fn make_test_description<R: Read>(
11031169
ignore = match parsed.outcome {
11041170
MatchOutcome::Match => ignore,
11051171
MatchOutcome::NoMatch => {
1106-
let name = parsed.name.unwrap();
1172+
let reason = parsed.pretty_reason.unwrap();
11071173
// The ignore reason must be a &'static str, so we have to leak memory to
11081174
// create it. This is fine, as the header is parsed only at the start of
11091175
// compiletest so it won't grow indefinitely.
11101176
ignore_message = Some(Box::leak(Box::<str>::from(match parsed.comment {
1111-
Some(comment) => format!("did not match only-{name} ({comment})"),
1112-
None => format!("did not match only-{name}"),
1177+
Some(comment) => format!("only executed {reason} ({comment})"),
1178+
None => format!("only executed {reason}"),
11131179
})) as &str);
11141180
true
11151181
}
1182+
MatchOutcome::External => ignore,
1183+
MatchOutcome::Invalid => panic!("invalid line in {}: {ln}", path.display()),
11161184
};
11171185
}
11181186

src/tools/compiletest/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
311311

312312
force_rerun: matches.opt_present("force-rerun"),
313313

314-
target_cfg: LazyCell::new(),
314+
target_cfgs: LazyCell::new(),
315315

316316
nocapture: matches.opt_present("nocapture"),
317317
}

0 commit comments

Comments
 (0)