Auto merge of #140592 - cuviper:beta-next, r=cuviper · rust-lang/rust@973ec11 (original) (raw)
`@@ -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(_) 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 item.ident.name == sym::main {
`
357
351
` info.has_main_fn = true;
`
358
352
`}
`
`@@ -411,37 +405,46 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
`
411
405
`push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi);
`
412
406
`}
`
413
407
`}
`
``
408
`+
let mut has_non_items = false;
`
414
409
`for stmt in &body.stmts {
`
415
410
`let mut is_extern_crate = false;
`
416
411
`match stmt.kind {
`
417
412
`StmtKind::Item(ref item) => {
`
418
``
`-
is_extern_crate = check_item(&item, &mut info, crate_name);
`
419
``
`-
}
`
420
``
`-
StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => {
`
421
``
`-
reset_error_count(&psess);
`
422
``
`-
return Err(());
`
``
413
`+
is_extern_crate = check_item(item, &mut info, crate_name);
`
423
414
`}
`
424
``
`-
StmtKind::MacCall(ref mac_call) if !info.has_main_fn => {
`
425
``
`-
let mut iter = mac_call.mac.args.tokens.iter();
`
426
``
-
427
``
`-
while let Some(token) = iter.next() {
`
428
``
`-
if let TokenTree::Token(token, _) = token
`
429
``
`-
&& let TokenKind::Ident(name, _) = token.kind
`
430
``
`-
&& name == kw::Fn
`
431
``
`-
&& let Some(TokenTree::Token(fn_token, _)) = iter.peek()
`
432
``
`-
&& let TokenKind::Ident(fn_name, _) = fn_token.kind
`
433
``
`-
&& fn_name == sym::main
`
434
``
`-
&& let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = {
`
435
``
`-
iter.next();
`
436
``
`-
iter.peek()
`
``
415
`+
// We assume that the macro calls will expand to item(s) even though they could
`
``
416
`+
// expand to statements and expressions.
`
``
417
`+
StmtKind::MacCall(ref mac_call) => {
`
``
418
`+
if !info.has_main_fn {
`
``
419
`` +
// For backward compatibility, we look for the token sequence fn main(…)
``
``
420
`+
// in the macro input (!) to crudely detect main functions "masked by a
`
``
421
`+
// wrapper macro". For the record, this is a horrible heuristic!
`
``
422
`+
// See https://github.com/rust-lang/rust/issues/56898.
`
``
423
`+
let mut iter = mac_call.mac.args.tokens.iter();
`
``
424
`+
while let Some(token) = iter.next() {
`
``
425
`+
if let TokenTree::Token(token, _) = token
`
``
426
`+
&& let TokenKind::Ident(kw::Fn, _) = token.kind
`
``
427
`+
&& let Some(TokenTree::Token(ident, _)) = iter.peek()
`
``
428
`+
&& let TokenKind::Ident(sym::main, _) = ident.kind
`
``
429
`+
&& let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, _)) = {
`
``
430
`+
iter.next();
`
``
431
`+
iter.peek()
`
``
432
`+
}
`
``
433
`+
{
`
``
434
`+
info.has_main_fn = true;
`
``
435
`+
break;
`
437
436
`}
`
438
``
`-
{
`
439
``
`-
info.has_main_fn = true;
`
440
``
`-
break;
`
441
437
`}
`
442
438
`}
`
443
439
`}
`
444
``
`-
_ => {}
`
``
440
`+
StmtKind::Expr(ref expr) => {
`
``
441
`+
if matches!(expr.kind, ast::ExprKind::Err(_)) {
`
``
442
`+
reset_error_count(&psess);
`
``
443
`+
return Err(());
`
``
444
`+
}
`
``
445
`+
has_non_items = true;
`
``
446
`+
}
`
``
447
`+
StmtKind::Let() | StmtKind::Semi() | StmtKind::Empty => has_non_items = true,
`
445
448
`}
`
446
449
``
447
450
`` // Weirdly enough, the Stmt
span doesn't include its attributes, so we need to
``
`@@ -466,6 +469,11 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
`
466
469
`push_to_s(&mut info.crates, source, span, &mut prev_span_hi);
`
467
470
`}
`
468
471
`}
`
``
472
`+
if has_non_items {
`
``
473
`` +
// FIXME: if info.has_main_fn
is true
, emit a warning here to mention that
``
``
474
`+
// this code will not be called.
`
``
475
`+
info.has_main_fn = false;
`
``
476
`+
}
`
469
477
`Ok(info)
`
470
478
`}
`
471
479
`Err(e) => {
`