From c02aa4e5807d36951418f6bfb1195acf58c75255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 30 Jul 2026 10:14:45 +0200 Subject: [PATCH 01/11] Bless bootstrap tests And only include the target name when rendering test metadata, to avoid including filenames in it. --- src/bootstrap/src/core/builder/tests.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 9c613811c8ccc..06842d3ddf4cd 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1941,6 +1941,8 @@ mod snapshot { [test] compiletest-coverage 1 [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 + [build] rustc 1 -> std 1 + [test] compiletest-mir-opt 1 [test] compiletest-codegen-llvm 1 [test] compiletest-codegen-units 1 [test] compiletest-assembly-llvm 1 @@ -2122,6 +2124,9 @@ mod snapshot { [test] compiletest-coverage 2 [build] rustc 2 -> std 2 [test] compiletest-mir-opt 2 + [build] rustc 1 -> std 1 + [build] rustc 2 -> std 2 + [test] compiletest-mir-opt 2 [test] compiletest-codegen-llvm 2 [test] compiletest-codegen-units 2 [test] compiletest-assembly-llvm 2 @@ -3184,7 +3189,7 @@ fn render_metadata(metadata: &StepMetadata, config: &RenderConfig) -> String { } fn normalize_target(target: TargetSelection, config: &RenderConfig) -> String { - let mut target = target.to_string(); + let mut target = target.triple.to_string(); if config.normalize_host { target = target.replace(&host_target(), "host"); } From 54d589a45c7477ef9cfad95c87e0713de2f5c93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 7 Aug 2026 09:59:58 +0200 Subject: [PATCH 02/11] Generalize `MirOptPanicAbortSyntheticTarget` to `SyntheticTargetWithPanicStrategy` --- .../src/core/build_steps/synthetic_targets.rs | 26 ++++++++++++++++--- src/bootstrap/src/core/build_steps/test.rs | 8 +++--- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 2b5039214f62c..75999c1fa355b 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -12,17 +12,37 @@ use crate::core::compiler::Compiler; use crate::core::config::TargetSelection; #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct MirOptPanicAbortSyntheticTarget { +pub(crate) enum PanicStrategy { + Unwind, + Abort, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct SyntheticTargetWithPanicStrategy { pub(crate) compiler: Compiler, pub(crate) base: TargetSelection, + pub(crate) strategy: PanicStrategy, +} + +impl SyntheticTargetWithPanicStrategy { + pub(crate) fn panic_abort(compiler: Compiler, base: TargetSelection) -> Self { + Self { compiler, base, strategy: PanicStrategy::Abort } + } + pub(crate) fn panic_unwind(compiler: Compiler, base: TargetSelection) -> Self { + Self { compiler, base, strategy: PanicStrategy::Unwind } + } } -impl Step for MirOptPanicAbortSyntheticTarget { +impl Step for SyntheticTargetWithPanicStrategy { type Output = TargetSelection; fn run(self, builder: &Builder<'_>) -> Self::Output { + let strategy = match self.strategy { + PanicStrategy::Unwind => "unwind", + PanicStrategy::Abort => "abort", + }; create_synthetic_target(builder, self.compiler, "miropt-abort", self.base, |spec| { - spec.insert("panic-strategy".into(), "abort".into()); + spec.insert("panic-strategy".into(), strategy.into()); }) } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 47318d3c086f5..81c7d7e9f5278 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -22,7 +22,7 @@ use crate::core::build_steps::format::InternalRustfmt; use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::{get_completion_paths, get_help_path}; -use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; +use crate::core::build_steps::synthetic_targets::SyntheticTargetWithPanicStrategy; use crate::core::build_steps::test::compiletest::CompiletestMode; use crate::core::build_steps::test::failed_tests::{RecordFailedTests, SetupFailedTestsFile}; use crate::core::build_steps::tool::{ @@ -2216,10 +2216,8 @@ impl CommandLineStep for MirOpt { for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] { let target = TargetSelection::from_user(target); - let panic_abort_target = builder.ensure(MirOptPanicAbortSyntheticTarget { - compiler: self.compiler, - base: target, - }); + let panic_abort_target = builder + .ensure(SyntheticTargetWithPanicStrategy::panic_abort(self.compiler, target)); run(panic_abort_target); } } From 874f72aebb912aafcb236468e08fb26626fafe3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 7 Aug 2026 10:11:25 +0200 Subject: [PATCH 03/11] Create targets for `mir-opt` tests explicitly and use the minimal set of targets to check --- .../src/core/build_steps/synthetic_targets.rs | 30 +++-- src/bootstrap/src/core/build_steps/test.rs | 108 +++++++++++++----- src/bootstrap/src/core/builder/tests.rs | 43 +++++++ 3 files changed, 143 insertions(+), 38 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 75999c1fa355b..4afbdff464e34 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -69,16 +69,7 @@ fn create_synthetic_target( return TargetSelection::create_synthetic(&name, path.to_str().unwrap()); } - let mut cmd = builder.rustc_cmd(compiler); - cmd.arg("--target").arg(base.rustc_target_arg()); - cmd.args(["-Zunstable-options", "--print", "target-spec-json"]); - - // If `rust.channel` is set to either beta or stable, rustc will complain that - // we cannot use nightly features. So `RUSTC_BOOTSTRAP` is needed here. - cmd.env("RUSTC_BOOTSTRAP", "1"); - - let output = cmd.run_capture(builder).stdout(); - let mut spec: serde_json::Value = serde_json::from_slice(output.as_bytes()).unwrap(); + let mut spec = get_target_specs(builder, compiler, base); let spec_map = spec.as_object_mut().unwrap(); // The `is-builtin` attribute of a spec needs to be removed, otherwise rustc will complain. @@ -89,3 +80,22 @@ fn create_synthetic_target( std::fs::write(&path, serde_json::to_vec_pretty(&spec).unwrap()).unwrap(); TargetSelection::create_synthetic(&name, path.to_str().unwrap()) } + +/// Get the JSON target specs from the given compiler. +pub fn get_target_specs( + builder: &Builder<'_>, + compiler: Compiler, + target: TargetSelection, +) -> serde_json::Value { + let mut cmd = builder.rustc_cmd(compiler); + cmd.arg("--target").arg(target.rustc_target_arg()); + cmd.args(["-Zunstable-options", "--print", "target-spec-json"]); + + // If `rust.channel` is set to either beta or stable, rustc will complain that + // we cannot use nightly features. So `RUSTC_BOOTSTRAP` is needed here. + cmd.env("RUSTC_BOOTSTRAP", "1"); + + let output = cmd.cached().run_capture(builder).stdout(); + let spec: serde_json::Value = serde_json::from_slice(output.as_bytes()).unwrap(); + spec +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 81c7d7e9f5278..8bf5189382c96 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -22,7 +22,9 @@ use crate::core::build_steps::format::InternalRustfmt; use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::{get_completion_paths, get_help_path}; -use crate::core::build_steps::synthetic_targets::SyntheticTargetWithPanicStrategy; +use crate::core::build_steps::synthetic_targets::{ + SyntheticTargetWithPanicStrategy, get_target_specs, +}; use crate::core::build_steps::test::compiletest::CompiletestMode; use crate::core::build_steps::test::failed_tests::{RecordFailedTests, SetupFailedTestsFile}; use crate::core::build_steps::tool::{ @@ -2168,8 +2170,8 @@ test!(CoverageRunRustdoc { // For the mir-opt suite we do not use macros, as we need custom behavior when blessing. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MirOpt { - pub compiler: Compiler, - pub target: TargetSelection, + compiler: Compiler, + target: TargetSelection, } impl CommandLineStep for MirOpt { @@ -2185,43 +2187,93 @@ impl CommandLineStep for MirOpt { fn make_run(run: RunConfig<'_>) { let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); - run.builder.ensure(MirOpt { compiler, target: run.target }); - } - fn run(self, builder: &Builder<'_>) { - let run = |target| { - builder.ensure(Compiletest { - test_compiler: self.compiler, - target, - mode: CompiletestMode::MirOpt, - suite: "mir-opt", - path: "tests/mir-opt", - compare_mode: None, - }) - }; + // The mir-opt tests check four distinct configurations, the cross-product of the + // following two axes: + // - Bit-width: 32-bit and 64-bit + // - Panic strategy: unwind and abort - run(self.target); + // Here we generate several configurations of this step to evaluate multiple targets. + let targets = if run.builder.config.cmd.bless() { + // When blessing, we generate a fixed set of 4 targets that cover all the + // possible combinations. This selection covers all our tier 1 operating systems and + // architectures using only tier 1 targets. - // Run more targets with `--bless`. But we always run the host target first, since some - // tests use very specific `only` clauses that are not covered by the target set below. - if builder.config.cmd.bless() { - // All that we really need to do is cover all combinations of 32/64-bit and unwind/abort, - // but while we're at it we might as well flex our cross-compilation support. This - // selection covers all our tier 1 operating systems and architectures using only tier - // 1 targets. + // We also include the host target, since some tests use very specific `only` clauses + // that are not covered by the target set below. + let mut targets = vec![run.target]; + + // 64-bit and 32-bit panic=unwind for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] { - run(TargetSelection::from_user(target)); + targets.push(TargetSelection::from_user(target)); } + // 64-bit and 32-bit panic=abort for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] { let target = TargetSelection::from_user(target); - let panic_abort_target = builder - .ensure(SyntheticTargetWithPanicStrategy::panic_abort(self.compiler, target)); - run(panic_abort_target); + let panic_abort_target = run + .builder + .ensure(SyntheticTargetWithPanicStrategy::panic_abort(compiler, target)); + targets.push(panic_abort_target); + } + targets + } else { + // When not blessing, we could also test all four configurations. But that would make + // local tests quite slow. So instead, we check the current target, and then the + // current target with switched panic strategy. + // On CI, we should be running this test for both 32-bit and 64-bit targets, so together + // this should check all possible configurations on CI. + + // The complicated thing here is how to figure out the panic strategy of the current + // target. In theory, we could just assume that in most situations, the target is + // panic=unwind, and force generation of panic=abort. But to ensure that we do this + // properly, we actually query the compiler to figure out the panic strategy, and then + // generate a synthetic target with the opposite strategy. + if !run.builder.config.dry_run() { + let target_specs = get_target_specs(run.builder, compiler, run.target); + let panic_strategy = target_specs + .as_object() + .and_then(|obj| obj.get("panic-strategy")) + .and_then(|v| v.as_str()) + // The default panic strategy is unwind + .unwrap_or("unwind"); + let synthetic_target = if panic_strategy == "unwind" { + run.builder + .ensure(SyntheticTargetWithPanicStrategy::panic_abort(compiler, run.target)) + } else { + run.builder.ensure(SyntheticTargetWithPanicStrategy::panic_unwind( + compiler, run.target, + )) + }; + vec![run.target, synthetic_target] + } else { + // Note: in a dry run, we just hardcode the other target to be panic=abort, + // so that we still see two targets in snapshot tests. + vec![ + run.target, + run.builder.ensure(SyntheticTargetWithPanicStrategy::panic_abort( + compiler, run.target, + )), + ] } + }; + + for target in targets { + run.builder.ensure(MirOpt { compiler, target }); } } + + fn run(self, builder: &Builder<'_>) { + builder.ensure(Compiletest { + test_compiler: self.compiler, + target: self.target, + mode: CompiletestMode::MirOpt, + suite: "mir-opt", + path: "tests/mir-opt", + compare_mode: None, + }); + } } /// Executes the `compiletest` tool to run a suite of tests. diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 06842d3ddf4cd..2deca8bbef30e 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2394,6 +2394,49 @@ mod snapshot { "); } + #[test] + fn test_mir_opt() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + prepare_test_config(&ctx) + .path("tests/mir-opt") + .render_steps(), @" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Compiletest 1 + [test] compiletest-mir-opt 1 + [build] rustc 1 -> std 1 + [test] compiletest-mir-opt 1 + "); + } + + #[test] + fn test_mir_opt_bless() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + prepare_test_config(&ctx) + .path("tests/mir-opt") + .arg("--bless") + .targets(&[TEST_TRIPLE_1]) + .render_steps(), @" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Compiletest 1 + [build] rustc 1 -> std 1 + [test] compiletest-mir-opt 1 + [build] rustc 1 -> std 1 + [test] compiletest-mir-opt 1 + [build] rustc 1 -> std 1 + [test] compiletest-mir-opt 1 + [build] rustc 1 -> std 1 + [test] compiletest-mir-opt 1 + [build] rustc 1 -> std 1 + [test] compiletest-mir-opt 1 + "); + } + #[test] fn doc_all() { let ctx = TestCtx::new(); From 22ec841d17f2c2e1717adaacb8a5d33a6e8ebd23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 7 Aug 2026 10:49:17 +0200 Subject: [PATCH 04/11] Fix host normalization --- src/bootstrap/src/core/builder/tests.rs | 27 +++++++++++++++---------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 2deca8bbef30e..df5d56e9d0d27 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2416,23 +2416,28 @@ mod snapshot { let ctx = TestCtx::new(); insta::assert_snapshot!( prepare_test_config(&ctx) - .path("tests/mir-opt") .arg("--bless") .targets(&[TEST_TRIPLE_1]) - .render_steps(), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> Compiletest 1 - [build] rustc 1 -> std 1 + .path("tests/mir-opt") + .get_steps() + // When blessing, the step executes for a pinned set of targets, so we cannot + // normalize here. + .render_with(RenderConfig { + normalize_host: false + }), @" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Compiletest 1 + [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 - [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 - [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 - [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 - [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 "); } From b0d6723a4980dcc06b4af03b7c9165a640ad9c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 7 Aug 2026 11:15:16 +0200 Subject: [PATCH 05/11] Bless at most four individual targets --- .../src/core/build_steps/synthetic_targets.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 83 +++++++++++-------- src/bootstrap/src/core/builder/tests.rs | 27 +++--- 3 files changed, 62 insertions(+), 50 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 4afbdff464e34..04b815743bafd 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -11,7 +11,7 @@ use crate::core::builder::{Builder, Step}; use crate::core::compiler::Compiler; use crate::core::config::TargetSelection; -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub(crate) enum PanicStrategy { Unwind, Abort, diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 8bf5189382c96..aba8d52959c88 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -23,7 +23,7 @@ use crate::core::build_steps::gcc::{Gcc, GccTargetPair, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::{get_completion_paths, get_help_path}; use crate::core::build_steps::synthetic_targets::{ - SyntheticTargetWithPanicStrategy, get_target_specs, + PanicStrategy, SyntheticTargetWithPanicStrategy, get_target_specs, }; use crate::core::build_steps::test::compiletest::CompiletestMode; use crate::core::build_steps::test::failed_tests::{RecordFailedTests, SetupFailedTestsFile}; @@ -2193,6 +2193,31 @@ impl CommandLineStep for MirOpt { // - Bit-width: 32-bit and 64-bit // - Panic strategy: unwind and abort + // Return the bitwidth and panic strategy of the default (usually host) target + let get_bitwidth_and_panic_strategy = || -> (u64, PanicStrategy) { + if run.builder.config.dry_run() { + return (64, PanicStrategy::Unwind); + } + + let specs = get_target_specs(run.builder, compiler, run.target); + let specs = specs.as_object(); + let bitwidth = specs + .and_then(|obj| obj.get("target-pointer-width")) + .and_then(|v| v.as_i64()) + .map(|v| v as u64) + .unwrap_or(64); + let panic_strategy = specs + .and_then(|obj| obj.get("panic-strategy")) + .and_then(|v| v.as_str()) + .map(|v| match v { + "unwind" => PanicStrategy::Unwind, + _ => PanicStrategy::Abort, + }) + // The default panic strategy is unwind + .unwrap_or(PanicStrategy::Unwind); + (bitwidth, panic_strategy) + }; + // Here we generate several configurations of this step to evaluate multiple targets. let targets = if run.builder.config.cmd.bless() { // When blessing, we generate a fixed set of 4 targets that cover all the @@ -2202,22 +2227,32 @@ impl CommandLineStep for MirOpt { // We also include the host target, since some tests use very specific `only` clauses // that are not covered by the target set below. - let mut targets = vec![run.target]; + let (bitwidth, strategy) = get_bitwidth_and_panic_strategy(); + let mut targets = vec![(bitwidth, strategy, run.target)]; // 64-bit and 32-bit panic=unwind - for target in ["aarch64-unknown-linux-gnu", "i686-pc-windows-msvc"] { - targets.push(TargetSelection::from_user(target)); + for (bitwidth, target) in + [(64, "aarch64-unknown-linux-gnu"), (32, "i686-pc-windows-msvc")] + { + targets.push((bitwidth, PanicStrategy::Unwind, TargetSelection::from_user(target))); } // 64-bit and 32-bit panic=abort - for target in ["x86_64-apple-darwin", "i686-unknown-linux-musl"] { + for (bitwidth, target) in [(64, "x86_64-apple-darwin"), (32, "i686-unknown-linux-musl")] + { let target = TargetSelection::from_user(target); let panic_abort_target = run .builder .ensure(SyntheticTargetWithPanicStrategy::panic_abort(compiler, target)); - targets.push(panic_abort_target); + targets.push((bitwidth, PanicStrategy::Abort, panic_abort_target)); } - targets + // This is a small optimization for local blessing. + // If we figure out that the host target already has a given bitwidth/panic strategy + // combination, we do not add the fixed targets to the list. + let mut unique = HashSet::new(); + targets.retain(|(bitwidth, strategy, _)| unique.insert((*bitwidth, *strategy))); + + targets.into_iter().map(|(_, _, target)| target).collect() } else { // When not blessing, we could also test all four configurations. But that would make // local tests quite slow. So instead, we check the current target, and then the @@ -2230,33 +2265,15 @@ impl CommandLineStep for MirOpt { // panic=unwind, and force generation of panic=abort. But to ensure that we do this // properly, we actually query the compiler to figure out the panic strategy, and then // generate a synthetic target with the opposite strategy. - if !run.builder.config.dry_run() { - let target_specs = get_target_specs(run.builder, compiler, run.target); - let panic_strategy = target_specs - .as_object() - .and_then(|obj| obj.get("panic-strategy")) - .and_then(|v| v.as_str()) - // The default panic strategy is unwind - .unwrap_or("unwind"); - let synthetic_target = if panic_strategy == "unwind" { - run.builder - .ensure(SyntheticTargetWithPanicStrategy::panic_abort(compiler, run.target)) - } else { - run.builder.ensure(SyntheticTargetWithPanicStrategy::panic_unwind( - compiler, run.target, - )) - }; - vec![run.target, synthetic_target] + let panic_strategy = get_bitwidth_and_panic_strategy().1; + let synthetic_target = if panic_strategy == PanicStrategy::Unwind { + run.builder + .ensure(SyntheticTargetWithPanicStrategy::panic_abort(compiler, run.target)) } else { - // Note: in a dry run, we just hardcode the other target to be panic=abort, - // so that we still see two targets in snapshot tests. - vec![ - run.target, - run.builder.ensure(SyntheticTargetWithPanicStrategy::panic_abort( - compiler, run.target, - )), - ] - } + run.builder + .ensure(SyntheticTargetWithPanicStrategy::panic_unwind(compiler, run.target)) + }; + vec![run.target, synthetic_target] }; for target in targets { diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index df5d56e9d0d27..e5023c55a41ca 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2417,27 +2417,22 @@ mod snapshot { insta::assert_snapshot!( prepare_test_config(&ctx) .arg("--bless") + .hosts(&[TEST_TRIPLE_1]) + .arg("--build") + .arg(TEST_TRIPLE_1) .targets(&[TEST_TRIPLE_1]) .path("tests/mir-opt") - .get_steps() - // When blessing, the step executes for a pinned set of targets, so we cannot - // normalize here. - .render_with(RenderConfig { - normalize_host: false - }), @" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustc 0 -> Compiletest 1 - [build] rustc 1 -> std 1 + .render_steps(), @" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 0 -> Compiletest 1 [test] compiletest-mir-opt 1 - [build] rustc 1 -> std 1 - [test] compiletest-mir-opt 1 - [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 - [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 - [build] rustc 1 -> std 1 + [build] rustc 1 -> std 1 [test] compiletest-mir-opt 1 "); } From 13cdbfdd297476f9708560989d817c3336aba58f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 10 Aug 2026 11:03:52 +0200 Subject: [PATCH 06/11] Do not call `configure_linker` for synthetic targets --- src/bootstrap/src/core/builder/cargo.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 288e147a26615..a05ba3c9801db 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -179,7 +179,11 @@ impl Cargo { // No need to configure the target linker for these command types. Kind::Clean | Kind::Check | Kind::Format | Kind::Setup => {} _ => { - cargo.configure_linker(builder); + // Do not configure the linker for synthetic targets, as we won't have cc set up + // for them. + if !target.is_synthetic() { + cargo.configure_linker(builder); + } } } From 6f6103e9861227961eceffbe2c7b685d6b2a23e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 20 Aug 2026 08:50:32 +0200 Subject: [PATCH 07/11] Add `needs-deterministic-layouts` flag --- tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs index 5534a45f19d64..8593a322ad363 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.rs @@ -1,4 +1,6 @@ //@ test-mir-pass: GVN +// layout randomization affects the alloc output +//@ needs-deterministic-layouts //@ compile-flags: -Zinline-mir --crate-type lib // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR_FOR_EACH_PANIC_STRATEGY From 03af1e8413a5fc3132de381d54f2b686401f8108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 1 Sep 2026 14:46:02 +0200 Subject: [PATCH 08/11] Add comments --- src/bootstrap/src/core/build_steps/synthetic_targets.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 04b815743bafd..2c35b39287d70 100644 --- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -11,6 +11,8 @@ use crate::core::builder::{Builder, Step}; use crate::core::compiler::Compiler; use crate::core::config::TargetSelection; +/// Note that this currently only contains panic strategies that we somehow use in bootstrap, not +/// all possible strategires supported by rustc. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub(crate) enum PanicStrategy { Unwind, @@ -82,6 +84,7 @@ fn create_synthetic_target( } /// Get the JSON target specs from the given compiler. +/// Note that the set of targets will differ between the stage0 and stage1+ (in-tree) compiler! pub fn get_target_specs( builder: &Builder<'_>, compiler: Compiler, From feafdd6cde42d6e63bf04e2272ad459744358b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 1 Sep 2026 15:53:04 +0200 Subject: [PATCH 09/11] Bless test --- ...er.enumerated_loop.runtime-optimized.after.panic-abort.mir | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir index 549af7af4d888..b42087b5c822d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir @@ -21,7 +21,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug x => _34; } scope 18 (inlined > as Iterator>::next) { - let mut _22: std::option::Option; + let mut _22: std::option::Option; let mut _27: std::option::Option<&T>; let mut _30: (usize, bool); let mut _31: (usize, &T); @@ -32,7 +32,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } scope 20 { scope 21 { - scope 27 (inlined as FromResidual>>::from_residual) { + scope 27 (inlined as FromResidual>>::from_residual) { let mut _21: isize; let mut _23: bool; } From 59ffbfe71fffc733525da785d5eca998e760770d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 3 Sep 2026 10:00:24 +0200 Subject: [PATCH 10/11] Do not normalize host in mir-opt bootstrap test to fix it on i686-pc-windows-msvc --- src/bootstrap/src/core/builder/tests.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index e5023c55a41ca..cd51fb5f171af 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2422,7 +2422,10 @@ mod snapshot { .arg(TEST_TRIPLE_1) .targets(&[TEST_TRIPLE_1]) .path("tests/mir-opt") - .render_steps(), @" + .get_steps() + .render_with(RenderConfig { + normalize_host: false + }), @" [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 From 373b59f144fe0a1ae733b7ee193a8053f86966d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 7 Sep 2026 08:36:28 +0200 Subject: [PATCH 11/11] Propagate `is_for_mir_opt_tests` when uplifting in the `Std` step --- src/bootstrap/src/core/build_steps/compile.rs | 6 ++++-- src/bootstrap/src/core/builder/tests.rs | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index b1157ef381013..28a5aa640c947 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -218,8 +218,10 @@ impl CommandLineStep for Std { if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage) { let build_compiler_for_std_to_uplift = builder.compiler(1, builder.host_target); - let stage_1_stamp = builder.std(build_compiler_for_std_to_uplift, target); - + let stage_1_stamp = builder.ensure( + Std::new(build_compiler_for_std_to_uplift, target) + .is_for_mir_opt_tests(self.is_for_mir_opt_tests), + ); let msg = if build_compiler_for_std_to_uplift.host == target { format!( "Uplifting library (stage{} -> stage{stage})", diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index cd51fb5f171af..dc96e5e7219b2 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2122,6 +2122,7 @@ mod snapshot { [build] rustc 0 -> CoverageDump 1 [test] compiletest-coverage 2 [test] compiletest-coverage 2 + [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 [test] compiletest-mir-opt 2 [build] rustc 1 -> std 1