From ecab8a4fae3668f9f06e1524345732f194573e9d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 18 Jan 2021 23:50:10 +0800 Subject: [PATCH] Skip unit tests of `proc-macro` crates --- cargo-miri/bin.rs | 84 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c312a581621a..b968b9df5918 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -37,9 +37,9 @@ enum MiriCommand { Setup, } -/// The inforamtion Miri needs to run a crate. Stored as JSON when the crate is "compiled". +/// The information to run a crate with the given environment. #[derive(Serialize, Deserialize)] -struct CrateRunInfo { +struct CrateRunEnv { /// The command-line arguments. args: Vec, /// The environment. @@ -48,13 +48,22 @@ struct CrateRunInfo { current_dir: OsString, } +/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +enum CrateRunInfo { + /// Run it with the given environment. + RunWith(CrateRunEnv), + /// Skip it as Miri does not support interpreting such kind of crates. + SkipProcMacroTest, +} + impl CrateRunInfo { /// Gather all the information we need. fn collect(args: env::Args) -> Self { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); - CrateRunInfo { args, env, current_dir } + Self::RunWith(CrateRunEnv { args, env, current_dir }) } fn store(&self, filename: &Path) { @@ -90,6 +99,7 @@ fn has_arg_flag(name: &str) -> bool { args.any(|val| val == name) } +/// Yields all values of command line flag `name`. struct ArgFlagValueIter<'a> { args: TakeWhile bool>, name: &'a str, @@ -455,14 +465,15 @@ fn phase_cargo_miri(mut args: env::Args) { // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. - let target = if let Some(target) = get_arg_flag_value("--target") { + let host = version_info().host; + let target = get_arg_flag_value("--target"); + let target = if let Some(ref target) = target { target } else { // No target given. Pick default and tell cargo about it. - let host = version_info().host; cmd.arg("--target"); cmd.arg(&host); - host + &host }; // Forward all further arguments. We do some processing here because we want to @@ -514,9 +525,16 @@ fn phase_cargo_miri(mut args: env::Args) { } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - // Set the runner for the current target to us as well, so we can interpret the binaries. - let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); - cmd.env(&runner_env_name, &cargo_miri_path); + let runner_env_name = |triple: &str| { + format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")) + }; + let host_runner_env_name = runner_env_name(&host); + let target_runner_env_name = runner_env_name(target); + // Set the target runner to us, so we can interpret the binaries. + cmd.env(&target_runner_env_name, &cargo_miri_path); + // Unit tests of `proc-macro` crates are run on the host, so we set the host runner to + // us in order to skip them. + cmd.env(&host_runner_env_name, &cargo_miri_path); // Set rustdoc to us as well, so we can make it do nothing (see issue #584). cmd.env("RUSTDOC", &cargo_miri_path); @@ -524,7 +542,10 @@ fn phase_cargo_miri(mut args: env::Args) { // Run cargo. if verbose { eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); - eprintln!("[cargo-miri miri] {}={:?}", runner_env_name, cargo_miri_path); + eprintln!("[cargo-miri miri] {}={:?}", target_runner_env_name, cargo_miri_path); + if *target != host { + eprintln!("[cargo-miri miri] {}={:?}", host_runner_env_name, cargo_miri_path); + } eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {:?}", cmd); cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. @@ -587,23 +608,34 @@ fn phase_cargo_rustc(args: env::Args) { _ => {}, } - if !print && target_crate && is_runnable_crate() { + let store_json = |info: CrateRunInfo| { + let filename = out_filename("", ""); + if verbose { + eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); + } + info.store(&filename); + // For Windows, do the same thing again with `.exe` appended to the filename. + // (Need to do this here as cargo moves that "binary" to a different place before running it.) + info.store(&out_filename("", ".exe")); + }; + + let runnable_crate = !print && is_runnable_crate(); + + if runnable_crate && target_crate { // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let info = CrateRunInfo::collect(args); - let filename = out_filename("", ""); - if verbose { - eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); - } - - info.store(&filename); - // For Windows, do the same thing again with `.exe` appended to the filename. - // (Need to do this here as cargo moves that "binary" to a different place before running it.) - info.store(&out_filename("", ".exe")); + store_json(CrateRunInfo::collect(args)); + return; + } + if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { + // This is a "runnable" `proc-macro` crate (unit tests). We do not support + // interpreting that under Miri now, so we write a JSON file to (display a + // helpful message and) skip it in the runner phase. + store_json(CrateRunInfo::SkipProcMacroTest); return; } @@ -671,8 +703,16 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); - let info: CrateRunInfo = serde_json::from_reader(file) + + let info = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); + let info = match info { + CrateRunInfo::RunWith(info) => info, + CrateRunInfo::SkipProcMacroTest => { + eprintln!("Running unit tests of `proc-macro` crates is not currently supported by Miri."); + return; + } + }; // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence,