@@ -394,7 +394,7 @@ pub fn make_test(s: &str,
394
394
395
395
// Uses libsyntax to parse the doctest and find if there's a main fn and the extern
396
396
// 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 ( || {
398
398
use crate :: syntax:: { ast, parse:: { self , ParseSess } , source_map:: FilePathMapping } ;
399
399
use crate :: syntax_pos:: FileName ;
400
400
use errors:: emitter:: EmitterWriter ;
@@ -412,6 +412,7 @@ pub fn make_test(s: &str,
412
412
413
413
let mut found_main = false ;
414
414
let mut found_extern_crate = cratename. is_none ( ) ;
415
+ let mut found_macro = false ;
415
416
416
417
let mut parser = match parse:: maybe_new_parser_from_source_str ( & sess, filename, source) {
417
418
Ok ( p) => p,
@@ -420,7 +421,7 @@ pub fn make_test(s: &str,
420
421
err. cancel ( ) ;
421
422
}
422
423
423
- return ( found_main, found_extern_crate) ;
424
+ return ( found_main, found_extern_crate, found_macro ) ;
424
425
}
425
426
} ;
426
427
@@ -448,6 +449,12 @@ pub fn make_test(s: &str,
448
449
}
449
450
}
450
451
452
+ if !found_macro {
453
+ if let ast:: ItemKind :: Mac ( ..) = item. node {
454
+ found_macro = true ;
455
+ }
456
+ }
457
+
451
458
if found_main && found_extern_crate {
452
459
break ;
453
460
}
@@ -460,9 +467,28 @@ pub fn make_test(s: &str,
460
467
}
461
468
}
462
469
463
- ( found_main, found_extern_crate)
470
+ ( found_main, found_extern_crate, found_macro )
464
471
} ) ;
465
472
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
+
466
492
// Don't inject `extern crate std` because it's already injected by the
467
493
// compiler.
468
494
if !already_has_extern_crate && !opts. no_crate_inject && cratename != Some ( "std" ) {
@@ -1143,4 +1169,23 @@ assert_eq!(asdf::foo, 4);
1143
1169
let output = make_test ( input, Some ( "asdf" ) , false , & opts) ;
1144
1170
assert_eq ! ( output, ( expected, 3 ) ) ;
1145
1171
}
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
+ }
1146
1191
}
0 commit comments