@@ -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 ( doctest, scraped_test) in doctests {
409+ for ( pos , ( doctest, scraped_test) ) in doctests. into_iter ( ) . enumerate ( ) {
410410 doctest. generate_unique_doctest (
411411 & scraped_test. text ,
412412 scraped_test. langstr . test_harness ,
@@ -419,6 +419,7 @@ pub(crate) fn run_tests(
419419 opts. clone ( ) ,
420420 Arc :: clone ( rustdoc_options) ,
421421 unused_extern_reports. clone ( ) ,
422+ pos,
422423 ) ) ;
423424 }
424425 }
@@ -548,11 +549,21 @@ pub(crate) struct RunnableDocTest {
548549}
549550
550551impl RunnableDocTest {
551- fn path_for_merged_doctest_bundle ( & self ) -> PathBuf {
552- self . test_opts . outdir . path ( ) . join ( format ! ( "doctest_bundle_{}.rs" , self . edition) )
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)
553559 }
554- fn path_for_merged_doctest_runner ( & self ) -> PathBuf {
555- self . test_opts . outdir . path ( ) . join ( format ! ( "doctest_runner_{}.rs" , self . edition) )
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)
556567 }
557568 fn is_multiple_tests ( & self ) -> bool {
558569 self . merged_test_code . is_some ( )
@@ -568,13 +579,14 @@ fn compile_merged_doctest_and_caller_binary(
568579 compiler_args : Vec < String > ,
569580 test_code : & str ,
570581 instant : Instant ,
582+ id : Option < usize > ,
571583) -> Result < process:: Output , ( Duration , Result < ( ) , RustdocResult > ) > {
572584 // compile-fail tests never get merged, so this should always pass
573585 let status = child. wait ( ) . expect ( "Failed to wait" ) ;
574586
575587 // the actual test runner is a separate component, built with nightly-only features;
576588 // build it now
577- let runner_input_file = doctest. path_for_merged_doctest_runner ( ) ;
589+ let runner_input_file = doctest. path_for_merged_doctest_runner ( id ) ;
578590
579591 let mut runner_compiler =
580592 wrapped_rustc_command ( & rustdoc_options. test_builder_wrappers , rustc_binary) ;
@@ -583,10 +595,14 @@ fn compile_merged_doctest_and_caller_binary(
583595 runner_compiler. env ( "RUSTC_BOOTSTRAP" , "1" ) ;
584596 runner_compiler. args ( compiler_args) ;
585597 runner_compiler. args ( [ "--crate-type=bin" , "-o" ] ) . arg ( output_file) ;
586- let mut extern_path = std:: ffi:: OsString :: from ( format ! (
587- "--extern=doctest_bundle_{edition}=" ,
588- edition = doctest. edition
589- ) ) ;
598+ let mut extern_path = if let Some ( id) = id {
599+ std:: ffi:: OsString :: from ( format ! ( "--extern=doctest_bundle_id_{id}=" ) )
600+ } else {
601+ std:: ffi:: OsString :: from ( format ! (
602+ "--extern=doctest_bundle_{edition}=" ,
603+ edition = doctest. edition
604+ ) )
605+ } ;
590606
591607 // Deduplicate passed -L directory paths, since usually all dependencies will be in the
592608 // same directory (e.g. target/debug/deps from Cargo).
@@ -605,11 +621,12 @@ fn compile_merged_doctest_and_caller_binary(
605621 }
606622 }
607623 }
608- let output_bundle_file = doctest
609- . test_opts
610- . outdir
611- . path ( )
612- . join ( format ! ( "libdoctest_bundle_{edition}.rlib" , edition = doctest. edition) ) ;
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) ;
613630 extern_path. push ( & output_bundle_file) ;
614631 runner_compiler. arg ( extern_path) ;
615632 runner_compiler. arg ( & runner_input_file) ;
@@ -647,6 +664,7 @@ fn run_test(
647664 rustdoc_options : & RustdocOptions ,
648665 supports_color : bool ,
649666 report_unused_externs : impl Fn ( UnusedExterns ) ,
667+ doctest_id : usize ,
650668) -> ( Duration , Result < ( ) , RustdocResult > ) {
651669 let langstr = & doctest. langstr ;
652670 // Make sure we emit well-formed executable names for our target.
@@ -727,12 +745,19 @@ fn run_test(
727745
728746 compiler. args ( & compiler_args) ;
729747
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+ ) ;
730753 // If this is a merged doctest, we need to write it into a file instead of using stdin
731754 // because if the size of the merged doctests is too big, it'll simply break stdin.
732- if doctest. is_multiple_tests ( ) {
755+ if doctest. is_multiple_tests ( ) || ( !langstr . compile_fail && langstr . should_panic ) {
733756 // It makes the compilation failure much faster if it is for a combined doctest.
734757 compiler. arg ( "--error-format=short" ) ;
735- let input_file = doctest. path_for_merged_doctest_bundle ( ) ;
758+ let input_file = doctest. path_for_merged_doctest_bundle (
759+ if !langstr. compile_fail && langstr. should_panic { Some ( doctest_id) } else { None } ,
760+ ) ;
736761 if std:: fs:: write ( & input_file, & doctest. full_test_code ) . is_err ( ) {
737762 // If we cannot write this file for any reason, we leave. All combined tests will be
738763 // tested as standalone tests.
@@ -751,11 +776,6 @@ fn run_test(
751776 . arg ( input_file) ;
752777 } else {
753778 compiler. arg ( "--crate-type=bin" ) . arg ( "-o" ) . arg ( & output_file) ;
754- compiler. env ( "UNSTABLE_RUSTDOC_TEST_PATH" , & doctest. test_opts . path ) ;
755- compiler. env (
756- "UNSTABLE_RUSTDOC_TEST_LINE" ,
757- format ! ( "{}" , doctest. line as isize - doctest. full_test_line_offset as isize ) ,
758- ) ;
759779 compiler. arg ( "-" ) ;
760780 compiler. stdin ( Stdio :: piped ( ) ) ;
761781 compiler. stderr ( Stdio :: piped ( ) ) ;
@@ -774,6 +794,37 @@ fn run_test(
774794 compiler_args,
775795 merged_test_code,
776796 instant,
797+ None ,
798+ ) {
799+ Ok ( out) => out,
800+ Err ( err) => return err,
801+ }
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+ "\
812+ #![feature(test)]
813+ extern crate test;
814+
815+ use std::process::{{ExitCode, Termination}};
816+
817+ fn main() -> ExitCode {{
818+ if test::cannot_handle_should_panic() {{
819+ ExitCode::SUCCESS
820+ }} else {{
821+ extern crate doctest_bundle_id_{doctest_id} as doctest_bundle;
822+ doctest_bundle::main().report()
823+ }}
824+ }}"
825+ ) ,
826+ instant,
827+ Some ( doctest_id) ,
777828 ) {
778829 Ok ( out) => out,
779830 Err ( err) => return err,
@@ -1087,6 +1138,7 @@ impl CreateRunnableDocTests {
10871138 self . opts . clone ( ) ,
10881139 Arc :: clone ( & self . rustdoc_options ) ,
10891140 self . unused_extern_reports . clone ( ) ,
1141+ self . standalone_tests . len ( ) ,
10901142 )
10911143 }
10921144}
@@ -1097,6 +1149,7 @@ fn generate_test_desc_and_fn(
10971149 opts : GlobalTestOptions ,
10981150 rustdoc_options : Arc < RustdocOptions > ,
10991151 unused_externs : Arc < Mutex < Vec < UnusedExterns > > > ,
1152+ doctest_id : usize ,
11001153) -> test:: TestDescAndFn {
11011154 let target_str = rustdoc_options. target . to_string ( ) ;
11021155 let rustdoc_test_options =
@@ -1131,6 +1184,7 @@ fn generate_test_desc_and_fn(
11311184 scraped_test,
11321185 rustdoc_options,
11331186 unused_externs,
1187+ doctest_id,
11341188 )
11351189 } ) ) ,
11361190 }
@@ -1143,6 +1197,7 @@ fn doctest_run_fn(
11431197 scraped_test : ScrapedDocTest ,
11441198 rustdoc_options : Arc < RustdocOptions > ,
11451199 unused_externs : Arc < Mutex < Vec < UnusedExterns > > > ,
1200+ doctest_id : usize ,
11461201) -> Result < ( ) , String > {
11471202 #[ cfg( not( bootstrap) ) ]
11481203 if scraped_test. langstr . should_panic && test:: cannot_handle_should_panic ( ) {
@@ -1168,8 +1223,13 @@ fn doctest_run_fn(
11681223 no_run : scraped_test. no_run ( & rustdoc_options) ,
11691224 merged_test_code : None ,
11701225 } ;
1171- let ( _, res) =
1172- run_test ( runnable_test, & rustdoc_options, doctest. supports_color , report_unused_externs) ;
1226+ let ( _, res) = run_test (
1227+ runnable_test,
1228+ & rustdoc_options,
1229+ doctest. supports_color ,
1230+ report_unused_externs,
1231+ doctest_id,
1232+ ) ;
11731233
11741234 if let Err ( err) = res {
11751235 eprint ! ( "{err}" ) ;
0 commit comments