@@ -157,6 +157,22 @@ fn exec(mut cmd: Command) {
157157 }
158158}
159159
160+ /// Execute the command and pipe `input` into its stdin.
161+ /// If it fails, fail this process with the same exit code.
162+ /// Otherwise, continue.
163+ fn exec_with_pipe ( mut cmd : Command , input : & [ u8 ] ) {
164+ cmd. stdin ( std:: process:: Stdio :: piped ( ) ) ;
165+ let mut child = cmd. spawn ( ) . expect ( "failed to spawn process" ) ;
166+ {
167+ let stdin = child. stdin . as_mut ( ) . expect ( "failed to open stdin" ) ;
168+ stdin. write_all ( input) . expect ( "failed to write out test source" ) ;
169+ }
170+ let exit_status = child. wait ( ) . expect ( "failed to run command" ) ;
171+ if exit_status. success ( ) . not ( ) {
172+ std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) )
173+ }
174+ }
175+
160176fn xargo_version ( ) -> Option < ( u32 , u32 , u32 ) > {
161177 let out = xargo_check ( ) . arg ( "--version" ) . output ( ) . ok ( ) ?;
162178 if !out. status . success ( ) {
@@ -598,6 +614,34 @@ fn phase_cargo_rustc(args: env::Args) {
598614 // (Need to do this here as cargo moves that "binary" to a different place before running it.)
599615 info. store ( & out_filename ( "" , ".exe" ) ) ;
600616
617+ // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`,
618+ // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build.
619+ if std:: env:: var_os ( "MIRI_CALLED_FROM_RUSTDOC" ) . is_some ( ) {
620+ let mut cmd = miri ( ) ;
621+
622+ // use our own sysroot
623+ if !has_arg_flag ( "--sysroot" ) {
624+ let sysroot = env:: var_os ( "MIRI_SYSROOT" )
625+ . expect ( "the wrapper should have set MIRI_SYSROOT" ) ;
626+ cmd. arg ( "--sysroot" ) . arg ( sysroot) ;
627+ }
628+
629+ // don't go into "code generation" (i.e. validation)
630+ if info. args . iter ( ) . position ( |arg| arg. starts_with ( "--emit=" ) ) . is_none ( ) {
631+ cmd. arg ( "--emit=dep-info,metadata" ) ;
632+ }
633+
634+ cmd. args ( info. args ) ;
635+ cmd. env ( "MIRI_BE_RUSTC" , "1" ) ;
636+
637+ if verbose {
638+ eprintln ! ( "[cargo-miri rustc] captured input:\n {}" , std:: str :: from_utf8( & info. stdin) . unwrap( ) ) ;
639+ eprintln ! ( "[cargo-miri rustc] {:?}" , cmd) ;
640+ }
641+
642+ exec_with_pipe ( cmd, & info. stdin ) ;
643+ }
644+
601645 return ;
602646 }
603647
@@ -743,31 +787,40 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) {
743787 eprintln ! ( "[cargo-miri runner] {:?}" , cmd) ;
744788 }
745789
746- cmd. stdin ( std:: process:: Stdio :: piped ( ) ) ;
747- let mut child = cmd. spawn ( ) . expect ( "failed to spawn miri process" ) ;
748- {
749- let stdin = child. stdin . as_mut ( ) . expect ( "failed to open stdin" ) ;
750- stdin. write_all ( & info. stdin ) . expect ( "failed to write out test source" ) ;
751- }
752- let exit_status = child. wait ( ) . expect ( "failed to run command" ) ;
753- if exit_status. success ( ) . not ( ) {
754- std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) )
755- }
790+ exec_with_pipe ( cmd, & info. stdin )
756791}
757792
758- fn phase_cargo_rustdoc ( fst_arg : & str , args : env:: Args ) {
793+ fn phase_cargo_rustdoc ( fst_arg : & str , mut args : env:: Args ) {
759794 let verbose = std:: env:: var_os ( "MIRI_VERBOSE" ) . is_some ( ) ;
760795
761796 // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here;
762797 // just default to a straight-forward invocation for now:
763798 let mut cmd = Command :: new ( OsString :: from ( "rustdoc" ) ) ;
764799
765- // just pass everything through until we find a reason not to do that:
800+ let extern_flag = "--extern" ;
801+ assert ! ( fst_arg != extern_flag) ;
766802 cmd. arg ( fst_arg) ;
767- cmd. args ( args) ;
768803
769- cmd. arg ( "-Z" ) . arg ( "unstable-options" ) ;
804+ // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
805+ while let Some ( arg) = args. next ( ) {
806+ if arg == extern_flag {
807+ cmd. arg ( extern_flag) ; // always forward flag, but adjust filename
808+ // `--extern` is always passed as a separate argument by cargo.
809+ let next_arg = args. next ( ) . expect ( "`--extern` should be followed by a filename" ) ;
810+ if let Some ( next_lib) = next_arg. strip_suffix ( ".rlib" ) {
811+ // If this is an rlib, make it an rmeta.
812+ cmd. arg ( format ! ( "{}.rmeta" , next_lib) ) ;
813+ } else {
814+ // Some other extern file (e.g., a `.so`). Forward unchanged.
815+ cmd. arg ( next_arg) ;
816+ }
817+ } else {
818+ cmd. arg ( arg) ;
819+ }
820+ }
770821
822+ cmd. arg ( "-Z" ) . arg ( "unstable-options" ) ;
823+
771824 let cargo_miri_path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
772825 cmd. arg ( "--test-builder" ) . arg ( & cargo_miri_path) ;
773826 cmd. arg ( "--runtool" ) . arg ( & cargo_miri_path) ;
0 commit comments