11//! Implements the various phases of `cargo miri run/test`.
22
3+ use std:: env;
34use std:: fs:: { self , File } ;
4- use std:: io:: { BufReader , Write } ;
5+ use std:: io:: BufReader ;
56use std:: path:: { Path , PathBuf } ;
67use std:: process:: Command ;
7- use std:: { env, thread} ;
88
99use rustc_version:: VersionMeta ;
1010
@@ -24,10 +24,7 @@ Subcommands:
2424 clean Clean the Miri cache & target directory
2525
2626The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively.
27- Furthermore, the following extra flags and environment variables are recognized for `run` and `test`:
28-
29- --many-seeds[=from..to] Run the program/tests many times with different seeds in the given range.
30- The range defaults to `0..64`.
27+ Furthermore, the following environment variables are recognized for `run` and `test`:
3128
3229 MIRIFLAGS Extra flags to pass to the Miri driver. Use this to pass `-Zmiri-...` flags.
3330
@@ -41,8 +38,6 @@ Examples:
4138
4239" ;
4340
44- const DEFAULT_MANY_SEEDS : & str = "0..64" ;
45-
4641fn show_help ( ) {
4742 println ! ( "{CARGO_MIRI_HELP}" ) ;
4843}
@@ -182,17 +177,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
182177 let target_dir = get_target_dir ( & metadata) ;
183178 cmd. arg ( "--target-dir" ) . arg ( target_dir) ;
184179
185- // Store many-seeds argument.
186- let mut many_seeds = None ;
187180 // *After* we set all the flags that need setting, forward everything else. Make sure to skip
188- // `--target-dir` (which would otherwise be set twice) and `--many-seeds` (which is our flag, not cargo's) .
181+ // `--target-dir` (which would otherwise be set twice).
189182 for arg in
190183 ArgSplitFlagValue :: from_string_iter ( & mut args, "--target-dir" ) . filter_map ( Result :: err)
191184 {
192- if arg == "--many-seeds" {
193- many_seeds = Some ( DEFAULT_MANY_SEEDS . to_owned ( ) ) ;
194- } else if let Some ( val ) = arg . strip_prefix ( " --many-seeds=" ) {
195- many_seeds = Some ( val . to_owned ( ) ) ;
185+ if arg == "--many-seeds" || arg . starts_with ( "--many-seeds=" ) {
186+ show_error ! (
187+ "ERROR: the ` --many-seeds` flag has been removed from cargo-miri; use MIRIFLAGS=-Zmiri-many-seeds instead"
188+ ) ;
196189 } else {
197190 cmd. arg ( arg) ;
198191 }
@@ -249,9 +242,6 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
249242 // Forward some crucial information to our own re-invocations.
250243 cmd. env ( "MIRI_SYSROOT" , miri_sysroot) ;
251244 cmd. env ( "MIRI_LOCAL_CRATES" , local_crates ( & metadata) ) ;
252- if let Some ( many_seeds) = many_seeds {
253- cmd. env ( "MIRI_MANY_SEEDS" , many_seeds) ;
254- }
255245 if verbose > 0 {
256246 cmd. env ( "MIRI_VERBOSE" , verbose. to_string ( ) ) ; // This makes the other phases verbose.
257247 }
@@ -407,14 +397,11 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
407397
408398 // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above.
409399 let mut args = env. args ;
410- let mut out_filename = None ;
411400 for i in 0 ..args. len ( ) {
412401 if args[ i] == "-o" {
413- out_filename = Some ( args[ i + 1 ] . clone ( ) ) ;
414402 args[ i + 1 ] . push_str ( ".miri" ) ;
415403 }
416404 }
417- let out_filename = out_filename. expect ( "rustdoc must pass `-o`" ) ;
418405
419406 cmd. args ( & args) ;
420407 cmd. env ( "MIRI_BE_RUSTC" , "target" ) ;
@@ -427,7 +414,7 @@ pub fn phase_rustc(mut args: impl Iterator<Item = String>, phase: RustcPhase) {
427414 eprintln ! ( "[cargo-miri rustc inside rustdoc] going to run:\n {cmd:?}" ) ;
428415 }
429416
430- exec_with_pipe ( cmd, & env. stdin , format ! ( "{out_filename}.stdin" ) ) ;
417+ exec_with_pipe ( cmd, & env. stdin ) ;
431418 }
432419
433420 return ;
@@ -589,111 +576,81 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
589576 }
590577 } ;
591578
592- let many_seeds = env:: var ( "MIRI_MANY_SEEDS" ) ;
593- run_many_seeds ( many_seeds. ok ( ) , |seed| {
594- let mut cmd = miri ( ) ;
595-
596- // Set missing env vars. We prefer build-time env vars over run-time ones; see
597- // <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes.
598- for ( name, val) in & info. env {
599- // `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time
600- // the program is being run, that jobserver no longer exists (cargo only runs the jobserver
601- // for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this.
602- // Also see <https://github.com/rust-lang/rust/pull/113730>.
603- if name == "CARGO_MAKEFLAGS" {
604- continue ;
605- }
606- if let Some ( old_val) = env:: var_os ( name) {
607- if * old_val == * val {
608- // This one did not actually change, no need to re-set it.
609- // (This keeps the `debug_cmd` below more manageable.)
610- continue ;
611- } else if verbose > 0 {
612- eprintln ! (
613- "[cargo-miri runner] Overwriting run-time env var {name:?}={old_val:?} with build-time value {val:?}"
614- ) ;
615- }
616- }
617- cmd. env ( name, val) ;
618- }
579+ let mut cmd = miri ( ) ;
619580
620- if phase != RunnerPhase :: Rustdoc {
621- // Set the sysroot. Not necessary in rustdoc, where we already set the sysroot in
622- // `phase_rustdoc`. rustdoc will forward that flag when invoking rustc (i.e., us), so the
623- // flag is present in `info.args`.
624- cmd. arg ( "--sysroot" ) . arg ( env:: var_os ( "MIRI_SYSROOT" ) . unwrap ( ) ) ;
581+ // Set missing env vars. We prefer build-time env vars over run-time ones; see
582+ // <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes.
583+ for ( name, val) in & info. env {
584+ // `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time
585+ // the program is being run, that jobserver no longer exists (cargo only runs the jobserver
586+ // for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this.
587+ // Also see <https://github.com/rust-lang/rust/pull/113730>.
588+ if name == "CARGO_MAKEFLAGS" {
589+ continue ;
625590 }
626- // Forward rustc arguments.
627- // We need to patch "--extern" filenames because we forced a check-only
628- // build without cargo knowing about that: replace `.rlib` suffix by
629- // `.rmeta`.
630- // We also need to remove `--error-format` as cargo specifies that to be JSON,
631- // but when we run here, cargo does not interpret the JSON any more. `--json`
632- // then also needs to be dropped.
633- let mut args = info. args . iter ( ) ;
634- while let Some ( arg) = args. next ( ) {
635- if arg == "--extern" {
636- forward_patched_extern_arg ( & mut ( & mut args) . cloned ( ) , & mut cmd) ;
637- } else if let Some ( suffix) = arg. strip_prefix ( "--error-format" ) {
638- assert ! ( suffix. starts_with( '=' ) ) ;
639- // Drop this argument.
640- } else if let Some ( suffix) = arg. strip_prefix ( "--json" ) {
641- assert ! ( suffix. starts_with( '=' ) ) ;
642- // Drop this argument.
643- } else {
644- cmd. arg ( arg) ;
591+ if let Some ( old_val) = env:: var_os ( name) {
592+ if * old_val == * val {
593+ // This one did not actually change, no need to re-set it.
594+ // (This keeps the `debug_cmd` below more manageable.)
595+ continue ;
596+ } else if verbose > 0 {
597+ eprintln ! (
598+ "[cargo-miri runner] Overwriting run-time env var {name:?}={old_val:?} with build-time value {val:?}"
599+ ) ;
645600 }
646601 }
647- // Respect `MIRIFLAGS`.
648- if let Ok ( a) = env:: var ( "MIRIFLAGS" ) {
649- let args = flagsplit ( & a) ;
650- cmd. args ( args) ;
651- }
652- // Set the current seed.
653- if let Some ( seed) = seed {
654- eprintln ! ( "Trying seed: {seed}" ) ;
655- cmd. arg ( format ! ( "-Zmiri-seed={seed}" ) ) ;
656- }
602+ cmd. env ( name, val) ;
603+ }
657604
658- // Then pass binary arguments.
659- cmd. arg ( "--" ) ;
660- cmd. args ( & binary_args) ;
661-
662- // Make sure we use the build-time working directory for interpreting Miri/rustc arguments.
663- // But then we need to switch to the run-time one, which we instruct Miri to do by setting `MIRI_CWD`.
664- cmd. current_dir ( & info. current_dir ) ;
665- cmd. env ( "MIRI_CWD" , env:: current_dir ( ) . unwrap ( ) ) ;
666-
667- // Run it.
668- debug_cmd ( "[cargo-miri runner]" , verbose, & cmd) ;
669-
670- match phase {
671- RunnerPhase :: Rustdoc => {
672- cmd. stdin ( std:: process:: Stdio :: piped ( ) ) ;
673- // the warning is wrong, we have a `wait` inside the `scope` closure.
674- let mut child = cmd. spawn ( ) . expect ( "failed to spawn process" ) ;
675- let child_stdin = child. stdin . take ( ) . unwrap ( ) ;
676- // Write stdin in a background thread, as it may block.
677- let exit_status = thread:: scope ( |s| {
678- s. spawn ( || {
679- let mut child_stdin = child_stdin;
680- // Ignore failure, it is most likely due to the process having terminated.
681- let _ = child_stdin. write_all ( & info. stdin ) ;
682- } ) ;
683- child. wait ( ) . expect ( "failed to run command" )
684- } ) ;
685- if !exit_status. success ( ) {
686- std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) ) ;
687- }
688- }
689- RunnerPhase :: Cargo => {
690- let exit_status = cmd. status ( ) . expect ( "failed to run command" ) ;
691- if !exit_status. success ( ) {
692- std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) ) ;
693- }
694- }
605+ if phase != RunnerPhase :: Rustdoc {
606+ // Set the sysroot. Not necessary in rustdoc, where we already set the sysroot in
607+ // `phase_rustdoc`. rustdoc will forward that flag when invoking rustc (i.e., us), so the
608+ // flag is present in `info.args`.
609+ cmd. arg ( "--sysroot" ) . arg ( env:: var_os ( "MIRI_SYSROOT" ) . unwrap ( ) ) ;
610+ }
611+ // Forward rustc arguments.
612+ // We need to patch "--extern" filenames because we forced a check-only
613+ // build without cargo knowing about that: replace `.rlib` suffix by
614+ // `.rmeta`.
615+ // We also need to remove `--error-format` as cargo specifies that to be JSON,
616+ // but when we run here, cargo does not interpret the JSON any more. `--json`
617+ // then also needs to be dropped.
618+ let mut args = info. args . iter ( ) ;
619+ while let Some ( arg) = args. next ( ) {
620+ if arg == "--extern" {
621+ forward_patched_extern_arg ( & mut ( & mut args) . cloned ( ) , & mut cmd) ;
622+ } else if let Some ( suffix) = arg. strip_prefix ( "--error-format" ) {
623+ assert ! ( suffix. starts_with( '=' ) ) ;
624+ // Drop this argument.
625+ } else if let Some ( suffix) = arg. strip_prefix ( "--json" ) {
626+ assert ! ( suffix. starts_with( '=' ) ) ;
627+ // Drop this argument.
628+ } else {
629+ cmd. arg ( arg) ;
695630 }
696- } ) ;
631+ }
632+ // Respect `MIRIFLAGS`.
633+ if let Ok ( a) = env:: var ( "MIRIFLAGS" ) {
634+ let args = flagsplit ( & a) ;
635+ cmd. args ( args) ;
636+ }
637+
638+ // Then pass binary arguments.
639+ cmd. arg ( "--" ) ;
640+ cmd. args ( & binary_args) ;
641+
642+ // Make sure we use the build-time working directory for interpreting Miri/rustc arguments.
643+ // But then we need to switch to the run-time one, which we instruct Miri to do by setting `MIRI_CWD`.
644+ cmd. current_dir ( & info. current_dir ) ;
645+ cmd. env ( "MIRI_CWD" , env:: current_dir ( ) . unwrap ( ) ) ;
646+
647+ // Run it.
648+ debug_cmd ( "[cargo-miri runner]" , verbose, & cmd) ;
649+
650+ match phase {
651+ RunnerPhase :: Rustdoc => exec_with_pipe ( cmd, & info. stdin ) ,
652+ RunnerPhase :: Cargo => exec ( cmd) ,
653+ }
697654}
698655
699656pub fn phase_rustdoc ( mut args : impl Iterator < Item = String > ) {
0 commit comments