Skip to content

Commit afa9fef

Browse files
committed
Auto merge of #112418 - ferrocene:pa-mir-opt-panic, r=ozkanonur,saethlin
Add support for targets without unwinding in `mir-opt`, and improve `--bless` for it The main goal of this PR is to add support for targets without unwinding support in the `mir-opt` test suite, by adding the `EMIT_MIR_FOR_EACH_PANIC_STRATEGY` comment. Similarly to 32bit vs 64bit, when that comment is present, blessed output files will have the `.panic-unwind` or `.panic-abort` suffix, and the right one will be chosen depending on the target's panic strategy. The `EMIT_MIR_FOR_EACH_PANIC_STRATEGY` comment replaced all the `ignore-wasm32` comments in the `mir-opt` test suite, as those comments were added due to `wasm32` being a target without unwinding support. The comment was also added on other tests that were only executed on x86 but were still panic strategy dependent. The `mir-opt` suite was then blessed, which caused a ton of churn as most of the existing output files had to be renamed and (mostly) duplicated with the abort strategy. --- After [asking on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/mir-opt.20tests.20and.20panic.3Dabort), the main concern about this change is it'd make blessing the `mir-opt` suite even harder, as you'd need to both bless it with an unwinding target and an aborting target. This exacerbated the current situation, where you'd need to bless it with a 32bit and a 64bit target already. Because of that, this PR also makes significant enhancements to `--bless` for the `mir-opt` suite, where it will automatically bless the suite four times with different targets, while requiring minimal cross-compilation. To handle the 32bit vs 64bit blessing, there is now an hardcoded list of target mapping between 32bit and 64bit. The goal of the list is to find a related target that will *probably* work without requiring additional cross-compilation toolchains on the system. If a mapping is found, bootstrap will bless the suite with both targets, otherwise just with the current target. To handle the panic strategy blessing (abort vs unwind), I had to resort to what I call "synthetic targets". For each of the target we're blessing (so either the current one, or a 32bit and a 64bit depending on the previous paragraph), bootstrap will extract the JSON spec of the target and change it to include `"panic-strategy": "abort"`. It will then build the standard library with this synthetic target, and bless the `mir-opt` suite with it. As a result of these changes, blessing the `mir-opt` suite will actually bless it two or four times with different targets, ensuring all possible variants are actually blessed. --- This PR is best reviewed commit-by-commit. r? `@jyn514` cc `@saethlin` `@oli-obk`
2 parents 7b0eac4 + f67809a commit afa9fef

File tree

518 files changed

+11693
-251
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

518 files changed

+11693
-251
lines changed

library/std/build.rs

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ fn main() {
3636
|| target.contains("nintendo-3ds")
3737
|| target.contains("vita")
3838
|| target.contains("nto")
39+
// See src/bootstrap/synthetic_targets.rs
40+
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
3941
{
4042
// These platforms don't have any special requirements.
4143
} else {

src/bootstrap/builder.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,8 @@ impl<'a> Builder<'a> {
16501650
}
16511651
};
16521652
cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
1653-
if self.cc[&target].args().iter().any(|arg| arg == "-gz") {
1653+
if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
1654+
{
16541655
rustflags.arg("-Clink-arg=-gz");
16551656
}
16561657
cargo.env(

src/bootstrap/cc_detect.rs

+53-49
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
8989
cfg
9090
}
9191

92-
pub fn find(build: &mut Build) {
92+
pub fn find(build: &Build) {
9393
// For all targets we're going to need a C compiler for building some shims
9494
// and such as well as for being a linker for Rust code.
9595
let targets = build
@@ -100,60 +100,64 @@ pub fn find(build: &mut Build) {
100100
.chain(iter::once(build.build))
101101
.collect::<HashSet<_>>();
102102
for target in targets.into_iter() {
103-
let mut cfg = new_cc_build(build, target);
104-
let config = build.config.target_config.get(&target);
105-
if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
106-
cfg.compiler(cc);
107-
} else {
108-
set_compiler(&mut cfg, Language::C, target, config, build);
109-
}
103+
find_target(build, target);
104+
}
105+
}
110106

111-
let compiler = cfg.get_compiler();
112-
let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
113-
ar
114-
} else {
115-
cc2ar(compiler.path(), target)
116-
};
107+
pub fn find_target(build: &Build, target: TargetSelection) {
108+
let mut cfg = new_cc_build(build, target);
109+
let config = build.config.target_config.get(&target);
110+
if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
111+
cfg.compiler(cc);
112+
} else {
113+
set_compiler(&mut cfg, Language::C, target, config, build);
114+
}
117115

118-
build.cc.insert(target, compiler.clone());
119-
let cflags = build.cflags(target, GitRepo::Rustc, CLang::C);
116+
let compiler = cfg.get_compiler();
117+
let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
118+
ar
119+
} else {
120+
cc2ar(compiler.path(), target)
121+
};
120122

121-
// If we use llvm-libunwind, we will need a C++ compiler as well for all targets
122-
// We'll need one anyways if the target triple is also a host triple
123-
let mut cfg = new_cc_build(build, target);
124-
cfg.cpp(true);
125-
let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
126-
cfg.compiler(cxx);
127-
true
128-
} else if build.hosts.contains(&target) || build.build == target {
129-
set_compiler(&mut cfg, Language::CPlusPlus, target, config, build);
130-
true
131-
} else {
132-
// Use an auto-detected compiler (or one configured via `CXX_target_triple` env vars).
133-
cfg.try_get_compiler().is_ok()
134-
};
123+
build.cc.borrow_mut().insert(target, compiler.clone());
124+
let cflags = build.cflags(target, GitRepo::Rustc, CLang::C);
135125

