@@ -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
@@ -748,31 +792,40 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) {
748792 eprintln ! ( "[cargo-miri runner] {:?}" , cmd) ;
749793 }
750794
751- cmd. stdin ( std:: process:: Stdio :: piped ( ) ) ;
752- let mut child = cmd. spawn ( ) . expect ( "failed to spawn miri process" ) ;
753- {
754- let stdin = child. stdin . as_mut ( ) . expect ( "failed to open stdin" ) ;
755- stdin. write_all ( & info. stdin ) . expect ( "failed to write out test source" ) ;
756- }
757- let exit_status = child. wait ( ) . expect ( "failed to run command" ) ;
758- if exit_status. success ( ) . not ( ) {
759- std:: process:: exit ( exit_status. code ( ) . unwrap_or ( -1 ) )
760- }
795+ exec_with_pipe ( cmd, & info. stdin )
761796}
762797
763- fn phase_cargo_rustdoc ( fst_arg : & str , args : env:: Args ) {
798+ fn phase_cargo_rustdoc ( fst_arg : & str , mut args : env:: Args ) {
764799 let verbose = std:: env:: var_os ( "MIRI_VERBOSE" ) . is_some ( ) ;
765800
766801 // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here;
767802 // just default to a straight-forward invocation for now:
768803 let mut cmd = Command :: new ( OsString :: from ( "rustdoc" ) ) ;
769804
770- // just pass everything through until we find a reason not to do that:
805+ let extern_flag = "--extern" ;
806+ assert ! ( fst_arg != extern_flag) ;
771807 cmd. arg ( fst_arg) ;
772- cmd. args ( args) ;
773808
774- cmd. arg ( "-Z" ) . arg ( "unstable-options" ) ;
809+ // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files.
810+ while let Some ( arg) = args. next ( ) {
811+ if arg == extern_flag {
812+ cmd. arg ( extern_flag) ; // always forward flag, but adjust filename
813+ // `--extern` is always passed as a separate argument by cargo.
814+ let next_arg = args. next ( ) . expect ( "`--extern` should be followed by a filename" ) ;
815+ if let Some ( next_lib) = next_arg. strip_suffix ( ".rlib" ) {
816+ // If this is an rlib, make it an rmeta.
817+ cmd. arg ( format ! ( "{}.rmeta" , next_lib) ) ;
818+ } else {
819+ // Some other extern file (e.g., a `.so`). Forward unchanged.
820+ cmd. arg ( next_arg) ;
821+ }
822+ } else {
823+ cmd. arg ( arg) ;
824+ }
825+ }
775826
827+ cmd. arg ( "-Z" ) . arg ( "unstable-options" ) ;
828+
776829 let cargo_miri_path = std:: env:: current_exe ( ) . expect ( "current executable path invalid" ) ;
777830 cmd. arg ( "--test-builder" ) . arg ( & cargo_miri_path) ;
778831 cmd. arg ( "--runtool" ) . arg ( & cargo_miri_path) ;
0 commit comments