Auto merge of #3419 - RalfJung:rustup, r=RalfJung
Rustup
https://github.com/rust-lang/rust/pull/123081 landed so hopefully this works now.
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 52f96a2..f49bc6d 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -192,12 +192,14 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
"WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver."
);
}
- // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke
- // `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that
- // to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host,
- // is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc
- // (it might be unable to produce binaries since the sysroot is check-only), but it's as close
- // as we can get, and it's good enough for autocfg.
+ // Ideally we would set RUSTC to some non-existent path, so we can be sure our wrapping is
+ // always applied. However, buggy build scripts (https://github.com/eyre-rs/eyre/issues/84) and
+ // also cargo (https://github.com/rust-lang/cargo/issues/10885) will invoke `rustc` even when
+ // `RUSTC_WRAPPER` is set, bypassing the wrapper. To make sure everything is coherent, we want
+ // that to be the Miri driver, but acting as rustc, on the target level. (Target, rather than
+ // host, is needed for cross-interpretation situations.) This is not a perfect emulation of real
+ // rustc (it might be unable to produce binaries since the sysroot is check-only), but it's as
+ // close as we can get, and it's good enough for autocfg.
//
// In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc
// or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that
@@ -251,6 +253,16 @@ fn is_target_crate() -> bool {
/// Cargo does not give us this information directly, so we need to check
/// various command-line flags.
fn is_runnable_crate() -> bool {
+ // Determine whether this is cargo invoking rustc to get some infos. Ideally we'd check "is
+ // there a filename passed to rustc", but that's very hard as we would have to know whether
+ // e.g. `--print foo` is a booolean flag `--print` followed by filename `foo` or equivalent
+ // to `--print=foo`. So instead we use this more fragile approach of detecting the presence
+ // of a "query" flag rather than the absence of a filename.
+ let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
+ if info_query {
+ // Nothing to run.
+ return false;
+ }
let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin";
let is_test = has_arg_flag("--test");
is_bin || is_test
@@ -297,8 +309,6 @@ fn out_filenames() -> Vec<PathBuf> {
let verbose = std::env::var("MIRI_VERBOSE")
.map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer"));
let target_crate = is_target_crate();
- // Determine whether this is cargo invoking rustc to get some infos.
- let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV");
let store_json = |info: CrateRunInfo| {
if get_arg_flag_value("--emit").unwrap_or_default().split(',').any(|e| e == "dep-info") {
@@ -325,7 +335,7 @@ fn out_filenames() -> Vec<PathBuf> {
}
};
- let runnable_crate = !info_query && is_runnable_crate();
+ let runnable_crate = is_runnable_crate();
if runnable_crate && target_crate {
assert!(
@@ -399,7 +409,7 @@ fn out_filenames() -> Vec<PathBuf> {
let mut emit_link_hack = false;
// Arguments are treated very differently depending on whether this crate is
// for interpretation by Miri, or for use by a build script / proc macro.
- if !info_query && target_crate {
+ if target_crate {
// Forward arguments, but remove "link" from "--emit" to make this a check-only build.
let emit_flag = "--emit";
while let Some(arg) = args.next() {
@@ -433,17 +443,14 @@ fn out_filenames() -> Vec<PathBuf> {
cmd.arg("-C").arg("panic=abort");
}
} else {
- // For host crates (but not when we are just printing some info),
- // we might still have to set the sysroot.
- if !info_query {
- // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly
- // due to bootstrap complications.
- if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") {
- cmd.arg("--sysroot").arg(sysroot);
- }
+ // This is a host crate.
+ // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly
+ // due to bootstrap complications.
+ if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") {
+ cmd.arg("--sysroot").arg(sysroot);
}
- // For host crates or when we are printing, just forward everything.
+ // Forward everything.
cmd.args(args);
}
@@ -455,9 +462,7 @@ fn out_filenames() -> Vec<PathBuf> {
// Run it.
if verbose > 0 {
- eprintln!(
- "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}"
- );
+ eprintln!("[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate}");
}
// 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
// but when we run here, cargo does not interpret the JSON any more. `--json`
// then also needs to be dropped.
let mut args = info.args.into_iter();
- let error_format_flag = "--error-format";
- let json_flag = "--json";
while let Some(arg) = args.next() {
if arg == "--extern" {
forward_patched_extern_arg(&mut args, &mut cmd);
- } else if let Some(suffix) = arg.strip_prefix(error_format_flag) {
+ } else if let Some(suffix) = arg.strip_prefix("--error-format") {
assert!(suffix.starts_with('='));
// Drop this argument.
- } else if let Some(suffix) = arg.strip_prefix(json_flag) {
+ } else if let Some(suffix) = arg.strip_prefix("--json") {
assert!(suffix.starts_with('='));
// Drop this argument.
} else {
@@ -592,13 +595,11 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) {
// just default to a straight-forward invocation for now:
let mut cmd = Command::new("rustdoc");
- let extern_flag = "--extern";
- let runtool_flag = "--runtool";
while let Some(arg) = args.next() {
- if arg == extern_flag {
+ if arg == "--extern" {
// Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
forward_patched_extern_arg(&mut args, &mut cmd);
- } else if arg == runtool_flag {
+ } else if arg == "--runtool" {
// An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support.
// Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag;
// otherwise, we won't be called as rustdoc at all.
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 66f3232..58deac6 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -479,10 +479,11 @@ fn test(bless: bool, flags: Vec<OsString>) -> Result<()> {
Ok(())
}
- fn run(dep: bool, flags: Vec<OsString>) -> Result<()> {
+ fn run(dep: bool, mut flags: Vec<OsString>) -> Result<()> {
let mut e = MiriEnv::new()?;
// Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so
- // that we set the MIRI_SYSROOT up the right way.
+ // that we set the MIRI_SYSROOT up the right way. We must make sure that
+ // MIRI_TEST_TARGET and `--target` are in sync.
use itertools::Itertools;
let target = flags
.iter()
@@ -493,33 +494,35 @@ fn run(dep: bool, flags: Vec<OsString>) -> Result<()> {
// Found it!
e.sh.set_var("MIRI_TEST_TARGET", target);
} else if let Ok(target) = std::env::var("MIRI_TEST_TARGET") {
- // Make sure miri actually uses this target.
- let miriflags = e.sh.var("MIRIFLAGS").unwrap_or_default();
- e.sh.set_var("MIRIFLAGS", format!("{miriflags} --target {target}"));
+ // Convert `MIRI_TEST_TARGET` into `--target`.
+ flags.push("--target".into());
+ flags.push(target.into());
}
- // Scan for "--edition" (we'll set one ourselves if that flag is not present).
+ // Scan for "--edition", set one ourselves if that flag is not present.
let have_edition =
flags.iter().take_while(|arg| *arg != "--").any(|arg| *arg == "--edition");
+ if !have_edition {
+ flags.push("--edition=2021".into()); // keep in sync with `tests/ui.rs`.`
+ }
// Prepare a sysroot.
e.build_miri_sysroot(/* quiet */ true)?;
- // Then run the actual command.
+ // Then run the actual command. Also add MIRIFLAGS.
let miri_manifest = path!(e.miri_dir / "Cargo.toml");
let miri_flags = e.sh.var("MIRIFLAGS").unwrap_or_default();
let miri_flags = flagsplit(&miri_flags);
let toolchain = &e.toolchain;
let extra_flags = &e.cargo_extra_flags;
- let edition_flags = (!have_edition).then_some("--edition=2021"); // keep in sync with `tests/ui.rs`.`
if dep {
cmd!(
e.sh,
- "cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {edition_flags...} {flags...}"
+ "cargo +{toolchain} --quiet test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode {miri_flags...} {flags...}"
).quiet().run()?;
} else {
cmd!(
e.sh,
- "cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {edition_flags...} {flags...}"
+ "cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {flags...}"
).quiet().run()?;
}
Ok(())
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index 129d1df..a75fa4c 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -54,34 +54,13 @@ fn build_so_for_c_ffi_tests() -> PathBuf {
so_file_path
}
-fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config {
+/// Does *not* set any args or env vars, since it is shared between the test runner and
+/// run_dep_mode.
+fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config {
// Miri is rustc-like, so we create a default builder for rustc and modify it
let mut program = CommandBuilder::rustc();
program.program = miri_path();
- // Add some flags we always want.
- program.args.push("-Dwarnings".into());
- program.args.push("-Dunused".into());
- program.args.push("-Ainternal_features".into());
- if let Ok(extra_flags) = env::var("MIRIFLAGS") {
- for flag in extra_flags.split_whitespace() {
- program.args.push(flag.into());
- }
- }
- program.args.push("-Zui-testing".into());
- program.args.push("--target".into());
- program.args.push(target.into());
-
- // If we're on linux, and we're testing the extern-so functionality,
- // then build the shared object file for testing external C function calls
- // and push the relevant compiler flag.
- if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
- let so_file_path = build_so_for_c_ffi_tests();
- let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
- flag.push(so_file_path.into_os_string());
- program.args.push(flag);
- }
-
let mut config = Config {
target: Some(target.to_owned()),
stderr_filters: STDERR.clone(),
@@ -119,17 +98,38 @@ fn run_tests(
with_dependencies: bool,
tmpdir: &Path,
) -> Result<()> {
- let mut config = test_config(target, path, mode, with_dependencies);
+ let mut config = miri_config(target, path, mode, with_dependencies);
// Add a test env var to do environment communication tests.
config.program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into())));
-
// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
config.program.envs.push(("MIRI_TEMP".into(), Some(tmpdir.to_owned().into())));
-
// If a test ICEs, we want to see a backtrace.
config.program.envs.push(("RUST_BACKTRACE".into(), Some("1".into())));
+ // Add some flags we always want.
+ config.program.args.push("-Dwarnings".into());
+ config.program.args.push("-Dunused".into());
+ config.program.args.push("-Ainternal_features".into());
+ if let Ok(extra_flags) = env::var("MIRIFLAGS") {
+ for flag in extra_flags.split_whitespace() {
+ config.program.args.push(flag.into());
+ }
+ }
+ config.program.args.push("-Zui-testing".into());
+ config.program.args.push("--target".into());
+ config.program.args.push(target.into());
+
+ // If we're on linux, and we're testing the extern-so functionality,
+ // then build the shared object file for testing external C function calls
+ // and push the relevant compiler flag.
+ if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
+ let so_file_path = build_so_for_c_ffi_tests();
+ let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
+ flag.push(so_file_path.into_os_string());
+ config.program.args.push(flag);
+ }
+
// Handle command-line arguments.
let args = ui_test::Args::test()?;
let default_bless = env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
@@ -292,13 +292,12 @@ fn main() -> Result<()> {
fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Result<()> {
let path = args.next().expect("./miri run-dep must be followed by a file name");
- let mut config = test_config(
+ let config = miri_config(
&target,
"",
Mode::Yolo { rustfix: RustfixMode::Disabled },
/* with dependencies */ true,
);
- config.program.args.clear(); // We want to give the user full control over flags
let dep_args = config.build_dependencies()?;
let mut cmd = config.program.build(&config.out_dir);