136-
// for VxWorks, record CXX compiler which will be used in lib.rs:linker()
137-
if cxx_configured || target.contains("vxworks") {
138-
let compiler = cfg.get_compiler();
139-
build.cxx.insert(target, compiler);
140-
}
126+
// If we use llvm-libunwind, we will need a C++ compiler as well for all targets
127+
// We'll need one anyways if the target triple is also a host triple
128+
let mut cfg = new_cc_build(build, target);
129+
cfg.cpp(true);
130+
let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
131+
cfg.compiler(cxx);
132+
true
133+
} else if build.hosts.contains(&target) || build.build == target {
134+
set_compiler(&mut cfg, Language::CPlusPlus, target, config, build);
135+
true
136+
} else {
137+
// Use an auto-detected compiler (or one configured via `CXX_target_triple` env vars).
138+
cfg.try_get_compiler().is_ok()
139+
};
141140

142-
build.verbose(&format!("CC_{} = {:?}", &target.triple, build.cc(target)));
143-
build.verbose(&format!("CFLAGS_{} = {:?}", &target.triple, cflags));
144-
if let Ok(cxx) = build.cxx(target) {
145-
let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx);
146-
build.verbose(&format!("CXX_{} = {:?}", &target.triple, cxx));
147-
build.verbose(&format!("CXXFLAGS_{} = {:?}", &target.triple, cxxflags));
148-
}
149-
if let Some(ar) = ar {
150-
build.verbose(&format!("AR_{} = {:?}", &target.triple, ar));
151-
build.ar.insert(target, ar);
152-
}
141+
// for VxWorks, record CXX compiler which will be used in lib.rs:linker()
142+
if cxx_configured || target.contains("vxworks") {
143+
let compiler = cfg.get_compiler();
144+
build.cxx.borrow_mut().insert(target, compiler);
145+
}
153146

154-
if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) {
155-
build.ranlib.insert(target, ranlib);
156-
}
147+
build.verbose(&format!("CC_{} = {:?}", &target.triple, build.cc(target)));
148+
build.verbose(&format!("CFLAGS_{} = {:?}", &target.triple, cflags));
149+
if let Ok(cxx) = build.cxx(target) {
150+
let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx);
151+
build.verbose(&format!("CXX_{} = {:?}", &target.triple, cxx));
152+
build.verbose(&format!("CXXFLAGS_{} = {:?}", &target.triple, cxxflags));
153+
}
154+
if let Some(ar) = ar {
155+
build.verbose(&format!("AR_{} = {:?}", &target.triple, ar));
156+
build.ar.borrow_mut().insert(target, ar);
157+
}
158+
159+
if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) {
160+
build.ranlib.borrow_mut().insert(target, ranlib);
157161
}
158162
}
159163

src/bootstrap/compile.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ impl Step for Std {
169169
cargo.arg("-p").arg(krate);
170170
}
171171

