@@ -37,9 +37,9 @@ enum MiriCommand {
3737 Setup ,
3838}
3939
40- /// The inforamtion Miri needs to run a crate. Stored as JSON when the crate is "compiled" .
40+ /// The information to run a crate with the given environment .
4141#[ derive( Serialize , Deserialize ) ]
42- struct CrateRunInfo {
42+ struct CrateRunEnv {
4343 /// The command-line arguments.
4444 args : Vec < String > ,
4545 /// The environment.
@@ -48,13 +48,22 @@ struct CrateRunInfo {
4848 current_dir : OsString ,
4949}
5050
51+ /// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled".
52+ #[ derive( Serialize , Deserialize ) ]
53+ enum CrateRunInfo {
54+ /// Run it with the given environment.
55+ RunWith ( CrateRunEnv ) ,
56+ /// Skip it as Miri does not support interpreting such kind of crates.
57+ SkipProcMacroTest ,
58+ }
59+
5160impl CrateRunInfo {
5261 /// Gather all the information we need.
5362 fn collect ( args : env:: Args ) -> Self {
5463 let args = args. collect ( ) ;
5564 let env = env:: vars_os ( ) . collect ( ) ;
5665 let current_dir = env:: current_dir ( ) . unwrap ( ) . into_os_string ( ) ;
57- CrateRunInfo { args, env, current_dir }
66+ Self :: RunWith ( CrateRunEnv { args, env, current_dir } )
5867 }
5968
6069 fn store ( & self , filename : & Path ) {
@@ -90,6 +99,7 @@ fn has_arg_flag(name: &str) -> bool {
9099 args. any ( |val| val == name)
91100}
92101
102+ /// Yields all values of command line flag `name`.
93103struct ArgFlagValueIter < ' a > {
94104 args : TakeWhile < env:: Args , fn ( & String ) -> bool > ,
95105 name : & ' a str ,
@@ -455,14 +465,15 @@ fn phase_cargo_miri(mut args: env::Args) {
455465 // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something,
456466 // and it later helps us detect which crates are proc-macro/build-script
457467 // (host crates) and which crates are needed for the program itself.
458- let target = if let Some ( target) = get_arg_flag_value ( "--target" ) {
468+ let host = version_info ( ) . host ;
469+ let target = get_arg_flag_value ( "--target" ) ;
470+ let target = if let Some ( ref target) = target {
459471 target
460472 } else {
461473 // No target given. Pick default and tell cargo about it.
462- let host = version_info ( ) . host ;
463474 cmd. arg ( "--target" ) ;
464475 cmd. arg ( & host) ;
465- host
476+ & host
466477 } ;
467478
468479 // Forward all further arguments. We do some processing here because we want to
@@ -514,17 +525,27 @@ fn phase_cargo_miri(mut args: env::Args) {
514525 }
515526 cmd. env ( "RUSTC_WRAPPER" , & cargo_miri_path) ;
516527
517- // Set the runner for the current target to us as well, so we can interpret the binaries.
518- let runner_env_name = format ! ( "CARGO_TARGET_{}_RUNNER" , target. to_uppercase( ) . replace( '-' , "_" ) ) ;
519- cmd. env ( & runner_env_name, & cargo_miri_path) ;
528+ let runner_env_name = |triple : & str | {
529+ format ! ( "CARGO_TARGET_{}_RUNNER" , triple. to_uppercase( ) . replace( '-' , "_" ) )
530+ } ;
531+ let host_runner_env_name = runner_env_name ( & host) ;
532+ let target_runner_env_name = runner_env_name ( target) ;
533+ // Set the target runner to us, so we can interpret the binaries.
534+ cmd. env ( & target_runner_env_name, & cargo_miri_path) ;
535+ // Unit tests of `proc-macro` crates are run on the host, so we set the host runner to
536+ // us in order to skip them.
537+ cmd. env ( & host_runner_env_name, & cargo_miri_path) ;
520538
521539 // Set rustdoc to us as well, so we can make it do nothing (see issue #584).
522540 cmd. env ( "RUSTDOC" , & cargo_miri_path) ;
523541
524542 // Run cargo.
525543 if verbose {
526544 eprintln ! ( "[cargo-miri miri] RUSTC_WRAPPER={:?}" , cargo_miri_path) ;
527- eprintln ! ( "[cargo-miri miri] {}={:?}" , runner_env_name, cargo_miri_path) ;
545+ eprintln ! ( "[cargo-miri miri] {}={:?}" , target_runner_env_name, cargo_miri_path) ;
546+ if * target != host {
547+ eprintln ! ( "[cargo-miri miri] {}={:?}" , host_runner_env_name, cargo_miri_path) ;
548+ }
528549 eprintln ! ( "[cargo-miri miri] RUSTDOC={:?}" , cargo_miri_path) ;
529550 eprintln ! ( "[cargo-miri miri] {:?}" , cmd) ;
530551 cmd. env ( "MIRI_VERBOSE" , "" ) ; // This makes the other phases verbose.
@@ -587,23 +608,34 @@ fn phase_cargo_rustc(args: env::Args) {
587608 _ => { } ,
588609 }
589610
590- if !print && target_crate && is_runnable_crate ( ) {
591- // This is the binary or test crate that we want to interpret under Miri.
592- // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not
593- // like we want them.
594- // Instead of compiling, we write JSON into the output file with all the relevant command-line flags
595- // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase.
596- let info = CrateRunInfo :: collect ( args) ;
611+ let store_json = |info : CrateRunInfo | {
597612 let filename = out_filename ( "" , "" ) ;
598613 if verbose {
599614 eprintln ! ( "[cargo-miri rustc] writing run info to `{}`" , filename. display( ) ) ;
600615 }
601-
602616 info. store ( & filename) ;
603617 // For Windows, do the same thing again with `.exe` appended to the filename.
604618 // (Need to do this here as cargo moves that "binary" to a different place before running it.)
605619 info. store ( & out_filename ( "" , ".exe" ) ) ;
620+ } ;
606621
622+ let runnable_crate = !print && is_runnable_crate ( ) ;
623+
624+ if runnable_crate && target_crate {
625+ // This is the binary or test crate that we want to interpret under Miri.
626+ // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not
627+ // like we want them.
628+ // Instead of compiling, we write JSON into the output file with all the relevant command-line flags
629+ // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase.
630+ store_json ( CrateRunInfo :: collect ( args) ) ;
631+ return ;
632+ }
633+
634+ if runnable_crate && ArgFlagValueIter :: new ( "--extern" ) . any ( |krate| krate == "proc_macro" ) {
635+ // This is a "runnable" `proc-macro` crate (unit tests). We do not support
636+ // interpreting that under Miri now, so we write a JSON file to (display a
637+ // helpful message and) skip it in the runner phase.
638+ store_json ( CrateRunInfo :: SkipProcMacroTest ) ;
607639 return ;
608640 }
609641
@@ -671,8 +703,16 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) {
671703 let file = File :: open ( & binary)
672704 . unwrap_or_else ( |_| show_error ( format ! ( "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`" , binary) ) ) ;
673705 let file = BufReader :: new ( file) ;
674- let info: CrateRunInfo = serde_json:: from_reader ( file)
706+
707+ let info = serde_json:: from_reader ( file)
675708 . unwrap_or_else ( |_| show_error ( format ! ( "file {:?} contains outdated or invalid JSON; try `cargo clean`" , binary) ) ) ;
709+ let info = match info {
710+ CrateRunInfo :: RunWith ( info) => info,
711+ CrateRunInfo :: SkipProcMacroTest => {
712+ eprintln ! ( "Running unit tests of `proc-macro` crates is not currently supported by Miri." ) ;
713+ return ;
714+ }
715+ } ;
676716
677717 // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but
678718 // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence,
0 commit comments