@@ -406,7 +406,7 @@ pub(crate) fn run_tests(
406406 // We failed to compile all compatible tests as one so we push them into the
407407 // `standalone_tests` doctests.
408408 debug ! ( "Failed to compile compatible doctests for edition {} all at once" , edition) ;
409- for ( pos , ( doctest, scraped_test) ) in doctests. into_iter ( ) . enumerate ( ) {
409+ for ( doctest, scraped_test) in doctests {
410410 doctest. generate_unique_doctest (
411411 & scraped_test. text ,
412412 scraped_test. langstr . test_harness ,
@@ -419,7 +419,6 @@ pub(crate) fn run_tests(
419419 opts. clone ( ) ,
420420 Arc :: clone ( rustdoc_options) ,
421421 unused_extern_reports. clone ( ) ,
422- pos,
423422 ) ) ;
424423 }
425424 }
@@ -549,44 +548,33 @@ pub(crate) struct RunnableDocTest {
549548}
550549
551550impl RunnableDocTest {
552- fn path_for_merged_doctest_bundle ( & self , id : Option < usize > ) -> PathBuf {
553- let name = if let Some ( id) = id {
554- format ! ( "doctest_bundle_id_{id}.rs" )
555- } else {
556- format ! ( "doctest_bundle_{}.rs" , self . edition)
557- } ;
558- self . test_opts . outdir . path ( ) . join ( name)
551+ fn path_for_merged_doctest_bundle ( & self ) -> PathBuf {
552+ self . test_opts . outdir . path ( ) . join ( format ! ( "doctest_bundle_{}.rs" , self . edition) )
559553 }
560- fn path_for_merged_doctest_runner ( & self , id : Option < usize > ) -> PathBuf {
561- let name = if let Some ( id) = id {
562- format ! ( "doctest_runner_id_{id}.rs" )
563- } else {
564- format ! ( "doctest_runner_{}.rs" , self . edition)
565- } ;
566- self . test_opts . outdir . path ( ) . join ( name)
554+ fn path_for_merged_doctest_runner ( & self ) -> PathBuf {
555+ self . test_opts . outdir . path ( ) . join ( format ! ( "doctest_runner_{}.rs" , self . edition) )
567556 }
568557 fn is_multiple_tests ( & self ) -> bool {
569558 self . merged_test_code . is_some ( )
570559 }
571560}
572561
573562fn compile_merged_doctest_and_caller_binary (
574- mut child : process:: Child ,
563+ child : process:: Child ,
575564 doctest : & RunnableDocTest ,
576565 rustdoc_options : & RustdocOptions ,
577566 rustc_binary : & Path ,
578567 output_file : & Path ,
579568 compiler_args : Vec < String > ,
580569 test_code : & str ,
581570 instant : Instant ,
582- id : Option < usize > ,
571+ is_compile_fail : bool ,
583572) -> Result < process:: Output , ( Duration , Result < ( ) , RustdocResult > ) > {
584573 // compile-fail tests never get merged, so this should always pass
585- let status = child. wait ( ) . expect ( "Failed to wait" ) ;
586-
587- // the actual test runner is a separate component, built with nightly-only features;
588- // build it now
589- let runner_input_file = doctest. path_for_merged_doctest_runner ( id) ;
574+ let output = child. wait_with_output ( ) . expect ( "Failed to wait" ) ;
575+ if is_compile_fail && !output. status . success ( ) {
576+ return Ok ( output) ;
577+ }
590578
591579 let mut runner_compiler =
592580 wrapped_rustc_command ( & rustdoc_options. test_builder_wrappers , rustc_binary) ;
@@ -595,13 +583,10 @@ fn compile_merged_doctest_and_caller_binary(
595583 runner_compiler. env ( "RUSTC_BOOTSTRAP" , "1" ) ;
596584 runner_compiler. args ( compiler_args) ;
597585 runner_compiler. args ( [ "--crate-type=bin" , "-o" ] ) . arg ( output_file) ;
598- let mut extern_path = if let Some ( id ) = id {
599- std :: ffi :: OsString :: from ( format ! ( "--extern=doctest_bundle_id_{id}=" ) )
586+ let base_name = if is_compile_fail {
587+ format ! ( "rust_out" )
600588 } else {
601- std:: ffi:: OsString :: from ( format ! (
602- "--extern=doctest_bundle_{edition}=" ,
603- edition = doctest. edition
604- ) )
589+ format ! ( "doctest_bundle_{edition}" , edition = doctest. edition)
605590 } ;
606591
607592 // Deduplicate passed -L directory paths, since usually all dependencies will be in the
@@ -621,36 +606,58 @@ fn compile_merged_doctest_and_caller_binary(
621606 }
622607 }
623608 }
624- let filename = if let Some ( id) = id {
625- format ! ( "libdoctest_bundle_id_{id}.rlib" )
626- } else {
627- format ! ( "libdoctest_bundle_{edition}.rlib" , edition = doctest. edition)
628- } ;
629- let output_bundle_file = doctest. test_opts . outdir . path ( ) . join ( filename) ;
609+ let output_bundle_file = doctest. test_opts . outdir . path ( ) . join ( format ! ( "lib{base_name}.rlib" ) ) ;
610+ let mut extern_path = std:: ffi:: OsString :: from ( format ! ( "--extern={base_name}=" ) ) ;
630611 extern_path. push ( & output_bundle_file) ;
631- runner_compiler. arg ( extern_path) ;
632- runner_compiler. arg ( & runner_input_file) ;
633- if std:: fs:: write ( & runner_input_file, test_code) . is_err ( ) {
634- // If we cannot write this file for any reason, we leave. All combined tests will be
635- // tested as standalone tests.
636- return Err ( ( instant. elapsed ( ) , Err ( RustdocResult :: CompileError ) ) ) ;
637- }
638- if !rustdoc_options. no_capture {
639- // If `no_capture` is disabled, then we don't display rustc's output when compiling
640- // the merged doctests.
641- runner_compiler. stderr ( Stdio :: null ( ) ) ;
612+ runner_compiler. arg ( & extern_path) ;
613+
614+ if is_compile_fail {
615+ add_rustdoc_env_vars ( & mut runner_compiler, doctest) ;
616+ runner_compiler. stderr ( Stdio :: piped ( ) ) ;
617+ runner_compiler. stdin ( Stdio :: piped ( ) ) ;
618+ runner_compiler. arg ( "-" ) ;
619+ } else {
620+ // The actual test runner is a separate component, built with nightly-only features;
621+ // build it now
622+ let runner_input_file = doctest. path_for_merged_doctest_runner ( ) ;
623+ runner_compiler. arg ( & runner_input_file) ;
624+ if std:: fs:: write ( & runner_input_file, test_code) . is_err ( ) {
625+ // If we cannot write this file for any reason, we leave. All combined tests will be
626+ // tested as standalone tests.
627+ return Err ( ( instant. elapsed ( ) , Err ( RustdocResult :: CompileError ) ) ) ;
628+ }
629+ if !rustdoc_options. no_capture {
630+ // If `no_capture` is disabled, then we don't display rustc's output when compiling
631+ // the merged doctests.
632+ runner_compiler. stderr ( Stdio :: null ( ) ) ;
633+ runner_compiler. arg ( "--error-format=short" ) ;
634+ }
642635 }
643- runner_compiler. arg ( "--error-format=short" ) ;
644636 debug ! ( "compiler invocation for doctest runner: {runner_compiler:?}" ) ;
645637
646- let status = if !status. success ( ) {
647- status
638+ let output = if !output . status . success ( ) {
639+ output
648640 } else {
649641 let mut child_runner = runner_compiler. spawn ( ) . expect ( "Failed to spawn rustc process" ) ;
650- child_runner. wait ( ) . expect ( "Failed to wait" )
642+ if is_compile_fail {
643+ let stdin = child_runner. stdin . as_mut ( ) . expect ( "Failed to open stdin" ) ;
644+ stdin. write_all ( test_code. as_bytes ( ) ) . expect ( "could write out test sources" ) ;
645+ }
646+ child_runner. wait_with_output ( ) . expect ( "Failed to wait" )
651647 } ;
648+ if is_compile_fail {
649+ Ok ( output)
650+ } else {
651+ Ok ( process:: Output { status : output. status , stdout : Vec :: new ( ) , stderr : Vec :: new ( ) } )
652+ }
653+ }
652654
653- Ok ( process:: Output { status, stdout : Vec :: new ( ) , stderr : Vec :: new ( ) } )
655+ fn add_rustdoc_env_vars ( compiler : & mut Command , doctest : & RunnableDocTest ) {
656+ compiler. env ( "UNSTABLE_RUSTDOC_TEST_PATH" , & doctest. test_opts . path ) ;
657+ compiler. env (
658+ "UNSTABLE_RUSTDOC_TEST_LINE" ,
659+ format ! ( "{}" , doctest. line as isize - doctest. full_test_line_offset as isize ) ,
660+ ) ;
654661}
655662
656663/// Execute a `RunnableDoctest`.
@@ -664,7 +671,6 @@ fn run_test(
664671 rustdoc_options : & RustdocOptions ,
665672 supports_color : bool ,
666673 report_unused_externs : impl Fn ( UnusedExterns ) ,
667- doctest_id : usize ,
668674) -> ( Duration , Result < ( ) , RustdocResult > ) {
669675 let langstr = & doctest. langstr ;
670676 // Make sure we emit well-formed executable names for our target.
@@ -695,11 +701,6 @@ fn run_test(
695701 compiler_args. extend_from_slice ( & [ "-Z" . to_owned ( ) , "unstable-options" . to_owned ( ) ] ) ;
696702 }
697703
698- if doctest. no_run && !langstr. compile_fail && rustdoc_options. persist_doctests . is_none ( ) {
699- // FIXME: why does this code check if it *shouldn't* persist doctests
700- // -- shouldn't it be the negation?
701- compiler_args. push ( "--emit=metadata" . to_owned ( ) ) ;
702- }
703704 compiler_args. extend_from_slice ( & [
704705 "--target" . to_owned ( ) ,
705706 match & rustdoc_options. target {
@@ -745,40 +746,47 @@ fn run_test(
745746
746747 compiler. args ( & compiler_args) ;
747748
748- compiler. env ( "UNSTABLE_RUSTDOC_TEST_PATH" , & doctest. test_opts . path ) ;
749- compiler. env (
750- "UNSTABLE_RUSTDOC_TEST_LINE" ,
751- format ! ( "{}" , doctest. line as isize - doctest. full_test_line_offset as isize ) ,
752- ) ;
749+ let is_should_panic = !langstr. compile_fail && langstr. should_panic ;
753750 // If this is a merged doctest, we need to write it into a file instead of using stdin
754751 // because if the size of the merged doctests is too big, it'll simply break stdin.
755- if doctest. is_multiple_tests ( ) || ( !langstr. compile_fail && langstr. should_panic ) {
756- // It makes the compilation failure much faster if it is for a combined doctest.
757- compiler. arg ( "--error-format=short" ) ;
758- let input_file = doctest. path_for_merged_doctest_bundle (
759- if !langstr. compile_fail && langstr. should_panic { Some ( doctest_id) } else { None } ,
760- ) ;
761- if std:: fs:: write ( & input_file, & doctest. full_test_code ) . is_err ( ) {
762- // If we cannot write this file for any reason, we leave. All combined tests will be
763- // tested as standalone tests.
764- return ( Duration :: default ( ) , Err ( RustdocResult :: CompileError ) ) ;
765- }
766- if !rustdoc_options. no_capture {
767- // If `no_capture` is disabled, then we don't display rustc's output when compiling
768- // the merged doctests.
769- compiler. stderr ( Stdio :: null ( ) ) ;
770- }
752+ if doctest. is_multiple_tests ( ) || is_should_panic {
771753 // bundled tests are an rlib, loaded by a separate runner executable
772- compiler
773- . arg ( "--crate-type=lib" )
774- . arg ( "--out-dir" )
775- . arg ( doctest. test_opts . outdir . path ( ) )
776- . arg ( input_file) ;
754+ compiler. arg ( "--crate-type=lib" ) . arg ( "--out-dir" ) . arg ( doctest. test_opts . outdir . path ( ) ) ;
755+
756+ if !is_should_panic {
757+ compiler. arg ( "--error-format=short" ) ;
758+ if !rustdoc_options. no_capture {
759+ // If `no_capture` is disabled, then we don't display rustc's output when compiling
760+ // the merged doctests.
761+ compiler. stderr ( Stdio :: null ( ) ) ;
762+ compiler. stdout ( Stdio :: null ( ) ) ;
763+ }
764+ // It makes the compilation failure much faster if it is for a combined doctest.
765+ let input_file = doctest. path_for_merged_doctest_bundle ( ) ;
766+ if std:: fs:: write ( & input_file, & doctest. full_test_code ) . is_err ( ) {
767+ // If we cannot write this file for any reason, we leave. All combined tests will be
768+ // tested as standalone tests.
769+ return ( Duration :: default ( ) , Err ( RustdocResult :: CompileError ) ) ;
770+ }
771+ compiler. arg ( input_file) ;
772+ } else {
773+ compiler. stdin ( Stdio :: piped ( ) ) ;
774+ compiler. stderr ( Stdio :: piped ( ) ) ;
775+ add_rustdoc_env_vars ( & mut compiler, & doctest) ;
776+ compiler. arg ( "-" ) ;
777+ }
777778 } else {
779+ add_rustdoc_env_vars ( & mut compiler, & doctest) ;
778780 compiler. arg ( "--crate-type=bin" ) . arg ( "-o" ) . arg ( & output_file) ;
779781 compiler. arg ( "-" ) ;
780782 compiler. stdin ( Stdio :: piped ( ) ) ;
781783 compiler. stderr ( Stdio :: piped ( ) ) ;
784+
785+ if doctest. no_run && !langstr. compile_fail && rustdoc_options. persist_doctests . is_none ( ) {
786+ // FIXME: why does this code check if it *shouldn't* persist doctests
787+ // -- shouldn't it be the negation?
788+ compiler_args. push ( "--emit=metadata" . to_owned ( ) ) ;
789+ }
782790 }
783791
784792 debug ! ( "compiler invocation for doctest: {compiler:?}" ) ;
@@ -794,45 +802,48 @@ fn run_test(
794802 compiler_args,
795803 merged_test_code,
796804 instant,
797- None ,
805+ false ,
798806 ) {
799807 Ok ( out) => out,
800808 Err ( err) => return err,
801809 }
802- } else if !langstr. compile_fail && langstr. should_panic {
803- match compile_merged_doctest_and_caller_binary (
804- child,
805- & doctest,
806- rustdoc_options,
807- rustc_binary,
808- & output_file,
809- compiler_args,
810- & format ! (
811- "\
810+ } else {
811+ let stdin = child. stdin . as_mut ( ) . expect ( "Failed to open stdin" ) ;
812+ stdin. write_all ( doctest. full_test_code . as_bytes ( ) ) . expect ( "could write out test sources" ) ;
813+
814+ if !langstr. compile_fail && langstr. should_panic {
815+ match compile_merged_doctest_and_caller_binary (
816+ child,
817+ & doctest,
818+ rustdoc_options,
819+ rustc_binary,
820+ & output_file,
821+ compiler_args,
822+ & format ! (
823+ "\
812824 #![feature(test)]
813825extern crate test;
814826
815- use std::process::{{ExitCode, Termination}};
827+ use std::process::{{ExitCode, Termination, exit }};
816828
817829fn main() -> ExitCode {{
818830 if test::cannot_handle_should_panic() {{
819- ExitCode::SUCCESS
831+ exit(test::ERROR_EXIT_CODE);
820832 }} else {{
821- extern crate doctest_bundle_id_{doctest_id} as doctest_bundle;
833+ extern crate rust_out as doctest_bundle;
822834 doctest_bundle::main().report()
823835 }}
824- }}"
825- ) ,
826- instant,
827- Some ( doctest_id) ,
828- ) {
829- Ok ( out) => out,
830- Err ( err) => return err,
836+ }}" ,
837+ ) ,
838+ instant,
839+ true ,
840+ ) {
841+ Ok ( out) => out,
842+ Err ( err) => return err,
843+ }
844+ } else {
845+ child. wait_with_output ( ) . expect ( "Failed to read stdout" )
831846 }
832- } else {
833- let stdin = child. stdin . as_mut ( ) . expect ( "Failed to open stdin" ) ;
834- stdin. write_all ( doctest. full_test_code . as_bytes ( ) ) . expect ( "could write out test sources" ) ;
835- child. wait_with_output ( ) . expect ( "Failed to read stdout" )
836847 } ;
837848
838849 struct Bomb < ' a > ( & ' a str ) ;
@@ -1138,7 +1149,6 @@ impl CreateRunnableDocTests {
11381149 self . opts . clone ( ) ,
11391150 Arc :: clone ( & self . rustdoc_options ) ,
11401151 self . unused_extern_reports . clone ( ) ,
1141- self . standalone_tests . len ( ) ,
11421152 )
11431153 }
11441154}
@@ -1149,7 +1159,6 @@ fn generate_test_desc_and_fn(
11491159 opts : GlobalTestOptions ,
11501160 rustdoc_options : Arc < RustdocOptions > ,
11511161 unused_externs : Arc < Mutex < Vec < UnusedExterns > > > ,
1152- doctest_id : usize ,
11531162) -> test:: TestDescAndFn {
11541163 let target_str = rustdoc_options. target . to_string ( ) ;
11551164 let rustdoc_test_options =
@@ -1184,7 +1193,6 @@ fn generate_test_desc_and_fn(
11841193 scraped_test,
11851194 rustdoc_options,
11861195 unused_externs,
1187- doctest_id,
11881196 )
11891197 } ) ) ,
11901198 }
@@ -1197,7 +1205,6 @@ fn doctest_run_fn(
11971205 scraped_test : ScrapedDocTest ,
11981206 rustdoc_options : Arc < RustdocOptions > ,
11991207 unused_externs : Arc < Mutex < Vec < UnusedExterns > > > ,
1200- doctest_id : usize ,
12011208) -> Result < ( ) , String > {
12021209 #[ cfg( not( bootstrap) ) ]
12031210 if scraped_test. langstr . should_panic && test:: cannot_handle_should_panic ( ) {
@@ -1223,13 +1230,8 @@ fn doctest_run_fn(
12231230 no_run : scraped_test. no_run ( & rustdoc_options) ,
12241231 merged_test_code : None ,
12251232 } ;
1226- let ( _, res) = run_test (
1227- runnable_test,
1228- & rustdoc_options,
1229- doctest. supports_color ,
1230- report_unused_externs,
1231- doctest_id,
1232- ) ;
1233+ let ( _, res) =
1234+ run_test ( runnable_test, & rustdoc_options, doctest. supports_color , report_unused_externs) ;
12331235
12341236 if let Err ( err) = res {
12351237 eprint ! ( "{err}" ) ;
0 commit comments