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