@@ -202,17 +202,7 @@ fn run_test(
202202 opts : & TestOptions ,
203203 edition : Edition ,
204204) -> Result < ( ) , TestFailure > {
205- let ( test, line_offset) = match panic:: catch_unwind ( || {
206- make_test ( test, Some ( cratename) , as_test_harness, opts, edition)
207- } ) {
208- Ok ( ( test, line_offset) ) => ( test, line_offset) ,
209- Err ( cause) if cause. is :: < errors:: FatalErrorMarker > ( ) => {
210- // If the parser used by `make_test` panicked due to a fatal error, pass the test code
211- // through unchanged. The error will be reported during compilation.
212- ( test. to_owned ( ) , 0 )
213- }
214- Err ( cause) => panic:: resume_unwind ( cause) ,
215- } ;
205+ let ( test, line_offset) = make_test ( test, Some ( cratename) , as_test_harness, opts, edition) ;
216206
217207 // FIXME(#44940): if doctests ever support path remapping, then this filename
218208 // needs to be the result of `SourceMap::span_to_unmapped_path`.
@@ -362,11 +352,6 @@ fn run_test(
362352
363353/// Transforms a test into code that can be compiled into a Rust binary, and returns the number of
364354/// lines before the test code begins.
365- ///
366- /// # Panics
367- ///
368- /// This function uses the compiler's parser internally. The parser will panic if it encounters a
369- /// fatal error while parsing the test.
370355pub fn make_test (
371356 s : & str ,
372357 cratename : Option < & str > ,
@@ -401,83 +386,94 @@ pub fn make_test(
401386
402387 // Uses libsyntax to parse the doctest and find if there's a main fn and the extern
403388 // crate already is included.
404- let ( already_has_main, already_has_extern_crate, found_macro) = with_globals ( edition, || {
405- use errors:: emitter:: EmitterWriter ;
406- use errors:: Handler ;
407- use rustc_parse:: maybe_new_parser_from_source_str;
408- use rustc_span:: source_map:: FilePathMapping ;
409- use syntax:: sess:: ParseSess ;
410-
411- let filename = FileName :: anon_source_code ( s) ;
412- let source = crates + & everything_else;
413-
414- // Any errors in parsing should also appear when the doctest is compiled for real, so just
415- // send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
416- let cm = Lrc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
417- let emitter = EmitterWriter :: new ( box io:: sink ( ) , None , false , false , false , None , false ) ;
418- // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
419- let handler = Handler :: with_emitter ( false , None , box emitter) ;
420- let sess = ParseSess :: with_span_handler ( handler, cm) ;
421-
422- let mut found_main = false ;
423- let mut found_extern_crate = cratename. is_none ( ) ;
424- let mut found_macro = false ;
425-
426- let mut parser = match maybe_new_parser_from_source_str ( & sess, filename, source) {
427- Ok ( p) => p,
428- Err ( errs) => {
429- for mut err in errs {
430- err. cancel ( ) ;
389+ let result = rustc_driver:: catch_fatal_errors ( || {
390+ with_globals ( edition, || {
391+ use errors:: emitter:: EmitterWriter ;
392+ use errors:: Handler ;
393+ use rustc_parse:: maybe_new_parser_from_source_str;
394+ use rustc_span:: source_map:: FilePathMapping ;
395+ use syntax:: sess:: ParseSess ;
396+
397+ let filename = FileName :: anon_source_code ( s) ;
398+ let source = crates + & everything_else;
399+
400+ // Any errors in parsing should also appear when the doctest is compiled for real, so just
401+ // send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
402+ let cm = Lrc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
403+ let emitter =
404+ EmitterWriter :: new ( box io:: sink ( ) , None , false , false , false , None , false ) ;
405+ // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
406+ let handler = Handler :: with_emitter ( false , None , box emitter) ;
407+ let sess = ParseSess :: with_span_handler ( handler, cm) ;
408+
409+ let mut found_main = false ;
410+ let mut found_extern_crate = cratename. is_none ( ) ;
411+ let mut found_macro = false ;
412+
413+ let mut parser = match maybe_new_parser_from_source_str ( & sess, filename, source) {
414+ Ok ( p) => p,
415+ Err ( errs) => {
416+ for mut err in errs {
417+ err. cancel ( ) ;
418+ }
419+
420+ return ( found_main, found_extern_crate, found_macro) ;
431421 }
422+ } ;
423+
424+ loop {
425+ match parser. parse_item ( ) {
426+ Ok ( Some ( item) ) => {
427+ if !found_main {
428+ if let ast:: ItemKind :: Fn ( ..) = item. kind {
429+ if item. ident . name == sym:: main {
430+ found_main = true ;
431+ }
432+ }
433+ }
432434
433- return ( found_main, found_extern_crate, found_macro) ;
434- }
435- } ;
435+ if !found_extern_crate {
436+ if let ast:: ItemKind :: ExternCrate ( original) = item. kind {
437+ // This code will never be reached if `cratename` is none because
438+ // `found_extern_crate` is initialized to `true` if it is none.
439+ let cratename = cratename. unwrap ( ) ;
436440
437- loop {
438- match parser. parse_item ( ) {
439- Ok ( Some ( item) ) => {
440- if !found_main {
441- if let ast:: ItemKind :: Fn ( ..) = item. kind {
442- if item. ident . name == sym:: main {
443- found_main = true ;
441+ match original {
442+ Some ( name) => found_extern_crate = name. as_str ( ) == cratename,
443+ None => found_extern_crate = item. ident . as_str ( ) == cratename,
444+ }
444445 }
445446 }
446- }
447-
448- if !found_extern_crate {
449- if let ast:: ItemKind :: ExternCrate ( original) = item. kind {
450- // This code will never be reached if `cratename` is none because
451- // `found_extern_crate` is initialized to `true` if it is none.
452- let cratename = cratename. unwrap ( ) ;
453447
454- match original {
455- Some ( name ) => found_extern_crate = name . as_str ( ) == cratename ,
456- None => found_extern_crate = item . ident . as_str ( ) == cratename ,
448+ if !found_macro {
449+ if let ast :: ItemKind :: Mac ( .. ) = item . kind {
450+ found_macro = true ;
457451 }
458452 }
459- }
460453
461- if !found_macro {
462- if let ast:: ItemKind :: Mac ( ..) = item. kind {
463- found_macro = true ;
454+ if found_main && found_extern_crate {
455+ break ;
464456 }
465457 }
466-
467- if found_main && found_extern_crate {
458+ Ok ( None ) => break ,
459+ Err ( mut e) => {
460+ e. cancel ( ) ;
468461 break ;
469462 }
470463 }
471- Ok ( None ) => break ,
472- Err ( mut e) => {
473- e. cancel ( ) ;
474- break ;
475- }
476464 }
477- }
478465
479- ( found_main, found_extern_crate, found_macro)
466+ ( found_main, found_extern_crate, found_macro)
467+ } )
480468 } ) ;
469+ let ( already_has_main, already_has_extern_crate, found_macro) = match result {
470+ Ok ( result) => result,
471+ Err ( ErrorReported ) => {
472+ // If the parser panicked due to a fatal error, pass the test code through unchanged.
473+ // The error will be reported during compilation.
474+ return ( s. to_owned ( ) , 0 ) ;
475+ }
476+ } ;
481477
482478 // If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't
483479 // see it. In that case, run the old text-based scan to see if they at least have a main
0 commit comments