@@ -8,14 +8,14 @@ use std::sync::Arc;
88use rustc_ast:: token:: { Delimiter , TokenKind } ;
99use rustc_ast:: tokenstream:: TokenTree ;
1010use rustc_ast:: { self as ast, AttrStyle , HasAttrs , StmtKind } ;
11- use rustc_errors:: ColorConfig ;
1211use rustc_errors:: emitter:: stderr_destination;
12+ use rustc_errors:: { ColorConfig , DiagCtxtHandle } ;
1313use rustc_parse:: new_parser_from_source_str;
1414use rustc_session:: parse:: ParseSess ;
1515use rustc_span:: edition:: Edition ;
1616use rustc_span:: source_map:: SourceMap ;
1717use rustc_span:: symbol:: sym;
18- use rustc_span:: { FileName , kw} ;
18+ use rustc_span:: { FileName , Span , kw} ;
1919use tracing:: debug;
2020
2121use super :: GlobalTestOptions ;
@@ -61,6 +61,8 @@ impl DocTestBuilder {
6161 // If `test_id` is `None`, it means we're generating code for a code example "run" link.
6262 test_id : Option < String > ,
6363 lang_str : Option < & LangString > ,
64+ dcx : Option < DiagCtxtHandle < ' _ > > ,
65+ span : Span ,
6466 ) -> Self {
6567 let can_merge_doctests = can_merge_doctests
6668 && lang_str. is_some_and ( |lang_str| {
@@ -69,7 +71,7 @@ impl DocTestBuilder {
6971
7072 let result = rustc_driver:: catch_fatal_errors ( || {
7173 rustc_span:: create_session_if_not_set_then ( edition, |_| {
72- parse_source ( source, & crate_name)
74+ parse_source ( source, & crate_name, dcx , span )
7375 } )
7476 } ) ;
7577
@@ -289,7 +291,12 @@ fn reset_error_count(psess: &ParseSess) {
289291
290292const DOCTEST_CODE_WRAPPER : & str = "fn f(){" ;
291293
292- fn parse_source ( source : & str , crate_name : & Option < & str > ) -> Result < ParseSourceInfo , ( ) > {
294+ fn parse_source (
295+ source : & str ,
296+ crate_name : & Option < & str > ,
297+ parent_dcx : Option < DiagCtxtHandle < ' _ > > ,
298+ span : Span ,
299+ ) -> Result < ParseSourceInfo , ( ) > {
293300 use rustc_errors:: DiagCtxt ;
294301 use rustc_errors:: emitter:: { Emitter , HumanEmitter } ;
295302 use rustc_span:: source_map:: FilePathMapping ;
@@ -475,8 +482,17 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
475482 }
476483 }
477484 if has_non_items {
478- // FIXME: if `info.has_main_fn` is `true`, emit a warning here to mention that
479- // this code will not be called.
485+ if info. has_main_fn
486+ && let Some ( dcx) = parent_dcx
487+ && !span. is_dummy ( )
488+ {
489+ dcx. span_warn (
490+ span,
491+ "the `main` function of this doctest won't be run as it contains \
492+ expressions at the top level, meaning that the whole doctest code will be \
493+ wrapped in a function",
494+ ) ;
495+ }
480496 info. has_main_fn = false ;
481497 }
482498 Ok ( info)
0 commit comments