@@ -394,7 +394,7 @@ pub fn make_test(s: &str,
394394
395395 // Uses libsyntax to parse the doctest and find if there's a main fn and the extern
396396 // crate already is included.
397- let ( already_has_main, already_has_extern_crate) = crate :: syntax:: with_globals ( || {
397+ let ( already_has_main, already_has_extern_crate, found_macro ) = crate :: syntax:: with_globals ( || {
398398 use crate :: syntax:: { ast, parse:: { self , ParseSess } , source_map:: FilePathMapping } ;
399399 use crate :: syntax_pos:: FileName ;
400400 use errors:: emitter:: EmitterWriter ;
@@ -412,6 +412,7 @@ pub fn make_test(s: &str,
412412
413413 let mut found_main = false ;
414414 let mut found_extern_crate = cratename. is_none ( ) ;
415+ let mut found_macro = false ;
415416
416417 let mut parser = match parse:: maybe_new_parser_from_source_str ( & sess, filename, source) {
417418 Ok ( p) => p,
@@ -420,7 +421,7 @@ pub fn make_test(s: &str,
420421 err. cancel ( ) ;
421422 }
422423
423- return ( found_main, found_extern_crate) ;
424+ return ( found_main, found_extern_crate, found_macro ) ;
424425 }
425426 } ;
426427
@@ -448,6 +449,12 @@ pub fn make_test(s: &str,
448449 }
449450 }
450451
452+ if !found_macro {
453+ if let ast:: ItemKind :: Mac ( ..) = item. node {
454+ found_macro = true ;
455+ }
456+ }
457+
451458 if found_main && found_extern_crate {
452459 break ;
453460 }
@@ -460,9 +467,28 @@ pub fn make_test(s: &str,
460467 }
461468 }
462469
463- ( found_main, found_extern_crate)
470+ ( found_main, found_extern_crate, found_macro )
464471 } ) ;
465472
473+ // If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't
474+ // see it. In that case, run the old text-based scan to see if they at least have a main
475+ // function written inside a macro invocation. See
476+ // https://github.com/rust-lang/rust/issues/56898
477+ let already_has_main = if found_macro && !already_has_main {
478+ s. lines ( )
479+ . map ( |line| {
480+ let comment = line. find ( "//" ) ;
481+ if let Some ( comment_begins) = comment {
482+ & line[ 0 ..comment_begins]
483+ } else {
484+ line
485+ }
486+ } )
487+ . any ( |code| code. contains ( "fn main" ) )
488+ } else {
489+ already_has_main
490+ } ;
491+
466492 // Don't inject `extern crate std` because it's already injected by the
467493 // compiler.
468494 if !already_has_extern_crate && !opts. no_crate_inject && cratename != Some ( "std" ) {
@@ -1143,4 +1169,23 @@ assert_eq!(asdf::foo, 4);
11431169 let output = make_test ( input, Some ( "asdf" ) , false , & opts) ;
11441170 assert_eq ! ( output, ( expected, 3 ) ) ;
11451171 }
1172+
1173+ #[ test]
1174+ fn make_test_main_in_macro ( ) {
1175+ let opts = TestOptions :: default ( ) ;
1176+ let input =
1177+ "#[macro_use] extern crate my_crate;
1178+ test_wrapper! {
1179+ fn main() {}
1180+ }" ;
1181+ let expected =
1182+ "#![allow(unused)]
1183+ #[macro_use] extern crate my_crate;
1184+ test_wrapper! {
1185+ fn main() {}
1186+ }" . to_string ( ) ;
1187+
1188+ let output = make_test ( input, Some ( "my_crate" ) , false , & opts) ;
1189+ assert_eq ! ( output, ( expected, 1 ) ) ;
1190+ }
11461191}
0 commit comments