@@ -407,7 +407,7 @@ pub(crate) fn run_tests(
407407 // We failed to compile all compatible tests as one so we push them into the
408408 // `standalone_tests` doctests.
409409 debug ! ( "Failed to compile compatible doctests for edition {} all at once" , edition) ;
410- for ( pos , ( doctest, scraped_test) ) in doctests. into_iter ( ) . enumerate ( ) {
410+ for ( doctest, scraped_test) in doctests {
411411 doctest. generate_unique_doctest (
412412 & scraped_test. text ,
413413 scraped_test. langstr . test_harness ,
@@ -420,7 +420,6 @@ pub(crate) fn run_tests(
420420 opts. clone ( ) ,
421421 Arc :: clone ( rustdoc_options) ,
422422 unused_extern_reports. clone ( ) ,
423- pos,
424423 ) ) ;
425424 }
426425 }
@@ -550,44 +549,33 @@ pub(crate) struct RunnableDocTest {
550549}
551550
552551impl RunnableDocTest {
553- fn path_for_merged_doctest_bundle ( & self , id : Option < usize > ) -> PathBuf {
554- let name = if let Some ( id) = id {
555- format ! ( "doctest_bundle_id_{id}.rs" )
556- } else {
557- format ! ( "doctest_bundle_{}.rs" , self . edition)
558- } ;
559- self . test_opts . outdir . path ( ) . join ( name)
552+ fn path_for_merged_doctest_bundle ( & self ) -> PathBuf {
553+ self . test_opts . outdir . path ( ) . join ( format ! ( "doctest_bundle_{}.rs" , self . edition) )
560554 }
561- fn path_for_merged_doctest_runner ( & self , id : Option < usize > ) -> PathBuf {
562- let name = if let Some ( id) = id {
563- format ! ( "doctest_runner_id_{id}.rs" )
564- } else {
565- format ! ( "doctest_runner_{}.rs" , self . edition)
566- } ;
567- self . test_opts . outdir . path ( ) . join ( name)
555+ fn path_for_merged_doctest_runner ( & self ) -> PathBuf {
556+ self . test_opts . outdir . path ( ) . join ( format ! ( "doctest_runner_{}.rs" , self . edition) )
568557 }
569558 fn is_multiple_tests ( & self ) -> bool {
570559 self . merged_test_code . is_some ( )
571560 }
572561}
573562
574563fn compile_merged_doctest_and_caller_binary (
575- mut child : process:: Child ,
564+ child : process:: Child ,
576565 doctest : & RunnableDocTest ,
577566 rustdoc_options : & RustdocOptions ,
578567 rustc_binary : & Path ,
579568 output_file : & Path ,
580569 compiler_args : Vec < String > ,
581570 test_code : & str ,
582571 instant : Instant ,
583- id : Option < usize > ,
572+ is_compile_fail : bool ,
584573) -> Result < process:: Output , ( Duration , Result < ( ) , RustdocResult > ) > {
585574 // compile-fail tests never get merged, so this should always pass
586- let status = child. wait ( ) . expect ( "Failed to wait" ) ;
587-
588- // the actual test runner is a separate component, built with nightly-only features;
589- // build it now
590- let runner_input_file = doctest. path_for_merged_doctest_runner ( id) ;
575+ let output = child. wait_with_output ( ) . expect ( "Failed to wait" ) ;
576+ if is_compile_fail && !output. status . success ( ) {
577+ return Ok ( output) ;
578+ }
591579
592580 let mut runner_compiler =
593581 wrapped_rustc_command ( & rustdoc_options. test_builder_wrappers , rustc_binary) ;
@@ -596,13 +584,10 @@ fn compile_merged_doctest_and_caller_binary(
596584 runner_compiler. env ( "RUSTC_BOOTSTRAP" , "1" ) ;
597585 runner_compiler. args ( compiler_args) ;
598586 runner_compiler. args ( [ "--crate-type=bin" , "-o" ] ) . arg ( output_file) ;
599- let mut extern_path = if let Some ( id ) = id {
600- std :: ffi :: OsString :: from ( format ! ( "--extern=doctest_bundle_id_{id}=" ) )
587+ let base_name = if is_compile_fail {
588+ format ! ( "rust_out" )
601589 } else {
602- std:: ffi:: OsString :: from ( format ! (
603- "--extern=doctest_bundle_{edition}=" ,
604- edition = doctest. edition
605- ) )
590+ format ! ( "doctest_bundle_{edition}" , edition = doctest. edition)
606591 } ;
607592
608593 // Deduplicate passed -L directory paths, since usually all dependencies will be in the
@@ -622,36 +607,58 @@ fn compile_merged_doctest_and_caller_binary(
622607 }
623608 }
624609 }
625- let filename = if let Some ( id) = id {
626- format ! ( "libdoctest_bundle_id_{id}.rlib" )
627- } else {
628- format ! ( "libdoctest_bundle_{edition}.rlib" , edition = doctest. edition)
629- } ;
630- let output_bundle_file = doctest. test_opts . outdir . path ( ) . join ( filename) ;
610+ let output_bundle_file = doctest. test_opts . outdir . path ( ) . join ( format ! ( "lib{base_name}.rlib" ) ) ;
611+ let mut extern_path = std:: ffi:: OsString :: from ( format ! ( "--extern={base_name}=" ) ) ;
631612 extern_path. push ( & output_bundle_file) ;
632- runner_compiler. arg ( extern_path) ;
633- runner_compiler. arg ( & runner_input_file) ;
634- if std:: fs:: write ( & runner_input_file, test_code) . is_err ( ) {
635- // If we cannot write this file for any reason, we leave. All combined tests will be
636- // tested as standalone tests.
637- return Err ( ( instant. elapsed ( ) , Err ( RustdocResult :: CompileError ) ) ) ;
638- }
639- if !rustdoc_options. nocapture {
640- // If `nocapture` is disabled, then we don't display rustc's output when compiling
641- // the merged doctests.
642- runner_compiler. stderr ( Stdio :: null ( ) ) ;
613+ runner_compiler. arg ( & extern_path) ;
614+
615+ if is_compile_fail {
616+ add_rustdoc_env_vars ( & mut runner_compiler, doctest) ;
617+ runner_compiler. stderr ( Stdio :: piped ( ) ) ;
618+ runner_compiler. stdin ( Stdio :: piped ( ) ) ;
619+ runner_compiler. arg ( "-" ) ;
620+ } else {
621+ // The actual test runner is a separate component, built with nightly-only features;
622+ // build it now
623+ let runner_input_file = doctest. path_for_merged_doctest_runner ( ) ;
624+ runner_compiler. arg ( & runner_input_file) ;
625+ if std:: fs:: write ( & runner_input_file, test_code) . is_err ( ) {
626+ // If we cannot write this file for any reason, we leave. All combined tests will be
627+ // tested as standalone tests.
628+ return Err ( ( instant. elapsed ( ) , Err ( RustdocResult :: CompileError ) ) ) ;
629+ }
630+ if !rustdoc_options. nocapture {
631+ // If `nocapture` is disabled, then we don't display rustc's output when compiling
632+ // the merged doctests.
633+ runner_compiler. stderr ( Stdio :: null ( ) ) ;
634+ runner_compiler. arg ( "--error-format=short" ) ;
635+ }
643636 }
644- runner_compiler. arg ( "--error-format=short" ) ;
645637 debug ! ( "compiler invocation for doctest runner: {runner_compiler:?}" ) ;
646638
647- let status = if !status. success ( ) {
648- status
639+ let output = if !output . status . success ( ) {
640+ output
649641 } else {
650642 let mut child_runner = runner_compiler. spawn ( ) . expect ( "Failed to spawn rustc process" ) ;
651- child_runner. wait ( ) . expect ( "Failed to wait" )
643+ if is_compile_fail {
644+ let stdin = child_runner. stdin . as_mut ( ) . expect ( "Failed to open stdin" ) ;
645+ stdin. write_all ( test_code. as_bytes ( ) ) . expect ( "could write out test sources" ) ;
646+ }
647+ child_runner. wait_with_output ( ) . expect ( "Failed to wait" )
652648 } ;
649+ if is_compile_fail {
650+ Ok ( output)
651+ } else {
652+ Ok ( process:: Output { status : output. status , stdout : Vec :: new ( ) , stderr : Vec :: new ( ) } )
653+ }
654+ }
653655
654- Ok ( process:: Output { status, stdout : Vec :: new ( ) , stderr : Vec :: new ( ) } )
656+ fn add_rustdoc_env_vars ( compiler : & mut Command , doctest : & RunnableDocTest ) {
657+ compiler. env ( "UNSTABLE_RUSTDOC_TEST_PATH" , & doctest. test_opts . path ) ;
658+ compiler. env (
659+ "UNSTABLE_RUSTDOC_TEST_LINE" ,
660+ format ! ( "{}" , doctest. line as isize - doctest. full_test_line_offset as isize ) ,
661+ ) ;
655662}
656663
657664/// Execute a `RunnableDoctest`.
@@ -665,7 +672,6 @@ fn run_test(
665672 rustdoc_options : & RustdocOptions ,
666673 supports_color : bool ,
667674 report_unused_externs : impl Fn ( UnusedExterns ) ,
668- doctest_id : usize ,
669675) -> ( Duration , Result < ( ) , RustdocResult > ) {
670676 let langstr = & doctest. langstr ;
671677 // Make sure we emit well-formed executable names for our target.
@@ -696,11 +702,6 @@ fn run_test(
696702 compiler_args. extend_from_slice ( & [ "-Z" . to_owned ( ) , "unstable-options" . to_owned ( ) ] ) ;
697703 }
698704
699- if doctest. no_run && !langstr. compile_fail && rustdoc_options. persist_doctests . is_none ( ) {
700- // FIXME: why does this code check if it *shouldn't* persist doctests
701- // -- shouldn't it be the negation?
702- compiler_args. push ( "--emit=metadata" . to_owned ( ) ) ;
703- }
704705 compiler_args. extend_from_slice ( & [
705706 "--target" . to_owned ( ) ,
706707 match & rustdoc_options. target {
@@ -746,40 +747,47 @@ fn run_test(
746747
747748 compiler. args ( & compiler_args) ;
748749
749- compiler. env ( "UNSTABLE_RUSTDOC_TEST_PATH" , & doctest. test_opts . path ) ;
750- compiler. env (
751- "UNSTABLE_RUSTDOC_TEST_LINE" ,
752- format ! ( "{}" , doctest. line as isize - doctest. full_test_line_offset as isize ) ,
753- ) ;
750+ let is_should_panic = !langstr. compile_fail && langstr. should_panic ;
754751 // If this is a merged doctest, we need to write it into a file instead of using stdin
755752 // because if the size of the merged doctests is too big, it'll simply break stdin.
756- if doctest. is_multiple_tests ( ) || ( !langstr. compile_fail && langstr. should_panic ) {
757- // It makes the compilation failure much faster if it is for a combined doctest.
758- compiler. arg ( "--error-format=short" ) ;
759- let input_file = doctest. path_for_merged_doctest_bundle (
760- if !langstr. compile_fail && langstr. should_panic { Some ( doctest_id) } else { None } ,
761- ) ;
762- if std:: fs:: write ( & input_file, & doctest. full_test_code ) . is_err ( ) {
763- // If we cannot write this file for any reason, we leave. All combined tests will be
764- // tested as standalone tests.
765- return ( Duration :: default ( ) , Err ( RustdocResult :: CompileError ) ) ;
766- }
767- if !rustdoc_options. nocapture {
768- // If `nocapture` is disabled, then we don't display rustc's output when compiling
769- // the merged doctests.
770- compiler. stderr ( Stdio :: null ( ) ) ;
771- }
753+ if doctest. is_multiple_tests ( ) || is_should_panic {
772754 // bundled tests are an rlib, loaded by a separate runner executable
773- compiler
774- . arg ( "--crate-type=lib" )
775- . arg ( "--out-dir" )
776- . arg ( doctest. test_opts . outdir . path ( ) )
777- . arg ( input_file) ;
755+ compiler. arg ( "--crate-type=lib" ) . arg ( "--out-dir" ) . arg ( doctest. test_opts . outdir . path ( ) ) ;
756+
757+ if !is_should_panic {
758+ compiler. arg ( "--error-format=short" ) ;
759+ if !rustdoc_options. nocapture {
760+ // If `nocapture` is disabled, then we don't display rustc's output when compiling
761+ // the merged doctests.
762+ compiler. stderr ( Stdio :: null ( ) ) ;
763+ compiler. stdout ( Stdio :: null ( ) ) ;
764+ }
765+ // It makes the compilation failure much faster if it is for a combined doctest.
766+ let input_file = doctest. path_for_merged_doctest_bundle ( ) ;
767+ if std:: fs:: write ( & input_file, & doctest. full_test_code ) . is_err ( ) {
768+ // If we cannot write this file for any reason, we leave. All combined tests will be
769+ // tested as standalone tests.
770+ return ( Duration :: default ( ) , Err ( RustdocResult :: CompileError ) ) ;
771+ }
772+ compiler. arg ( input_file) ;
773+ } else {
774+ compiler. stdin ( Stdio :: piped ( ) ) ;
775+ compiler. stderr ( Stdio :: piped ( ) ) ;
776+ add_rustdoc_env_vars ( & mut compiler, & doctest) ;
777+ compiler. arg ( "-" ) ;
778+ }
778779 } else {
780+ add_rustdoc_env_vars ( & mut compiler, & doctest) ;
779781 compiler. arg ( "--crate-type=bin" ) . arg ( "-o" ) . arg ( & output_file) ;
780782 compiler. arg ( "-" ) ;
781783 compiler. stdin ( Stdio :: piped ( ) ) ;
782784 compiler. stderr ( Stdio :: piped ( ) ) ;
785+
786+ if doctest. no_run && !langstr. compile_fail && rustdoc_options. persist_doctests . is_none ( ) {
787+ // FIXME: why does this code check if it *shouldn't* persist doctests
788+ // -- shouldn't it be the negation?
789+ compiler_args. push ( "--emit=metadata" . to_owned ( ) ) ;
790+ }
783791 }
784792
785793 debug ! ( "compiler invocation for doctest: {compiler:?}" ) ;
@@ -795,45 +803,48 @@ fn run_test(
795803 compiler_args,
796804 merged_test_code,
797805 instant,
798- None ,
806+ false ,
799807 ) {
800808 Ok ( out) => out,
801809 Err ( err) => return err,
802810 }
803- } else if !langstr. compile_fail && langstr. should_panic {
804- match compile_merged_doctest_and_caller_binary (
805- child,
806- & doctest,
807- rustdoc_options,
808- rustc_binary,
809- & output_file,
810- compiler_args,
811- & format ! (
812- "\
811+ } else {
812+ let stdin = child. stdin . as_mut ( ) . expect ( "Failed to open stdin" ) ;
813+ stdin. write_all ( doctest. full_test_code . as_bytes ( ) ) . expect ( "could write out test sources" ) ;
814+
815+ if !langstr. compile_fail && langstr. should_panic {
816+ match compile_merged_doctest_and_caller_binary (
817+ child,
818+ & doctest,
819+ rustdoc_options,
820+ rustc_binary,
821+ & output_file,
822+ compiler_args,
823+ & format ! (
824+ "\
813825 #![feature(test)]
814826extern crate test;
815827
816- use std::process::{{ExitCode, Termination}};
828+ use std::process::{{ExitCode, Termination, exit }};
817829
818830fn main() -> ExitCode {{
819831 if test::cannot_handle_should_panic() {{
820- ExitCode::SUCCESS
832+ exit(test::ERROR_EXIT_CODE);
821833 }} else {{
822- extern crate doctest_bundle_id_{doctest_id} as doctest_bundle;
834+ extern crate rust_out as doctest_bundle;
823835 doctest_bundle::main().report()
824836 }}
825- }}"
826- ) ,
827- instant,
828- Some ( doctest_id) ,
829- ) {
830- Ok ( out) => out,
831- Err ( err) => return err,
837+ }}" ,
838+ ) ,
839+ instant,
840+ true ,
841+ ) {
842+ Ok ( out) => out,
843+ Err ( err) => return err,
844+ }
845+ } else {
846+ child. wait_with_output ( ) . expect ( "Failed to read stdout" )
832847 }
833- } else {
834- let stdin = child. stdin . as_mut ( ) . expect ( "Failed to open stdin" ) ;
835- stdin. write_all ( doctest. full_test_code . as_bytes ( ) ) . expect ( "could write out test sources" ) ;
836- child. wait_with_output ( ) . expect ( "Failed to read stdout" )
837848 } ;
838849
839850 struct Bomb < ' a > ( & ' a str ) ;
@@ -1142,7 +1153,6 @@ impl CreateRunnableDocTests {
11421153 self . opts . clone ( ) ,
11431154 Arc :: clone ( & self . rustdoc_options ) ,
11441155 self . unused_extern_reports . clone ( ) ,
1145- self . standalone_tests . len ( ) ,
11461156 )
11471157 }
11481158}
@@ -1153,7 +1163,6 @@ fn generate_test_desc_and_fn(
11531163 opts : GlobalTestOptions ,
11541164 rustdoc_options : Arc < RustdocOptions > ,
11551165 unused_externs : Arc < Mutex < Vec < UnusedExterns > > > ,
1156- doctest_id : usize ,
11571166) -> test:: TestDescAndFn {
11581167 let target_str = rustdoc_options. target . to_string ( ) ;
11591168 let rustdoc_test_options =
@@ -1188,7 +1197,6 @@ fn generate_test_desc_and_fn(
11881197 scraped_test,
11891198 rustdoc_options,
11901199 unused_externs,
1191- doctest_id,
11921200 )
11931201 } ) ) ,
11941202 }
@@ -1201,7 +1209,6 @@ fn doctest_run_fn(
12011209 scraped_test : ScrapedDocTest ,
12021210 rustdoc_options : Arc < RustdocOptions > ,
12031211 unused_externs : Arc < Mutex < Vec < UnusedExterns > > > ,
1204- doctest_id : usize ,
12051212) -> Result < ( ) , String > {
12061213 #[ cfg( not( bootstrap) ) ]
12071214 if scraped_test. langstr . should_panic && test:: cannot_handle_should_panic ( ) {
@@ -1227,13 +1234,8 @@ fn doctest_run_fn(
12271234 no_run : scraped_test. no_run ( & rustdoc_options) ,
12281235 merged_test_code : None ,
12291236 } ;
1230- let ( _, res) = run_test (
1231- runnable_test,
1232- & rustdoc_options,
1233- doctest. supports_color ,
1234- report_unused_externs,
1235- doctest_id,
1236- ) ;
1237+ let ( _, res) =
1238+ run_test ( runnable_test, & rustdoc_options, doctest. supports_color , report_unused_externs) ;
12371239
12381240 if let Err ( err) = res {
12391241 eprint ! ( "{err}" ) ;
0 commit comments