about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPietro Albini <pietro.albini@ferrous-systems.com>2023-06-07 15:05:54 +0200
committerPietro Albini <pietro.albini@ferrous-systems.com>2023-06-12 09:34:12 +0200
commit9de3c29319a42bbfdf3c61f1bced9e2e79373452 (patch)
treee36b3f5777c1d70a6de69777e151f1d4cd414bc9
parent9ec370d40ceb86249b303c9d26f576229ad0b318 (diff)
downloadrust-9de3c29319a42bbfdf3c61f1bced9e2e79373452.tar.gz
rust-9de3c29319a42bbfdf3c61f1bced9e2e79373452.zip
add support for blessing panic=abort mir-opt tests
-rw-r--r--src/bootstrap/config.rs16
-rw-r--r--src/bootstrap/lib.rs1
-rw-r--r--src/bootstrap/synthetic_targets.rs82
-rw-r--r--src/bootstrap/test.rs11
4 files changed, 107 insertions, 3 deletions
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 @@ impl std::str::FromStr for RustcLto {
 pub struct TargetSelection {
     pub triple: Interned<String>,
     file: Option<Interned<String>>,
+    synthetic: bool,
 }
 
 /// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
@@ -460,7 +461,15 @@ impl TargetSelection {
         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 @@ impl TargetSelection {
     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 run;
 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<String, serde_json::Value>),
+) -> 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::doc::DocumentationFormat;
 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 @@ impl Step for MirOpt {
         };
 
         // 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 @@ You can add that mapping by changing MIR_OPT_BLESS_TARGET_MAPPING in src/bootstr
 
             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);