@@ -301,8 +301,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
301
301
302
302
let filename = FileName :: anon_source_code ( & wrapped_source) ;
303
303
304
- // Any errors in parsing should also appear when the doctest is compiled for real, so just
305
- // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr.
306
304
let sm = Arc :: new ( SourceMap :: new ( FilePathMapping :: empty ( ) ) ) ;
307
305
let fallback_bundle = rustc_errors:: fallback_fluent_bundle (
308
306
rustc_driver:: DEFAULT_LOCALE_RESOURCES . to_vec ( ) ,
@@ -311,7 +309,8 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
311
309
info. supports_color =
312
310
HumanEmitter :: new ( stderr_destination ( ColorConfig :: Auto ) , fallback_bundle. clone ( ) )
313
311
. supports_color ( ) ;
314
-
312
+ // Any errors in parsing should also appear when the doctest is compiled for real, so just
313
+ // send all the errors that the parser emits directly into a `Sink` instead of stderr.
315
314
let emitter = HumanEmitter :: new ( Box :: new ( io:: sink ( ) ) , fallback_bundle) ;
316
315
317
316
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
@@ -339,9 +338,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
339
338
* prev_span_hi = hi;
340
339
}
341
340
342
- // Recurse through functions body. It is necessary because the doctest source code is
343
- // wrapped in a function to limit the number of AST errors. If we don't recurse into
344
- // functions, we would thing all top-level items (so basically nothing).
345
341
fn check_item ( item : & ast:: Item , info : & mut ParseSourceInfo , crate_name : & Option < & str > ) -> bool {
346
342
let mut is_extern_crate = false ;
347
343
if !info. has_global_allocator
@@ -351,8 +347,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
351
347
}
352
348
match item. kind {
353
349
ast:: ItemKind :: Fn ( ref fn_item) if !info. has_main_fn => {
354
- // We only push if it's the top item because otherwise, we would duplicate
355
- // its content since the top-level item was already added.
356
350
if fn_item. ident . name == sym:: main {
357
351
info. has_main_fn = true ;
358
352
}
@@ -412,44 +406,38 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
412
406
let mut is_extern_crate = false ;
413
407
match stmt. kind {
414
408
StmtKind :: Item ( ref item) => {
415
- is_extern_crate = check_item ( & item, & mut info, crate_name) ;
416
- }
417
- StmtKind :: Expr ( ref expr) => {
418
- if matches ! ( expr. kind, ast:: ExprKind :: Err ( _) ) {
419
- reset_error_count ( & psess) ;
420
- return Err ( ( ) ) ;
421
- }
422
- has_non_items = true ;
409
+ is_extern_crate = check_item ( item, & mut info, crate_name) ;
423
410
}
424
411
// We assume that the macro calls will expand to item(s) even though they could
425
- // expand to statements and expressions. And the simple fact that we're trying
426
- // to retrieve a `main` function inside it is a terrible idea.
412
+ // expand to statements and expressions.
427
413
StmtKind :: MacCall ( ref mac_call) => {
428
- if info. has_main_fn {
429
- continue ;
430
- }
431
- let mut iter = mac_call . mac . args . tokens . iter ( ) ;
432
-
433
- while let Some ( token ) = iter . next ( ) {
434
- if let TokenTree :: Token ( token, _ ) = token
435
- && let TokenKind :: Ident ( name , _) = token. kind
436
- && name == kw:: Fn
437
- && let Some ( TokenTree :: Token ( fn_token , _) ) = iter. peek ( )
438
- && let TokenKind :: Ident ( fn_name , _) = fn_token . kind
439
- && fn_name == sym :: main
440
- && let Some ( TokenTree :: Delimited ( _ , _ , Delimiter :: Parenthesis , _ ) ) = {
441
- iter . next ( ) ;
442
- iter . peek ( )
414
+ if ! info. has_main_fn {
415
+ // For backward compatibility, we look for the token sequence `fn main(…)`
416
+ // in the macro input (!) to crudely detect main functions "masked by a
417
+ // wrapper macro". For the record, this is a horrible heuristic!
418
+ // See <https://github.com/rust-lang/rust/issues/56898>.
419
+ let mut iter = mac_call . mac . args . tokens . iter ( ) ;
420
+ while let Some ( token) = iter . next ( ) {
421
+ if let TokenTree :: Token ( token , _) = token
422
+ && let TokenKind :: Ident ( kw:: Fn , _ ) = token . kind
423
+ && let Some ( TokenTree :: Token ( ident , _) ) = iter. next ( )
424
+ && let TokenKind :: Ident ( sym :: main , _) = ident . kind
425
+ && let Some ( TokenTree :: Delimited ( .. , Delimiter :: Parenthesis , _ ) ) =
426
+ iter . next ( )
427
+ {
428
+ info . has_main_fn = true ;
443
429
}
444
- {
445
- info. has_main_fn = true ;
446
- break ;
447
430
}
448
431
}
449
432
}
450
- _ => {
433
+ StmtKind :: Expr ( ref expr) => {
434
+ if matches ! ( expr. kind, ast:: ExprKind :: Err ( _) ) {
435
+ reset_error_count ( & psess) ;
436
+ return Err ( ( ) ) ;
437
+ }
451
438
has_non_items = true ;
452
439
}
440
+ StmtKind :: Let ( _) | StmtKind :: Semi ( _) | StmtKind :: Empty => has_non_items = true ,
453
441
}
454
442
455
443
// Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to
0 commit comments