Skip to content

Commit 78d556e

Browse files
committed
Auto merge of rust-lang#3418 - RalfJung:cargo-miri, r=RalfJung
cargo-miri, miri-script, tests/ui: misc simplifications and comments Parts of rust-lang/miri#3411 that can be landed now.
2 parents 5f73da7 + 5b877a3 commit 78d556e

File tree

3 files changed

+72
-69
lines changed

3 files changed

+72
-69
lines changed

src/tools/miri/cargo-miri/src/phases.rs

+31-30
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,14 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
192192
"WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver."
193193
);
194194
}
195-
// Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke
196-
// `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that
197-
// to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host,
198-
// is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc
199-
// (it might be unable to produce binaries since the sysroot is check-only), but it's as close
200-
// as we can get, and it's good enough for autocfg.
195+
// Ideally we would set RUSTC to some non-existent path, so we can be sure our wrapping is
196+
// always applied. However, buggy build scripts (https://github.com/eyre-rs/eyre/issues/84) and
197+
// also cargo (https://github.com/rust-lang/cargo/issues/10885) will invoke `rustc` even when
198+
// `RUSTC_WRAPPER` is set, bypassing the wrapper. To make sure everything is coherent, we want
199+
// that to be the Miri driver, but acting as rustc, on the target level. (Target, rather than
200+
// host, is needed for cross-interpretation situations.) This is not a perfect emulation of real
201+
// rustc (it might be unable to produce binaries since the sysroot is check-only), but it's as
202+
// close as we can get, and it's good enough for autocfg.
201203
//
202204
// In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc
203205
// or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that
@@ -251,6 +253,16 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
251253
/// Cargo does not give us this information directly, so we need to check
252254
/// various command-line flags.
253255
fn is_runnable_crate() -> bool {
256+
// Determine whether this is cargo invoking rustc to get some infos. Ideally we'd check "is
257+
// there a filename passed to rustc", but that's very hard as we would have to know whether
258+
// e.g. `--print foo` is a booolean flag `--print` followed by filename `foo` or equivalent
259+
// to `--print=foo`. So instead we use this more fragile approach of detecting the presence
260+
// of a "query" flag rather than the absence of a filename.
261+
let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
262+
if info_query {
263+
// Nothing to run.
264+
return false;
265+
}
254266
let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin";
255267
let is_test = has_arg_flag("--test");
256268
is_bin || is_test
@@ -297,8 +309,6 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
297309
let verbose = std::env::var("MIRI_VERBOSE")
298310
.map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer"));
299311
let target_crate = is_target_crate();
300-
// Determine whether this is cargo invoking rustc to get some infos.
301-
let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
302312

303313
let store_json = |info: CrateRunInfo| {
304314
if get_arg_flag_value("--emit").unwrap_or_default().split(',').any(|e| e == "dep-info") {
@@ -325,7 +335,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
325335
}
326336
};
327337

328-
let runnable_crate = !info_query && is_runnable_crate();
338+
let runnable_crate = is_runnable_crate();
329339

330340
if runnable_crate && target_crate {
331341
assert!(
@@ -399,7 +409,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
399409
let mut emit_link_hack = false;
400410
// Arguments are treated very differently depending on whether this crate is
401411
// for interpretation by Miri, or for use by a build script / proc macro.
402-
if !info_query && target_crate {
412+
if target_crate {
403413
// Forward arguments, but remove "link" from "--emit" to make this a check-only build.
404414
let emit_flag = "--emit";
405415
while let Some(arg) = args.next() {
@@ -433,17 +443,14 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
433443
cmd.arg("-C").arg("panic=abort");
434444
}
435445
} else {
436-
// For host crates (but not when we are just printing some info),
437-
// we might still have to set the sysroot.
438-
if !info_query {
439-
// When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly
440-
// due to bootstrap complications.
441-
if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") {
442-
cmd.arg("--sysroot").arg(sysroot);
443-
}
446+
// This is a host crate.
447+
// When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly
448+
// due to bootstrap complications.
449+
if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") {
450+
cmd.arg("--sysroot").arg(sysroot);
444451
}
445452

446-
// For host crates or when we are printing, just forward everything.
453+
// Forward everything.
447454
cmd.args(args);
448455
}
449456

@@ -455,9 +462,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
455462

456463
// Run it.
457464
if verbose > 0 {
458-
eprintln!(
459-
"[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}"
460-
);
465+
eprintln!("[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate}");
461466
}
462467

463468
// Create a stub .rlib file if "link" was requested by cargo.
@@ -546,15 +551,13 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
546551
// but when we run here, cargo does not interpret the JSON any more. `--json`
547552
// then also needs to be dropped.
548553
let mut args = info.args.into_iter();
549-
let error_format_flag = "--error-format";
550-
let json_flag = "--json";
551554
while let Some(arg) = args.next() {
552555
if arg == "--extern" {
553556
forward_patched_extern_arg(&mut args, &mut cmd);
554-
} else if let Some(suffix) = arg.strip_prefix(error_format_flag) {
557+
} else if let Some(suffix) = arg.strip_prefix("--error-format") {
555558
assert!(suffix.starts_with('='));
556559
// Drop this argument.
557-
} else if let Some(suffix) = arg.strip_prefix(json_flag) {
560+
} else if let Some(suffix) = arg.strip_prefix("--json") {
558561
assert!(suffix.starts_with('='));
559562
// Drop this argument.
560563
} else {
@@ -592,13 +595,11 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
592595
// just default to a straight-forward invocation for now:
593596
let mut cmd = Command::new("rustdoc");
594597

595-
let extern_flag = "--extern";
596-
let runtool_flag = "--runtool";
597598
while let Some(arg) = args.next() {
598-
if arg == extern_flag {
599+
if arg == "--extern" {
599600
// Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
600601
forward_patched_extern_arg(&mut args, &mut cmd);
601-
} else if arg == runtool_flag {
602+
} else if arg == "--runtool" {
602603
// An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support.
603604
// Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag;
604605
// otherwise, we won't be called as rustdoc at all.

src/tools/miri/miri-script/src/commands.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -479,10 +479,11 @@ impl Command {
479479
Ok(())
480480
}
481481

482-
fn run(dep: bool, flags: Vec<OsString>) -> Result<()> {
482+
fn run(dep: bool, mut flags: Vec<OsString>) -> Result<()> {
483483
let mut e = MiriEnv::new()?;
484484
// Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so
485-
// that we set the MIRI_SYSROOT up the right way.
485+
// that we set the MIRI_SYSROOT up the right way. We must make sure that
486+
// MIRI_TEST_TARGET and `--target` are in sync.
486487
use itertools::Itertools;
487488
let target = flags
488489
.iter()
@@ -493,33 +494,35 @@ impl Command {
493494
// Found it!
494495
e.sh.set_var("MIRI_TEST_TARGET", target);
495496
} else if let Ok(target) = std::env::var("MIRI_TEST_TARGET") {
496-
// Make sure miri actually uses this target.
497-
let miriflags = e.sh.var("MIRIFLAGS").unwrap_or_default();
498-
e.sh.set_var("MIRIFLAGS", format!("{miriflags} --target {target}"));
497+
// Convert `MIRI_TEST_TARGET` into `--target`.
498+
flags.push("--target".into());
499+
flags.push(target.into());
499500
}
500-
// Scan for "--edition" (we'll set one ourselves if that flag is not present).
501+
// Scan for "--edition", set one ourselves if that flag is not present.
501502
let have_edition =
502503
flags.iter().take_while(|arg| *arg != "--").any(|arg| *arg == "--edition");
504+
if !have_edition {
505+
flags.push("--edition=2021".into()); // keep in sync with `tests/ui.rs`.`
506+
}
503507

504508
// Prepare a sysroot.
505509
e.build_miri_sysroot(/* quiet */ true)?;
506510

507-
// Then run the actual command.
511+
// Then run the actual command. Also add MIRIFLAGS.
508512
let miri_manifest = path!(e.miri_dir / "Cargo.toml");
509513
let miri_flags = e.sh.var("MIRIFLAGS").unwrap_or_default();
510514
let miri_flags = flagsplit(&miri_flags);
511515
let toolchain = &e.toolchain;
512516
let extra_flags = &e.cargo_extra_flags;
513-
let edition_flags = (!have_edition).then_some("--edition=2021"); // keep in sync with `tests/ui.rs`.`
514517
if dep {
515518
cmd!(
516519
e.sh,
517-
"cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {edition_flags...} {flags...}"
520+
"cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {flags...}"
518521
).quiet().run()?;
519522
} else {
520523
cmd!(
521524
e.sh,
522-
"cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {edition_flags...} {flags...}"
525+
"cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {flags...}"
523526
).quiet().run()?;
524527
}
525528
Ok(())

src/tools/miri/tests/ui.rs

+28-29
Original file line numberDiff line numberDiff line change
@@ -54,34 +54,13 @@ fn build_so_for_c_ffi_tests() -> PathBuf {
5454
so_file_path
5555
}
5656

57-
fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config {
57+
/// Does *not* set any args or env vars, since it is shared between the test runner and
58+
/// run_dep_mode.
59+
fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config {
5860
// Miri is rustc-like, so we create a default builder for rustc and modify it
5961
let mut program = CommandBuilder::rustc();
6062
program.program = miri_path();
6163

62-
// Add some flags we always want.
63-
program.args.push("-Dwarnings".into());
64-
program.args.push("-Dunused".into());
65-
program.args.push("-Ainternal_features".into());
66-
if let Ok(extra_flags) = env::var("MIRIFLAGS") {
67-
for flag in extra_flags.split_whitespace() {
68-
program.args.push(flag.into());
69-
}
70-
}
71-
program.args.push("-Zui-testing".into());
72-
program.args.push("--target".into());
73-
program.args.push(target.into());
74-
75-
// If we're on linux, and we're testing the extern-so functionality,
76-
// then build the shared object file for testing external C function calls
77-
// and push the relevant compiler flag.
78-
if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
79-
let so_file_path = build_so_for_c_ffi_tests();
80-
let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
81-
flag.push(so_file_path.into_os_string());
82-
program.args.push(flag);
83-
}
84-
8564
let mut config = Config {
8665
target: Some(target.to_owned()),
8766
stderr_filters: STDERR.clone(),
@@ -119,17 +98,38 @@ fn run_tests(
11998
with_dependencies: bool,
12099
tmpdir: &Path,
121100
) -> Result<()> {
122-
let mut config = test_config(target, path, mode, with_dependencies);
101+
let mut config = miri_config(target, path, mode, with_dependencies);
123102

124103
// Add a test env var to do environment communication tests.
125104
config.program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));
126-
127105
// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
128106
config.program.envs.push(("MIRI_TEMP".into(), Some(tmpdir.to_owned().into())));
129-
130107
// If a test ICEs, we want to see a backtrace.
131108
config.program.envs.push(("RUST_BACKTRACE".into(), Some("1".into())));
132109

110+
// Add some flags we always want.
111+
config.program.args.push("-Dwarnings".into());
112+
config.program.args.push("-Dunused".into());
113+
config.program.args.push("-Ainternal_features".into());
114+
if let Ok(extra_flags) = env::var("MIRIFLAGS") {
115+
for flag in extra_flags.split_whitespace() {
116+
config.program.args.push(flag.into());
117+
}
118+
}
119+
config.program.args.push("-Zui-testing".into());
120+
config.program.args.push("--target".into());
121+
config.program.args.push(target.into());
122+
123+
// If we're on linux, and we're testing the extern-so functionality,
124+
// then build the shared object file for testing external C function calls
125+
// and push the relevant compiler flag.
126+
if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
127+
let so_file_path = build_so_for_c_ffi_tests();
128+
let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
129+
flag.push(so_file_path.into_os_string());
130+
config.program.args.push(flag);
131+
}
132+
133133
// Handle command-line arguments.
134134
let args = ui_test::Args::test()?;
135135
let default_bless = env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
@@ -292,13 +292,12 @@ fn main() -> Result<()> {
292292

293293
fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Result<()> {
294294
let path = args.next().expect("./miri run-dep must be followed by a file name");
295-
let mut config = test_config(
295+
let config = miri_config(
296296
&target,
297297
"",
298298
Mode::Yolo { rustfix: RustfixMode::Disabled },
299299
/* with dependencies */ true,
300300
);
301-
config.program.args.clear(); // We want to give the user full control over flags
302301
let dep_args = config.build_dependencies()?;
303302

304303
let mut cmd = config.program.build(&config.out_dir);

0 commit comments

Comments
 (0)