172+
// See src/bootstrap/synthetic_targets.rs
173+
if target.is_synthetic() {
174+
cargo.env("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET", "1");
175+
}
176+
172177
let _guard = builder.msg(
173178
Kind::Build,
174179
compiler.stage,
@@ -314,7 +319,7 @@ fn copy_self_contained_objects(
314319
}
315320
} else if target.ends_with("windows-gnu") {
316321
for obj in ["crt2.o", "dllcrt2.o"].iter() {
317-
let src = compiler_file(builder, builder.cc(target), target, CLang::C, obj);
322+
let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj);
318323
let target = libdir_self_contained.join(obj);
319324
builder.copy(&src, &target);
320325
target_deps.push((target, DependencyType::TargetSelfContained));
@@ -995,8 +1000,13 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
9951000
&& !target.contains("apple")
9961001
&& !target.contains("solaris")
9971002
{
998-
let file =
999-
compiler_file(builder, builder.cxx(target).unwrap(), target, CLang::Cxx, "libstdc++.a");
1003+
let file = compiler_file(
1004+
builder,
1005+
&builder.cxx(target).unwrap(),
1006+
target,
1007+
CLang::Cxx,
1008+
"libstdc++.a",
1009+
);
10001010
cargo.env("LLVM_STATIC_STDCPP", file);
10011011
}
10021012
if builder.llvm_link_shared() {
@@ -1267,6 +1277,9 @@ pub fn compiler_file(
12671277
c: CLang,
12681278
file: &str,
12691279
) -> PathBuf {
1280+
if builder.config.dry_run() {
1281+
return PathBuf::new();
1282+
}
12701283
let mut cmd = Command::new(compiler);
12711284
cmd.args(builder.cflags(target, GitRepo::Rustc, c));
12721285
cmd.arg(format!("-print-file-name={}", file));

src/bootstrap/config.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ impl std::str::FromStr for RustcLto {
429429
pub struct TargetSelection {
430430
pub triple: Interned<String>,
431431
file: Option<Interned<String>>,
432+
synthetic: bool,
432433
}
433434

434435
/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
@@ -460,7 +461,15 @@ impl TargetSelection {
460461
let triple = INTERNER.intern_str(triple);
461462
let file = file.map(|f| INTERNER.intern_str(f));
462463

463-
Self { triple, file }
464+
Self { triple, file, synthetic: false }
465+
}
466+
467+
pub fn create_synthetic(triple: &str, file: &str) -> Self {
468+
Self {
469+
triple: INTERNER.intern_str(triple),
470+
file: Some(INTERNER.intern_str(file)),
471+
synthetic: true,
472+
}
464473
}
465474

466475
pub fn rustc_target_arg(&self) -> &str {
@@ -478,6 +487,11 @@ impl TargetSelection {
478487
pub fn ends_with(&self, needle: &str) -> bool {
479488
self.triple.ends_with(needle)
480489
}
490+
491+
// See src/bootstrap/synthetic_targets.rs
492+
pub fn is_synthetic(&self) -> bool {
493+
self.synthetic
494+
}
481495
}
482496

483497
impl fmt::Display for TargetSelection {

src/bootstrap/dist.rs

+4
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ fn make_win_dist(
170170
target: TargetSelection,
171171
builder: &Builder<'_>,
172172
) {
173+
if builder.config.dry_run() {
174+
return;
175+
}
176+
173177
//Ask gcc where it keeps its stuff
174178
let mut cmd = Command::new(builder.cc(target));
175179
cmd.arg("-print-search-dirs");

src/bootstrap/lib.rs

+43-24
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ mod run;
6161
mod sanity;
6262
mod setup;
6363
mod suggest;
64+
mod synthetic_targets;
6465
mod tarball;
6566
mod test;
6667
mod tool;
@@ -226,10 +227,10 @@ pub struct Build {
226227

227228
// Runtime state filled in later on
228229
// C/C++ compilers and archiver for all targets
229-
cc: HashMap<TargetSelection, cc::Tool>,
230-
cxx: HashMap<TargetSelection, cc::Tool>,
231-
ar: HashMap<TargetSelection, PathBuf>,
232-
ranlib: HashMap<TargetSelection, PathBuf>,
230+
cc: RefCell<HashMap<TargetSelection, cc::Tool>>,
231+
cxx: RefCell<HashMap<TargetSelection, cc::Tool>>,
232+
ar: RefCell<HashMap<TargetSelection, PathBuf>>,
233+
ranlib: RefCell<HashMap<TargetSelection, PathBuf>>,
233234
// Miscellaneous
234235
// allow bidirectional lookups: both name -> path and path -> name
235236
crates: HashMap<Interned<String>, Crate>,
@@ -451,10 +452,10 @@ impl Build {
451452
miri_info,
452453
rustfmt_info,
453454
in_tree_llvm_info,
454-
cc: HashMap::new(),
455-
cxx: HashMap::new(),
456-
ar: HashMap::new(),
457-
ranlib: HashMap::new(),
455+
cc: RefCell::new(HashMap::new()),
456+
cxx: RefCell::new(HashMap::new()),
457+
ar: RefCell::new(HashMap::new()),
458+
ranlib: RefCell::new(HashMap::new()),
458459
crates: HashMap::new(),
459460
crate_paths: HashMap::new(),
460461
is_sudo,
@@ -482,7 +483,7 @@ impl Build {
482483
}
483484

484485
build.verbose("finding compilers");
485-
cc_detect::find(&mut build);
486+
cc_detect::find(&build);
486487
// When running `setup`, the profile is about to change, so any requirements we have now may
487488
// be different on the next invocation. Don't check for them until the next time x.py is
488489
// run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
@@ -1103,16 +1104,22 @@ impl Build {
11031104
}
11041105

11051106
/// Returns the path to the C compiler for the target specified.
1106-
fn cc(&self, target: TargetSelection) -> &Path {
1107-
self.cc[&target].path()
1107+
fn cc(&self, target: TargetSelection) -> PathBuf {
1108+
if self.config.dry_run() {
1109+
return PathBuf::new();
1110+
}
1111+
self.cc.borrow()[&target].path().into()
11081112
}
11091113

11101114
/// Returns a list of flags to pass to the C compiler for the target
11111115
/// specified.
11121116
fn cflags(&self, target: TargetSelection, which: GitRepo, c: CLang) -> Vec<String> {
1117+
if self.config.dry_run() {
1118+
return Vec::new();
1119+
}
11131120
let base = match c {
1114-
CLang::C => &self.cc[&target],
1115-
CLang::Cxx => &self.cxx[&target],
1121+
CLang::C => self.cc.borrow()[&target].clone(),
1122+
CLang::Cxx => self.cxx.borrow()[&target].clone(),
11161123
};
11171124

11181125
// Filter out -O and /O (the optimization flags) that we picked up from
@@ -1153,41 +1160,53 @@ impl Build {
11531160
}
11541161

11551162
/// Returns the path to the `ar` archive utility for the target specified.
1156-
fn ar(&self, target: TargetSelection) -> Option<&Path> {
1157-
self.ar.get(&target).map(|p| &**p)
1163+
fn ar(&self, target: TargetSelection) -> Option<PathBuf> {
1164+
if self.config.dry_run() {
1165+
return None;
1166+
}
1167+
self.ar.borrow().get(&target).cloned()
11581168
}
11591169

11601170
/// Returns the path to the `ranlib` utility for the target specified.
1161-
fn ranlib(&self, target: TargetSelection) -> Option<&Path> {
1162-
self.ranlib.get(&target).map(|p| &**p)
1171+
fn ranlib(&self, target: TargetSelection) -> Option<PathBuf> {
1172+
if self.config.dry_run() {
1173+
return None;
1174+
}
1175+
self.ranlib.borrow().get(&target).cloned()
11631176
}
11641177

11651178
/// Returns the path to the C++ compiler for the target specified.
1166-
fn cxx(&self, target: TargetSelection) -> Result<&Path, String> {
1167-
match self.cxx.get(&target) {
1168-
Some(p) => Ok(p.path()),
1179+
fn cxx(&self, target: TargetSelection) -> Result<PathBuf, String> {
1180+
if self.config.dry_run() {
1181+
return Ok(PathBuf::new());
1182+
}
1183+
match self.cxx.borrow().get(&target) {
1184+
Some(p) => Ok(p.path().into()),
11691185
None => {
11701186
Err(format!("target `{}` is not configured as a host, only as a target", target))
11711187
}
11721188
}
11731189
}
11741190

11751191
/// Returns the path to the linker for the given target if it needs to be overridden.
1176-
fn linker(&self, target: TargetSelection) -> Option<&Path> {
1177-
if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref())
1192+
fn linker(&self, target: TargetSelection) -> Option<PathBuf> {
1193+
if self.config.dry_run() {
1194+
return Some(PathBuf::new());
1195+
}
1196+
if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.clone())
11781197
{
11791198
Some(linker)
11801199
} else if target.contains("vxworks") {
11811200
// need to use CXX compiler as linker to resolve the exception functions
11821201
// that are only existed in CXX libraries
1183-
Some(self.cxx[&target].path())
1202+
Some(self.cxx.borrow()[&target].path().into())
11841203
} else if target != self.config.build
11851204
&& util::use_host_linker(target)
11861205
&& !target.contains("msvc")
11871206
{
11881207
Some(self.cc(target))
11891208
} else if self.config.use_lld && !self.is_fuse_ld_lld(target) && self.build == target {
1190-
Some(&self.initial_lld)
1209+
Some(self.initial_lld.clone())
11911210
} else {
11921211
None
11931212
}

0 commit comments

Comments
 (0)