From 9de3c29319a42bbfdf3c61f1bced9e2e79373452 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 7 Jun 2023 15:05:54 +0200 Subject: [PATCH] add support for blessing panic=abort mir-opt tests --- src/bootstrap/config.rs | 16 +++++- src/bootstrap/lib.rs | 1 + src/bootstrap/synthetic_targets.rs | 82 ++++++++++++++++++++++++++++++ src/bootstrap/test.rs | 11 +++- 4 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 src/bootstrap/synthetic_targets.rs diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index b521ad75d63..8ee63e561ba 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -429,6 +429,7 @@ fn from_str(s: &str) -> Result { pub struct TargetSelection { pub triple: Interned, file: Option>, + synthetic: bool, } /// Newtype over `Vec` so we can implement custom parsing logic @@ -460,7 +461,15 @@ pub fn from_user(selection: &str) -> Self { let triple = INTERNER.intern_str(triple); let file = file.map(|f| INTERNER.intern_str(f)); - Self { triple, file } + Self { triple, file, synthetic: false } + } + + pub fn create_synthetic(triple: &str, file: &str) -> Self { + Self { + triple: INTERNER.intern_str(triple), + file: Some(INTERNER.intern_str(file)), + synthetic: true, + } } pub fn rustc_target_arg(&self) -> &str { @@ -478,6 +487,11 @@ pub fn starts_with(&self, needle: &str) -> bool { pub fn ends_with(&self, needle: &str) -> bool { self.triple.ends_with(needle) } + + // See src/bootstrap/synthetic_targets.rs + pub fn is_synthetic(&self) -> bool { + self.synthetic + } } impl fmt::Display for TargetSelection { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index c9d256028d4..d7e77aeb338 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -61,6 +61,7 @@ mod sanity; mod setup; mod suggest; +mod synthetic_targets; mod tarball; mod test; mod tool; diff --git a/src/bootstrap/synthetic_targets.rs b/src/bootstrap/synthetic_targets.rs new file mode 100644 index 00000000000..7eeac9025c9 --- /dev/null +++ b/src/bootstrap/synthetic_targets.rs @@ -0,0 +1,82 @@ +//! In some cases, parts of bootstrap need to change part of a target spec just for one or a few +//! steps. Adding these targets to rustc proper would "leak" this implementation detail of +//! bootstrap, and would make it more complex to apply additional changes if the need arises. +//! +//! To address that problem, this module implements support for "synthetic targets". Synthetic +//! targets are custom target specs generated using builtin target specs as their base. You can use +//! one of the target specs already defined in this module, or create new ones by adding a new step +//! that calls create_synthetic_target. + +use crate::builder::{Builder, ShouldRun, Step}; +use crate::config::TargetSelection; +use crate::Compiler; +use std::process::{Command, Stdio}; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub(crate) struct MirOptPanicAbortSyntheticTarget { + pub(crate) compiler: Compiler, + pub(crate) base: TargetSelection, +} + +impl Step for MirOptPanicAbortSyntheticTarget { + type Output = TargetSelection; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.never() + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + create_synthetic_target(builder, self.compiler, "miropt-abort", self.base, |spec| { + spec.insert("panic-strategy".into(), "abort".into()); + }) + } +} + +fn create_synthetic_target( + builder: &Builder<'_>, + compiler: Compiler, + suffix: &str, + base: TargetSelection, + customize: impl FnOnce(&mut serde_json::Map), +) -> TargetSelection { + if base.contains("synthetic") { + // This check is not strictly needed, but nothing currently needs recursive synthetic + // targets. If the need arises, removing this in the future *SHOULD* be safe. + panic!("cannot create synthetic targets with other synthetic targets as their base"); + } + + let name = format!("{base}-synthetic-{suffix}"); + let path = builder.out.join("synthetic-target-specs").join(format!("{name}.json")); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + + if builder.config.dry_run() { + std::fs::write(&path, b"dry run\n").unwrap(); + return TargetSelection::create_synthetic(&name, path.to_str().unwrap()); + } + + let mut cmd = Command::new(builder.rustc(compiler)); + cmd.arg("--target").arg(base.rustc_target_arg()); + cmd.args(["-Zunstable-options", "--print", "target-spec-json"]); + cmd.stdout(Stdio::piped()); + + let output = cmd.spawn().unwrap().wait_with_output().unwrap(); + if !output.status.success() { + panic!("failed to gather the target spec for {base}"); + } + + let mut spec: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + let spec_map = spec.as_object_mut().unwrap(); + + // The `is-builtin` attribute of a spec needs to be removed, otherwise rustc will complain. + spec_map.remove("is-builtin"); + + customize(spec_map); + + std::fs::write(&path, &serde_json::to_vec_pretty(&spec).unwrap()).unwrap(); + let target = TargetSelection::create_synthetic(&name, path.to_str().unwrap()); + crate::cc_detect::find_target(builder, target); + + target +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 5ecac833d27..d7f0205cbed 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -23,6 +23,7 @@ use crate::flags::Subcommand; use crate::llvm; use crate::render_tests::add_flags_and_try_run_tests; +use crate::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::tool::{self, SourceType, Tool}; use crate::toolstate::ToolState; use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date}; @@ -1347,8 +1348,8 @@ fn run(self, builder: &Builder<'_>) { }; // We use custom logic to bless the mir-opt suite: mir-opt tests have multiple variants - // (32bit vs 64bit), and all of them needs to be blessed. When blessing, we try best-effort - // to also bless the other variants, to aid developers. + // (32bit vs 64bit, and panic=abort vs panic=unwind), and all of them needs to be blessed. + // When blessing, we try best-effort to also bless the other variants, to aid developers. if builder.config.cmd.bless() { let targets = MIR_OPT_BLESS_TARGET_MAPPING .iter() @@ -1385,6 +1386,12 @@ fn run(self, builder: &Builder<'_>) { for target in targets { run(target); + + let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget { + compiler: self.compiler, + base: target, + }); + run(panic_abort_target); } } else { run(self.target);