@@ -10,18 +10,19 @@ use rustc_ast::util::case::Case;
1010use rustc_ast:: { self as ast} ;
1111use rustc_ast_pretty:: pprust;
1212use rustc_errors:: codes:: * ;
13- use rustc_errors:: { Applicability , PResult , StashKey , struct_span_code_err } ;
13+ use rustc_errors:: { struct_span_code_err , Applicability , PResult , StashKey } ;
1414use rustc_span:: edit_distance:: edit_distance;
1515use rustc_span:: edition:: Edition ;
16- use rustc_span:: symbol:: { Ident , Symbol , kw , sym } ;
17- use rustc_span:: { DUMMY_SP , ErrorGuaranteed , Span , source_map } ;
18- use thin_vec:: { ThinVec , thin_vec } ;
16+ use rustc_span:: symbol:: { kw , sym , Ident , Symbol } ;
17+ use rustc_span:: { source_map , ErrorGuaranteed , Span , DUMMY_SP } ;
18+ use thin_vec:: { thin_vec , ThinVec } ;
1919use tracing:: debug;
2020
21- use super :: diagnostics:: { ConsumeClosingDelim , dummy_arg } ;
21+ use super :: diagnostics:: { dummy_arg , ConsumeClosingDelim } ;
2222use super :: ty:: { AllowPlus , RecoverQPath , RecoverReturnSign } ;
2323use super :: {
24- AttrWrapper , FollowedByType , ForceCollect , Parser , PathStyle , Trailing , UsePreAttrPos ,
24+ AttemptLocalParseRecovery , AttrWrapper , FollowedByType , ForceCollect , Parser , PathStyle ,
25+ Trailing , UsePreAttrPos ,
2526} ;
2627use crate :: errors:: { self , MacroExpandsToAdtField } ;
2728use crate :: { fluent_generated as fluent, maybe_whole} ;
@@ -75,20 +76,8 @@ impl<'a> Parser<'a> {
7576 }
7677
7778 if !self . eat ( term) {
78- let token_str = super :: token_descr ( & self . token ) ;
7979 if !self . maybe_consume_incorrect_semicolon ( items. last ( ) . map ( |x| & * * x) ) {
80- let msg = format ! ( "expected item, found {token_str}" ) ;
81- let mut err = self . dcx ( ) . struct_span_err ( self . token . span , msg) ;
82- let span = self . token . span ;
83- if self . is_kw_followed_by_ident ( kw:: Let ) {
84- err. span_label (
85- span,
86- "consider using `const` or `static` instead of `let` for global variables" ,
87- ) ;
88- } else {
89- err. span_label ( span, "expected item" )
90- . note ( "for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>" ) ;
91- } ;
80+ let err = self . fallback_incorrect_item ( ) ;
9281 return Err ( err) ;
9382 }
9483 }
@@ -97,6 +86,55 @@ impl<'a> Parser<'a> {
9786 let mod_spans = ModSpans { inner_span : lo. to ( self . prev_token . span ) , inject_use_span } ;
9887 Ok ( ( attrs, items, mod_spans) )
9988 }
89+
90+ /// Tries to parse the item as a statement to provide further diagnostics.
91+ fn fallback_incorrect_item ( & mut self ) -> rustc_errors:: Diag < ' a > {
92+ let token_str = super :: token_descr ( & self . token ) ;
93+ let mut err = self
94+ . dcx ( )
95+ . struct_span_err ( self . token . span , format ! ( "expected item, found {token_str}" ) ) ;
96+
97+ match self . parse_full_stmt ( AttemptLocalParseRecovery :: No ) {
98+ Ok ( Some ( stmt) ) => {
99+ let span = stmt. span ;
100+ match & stmt. kind {
101+ StmtKind :: Let ( _) => {
102+ err. span_label ( span, "unexpected `let` binding outside of a function" )
103+ . help ( format ! ( "consider using `const` or `static` instead of `let` for global variables, or put it inside of a function: fn foo() {{ {} }}" ,
104+ pprust:: stmt_to_string( & stmt) ) ) ;
105+ }
106+ StmtKind :: Semi ( expr) => {
107+ err. span_label ( span, "unexpected expression" ) . help ( format ! (
108+ "consider putting it inside a function: fn foo() {{ {}; }}" ,
109+ pprust:: expr_to_string( expr)
110+ ) ) ;
111+ }
112+ StmtKind :: Expr ( expr) => {
113+ err. span_label ( span, "unexpected expression" ) . help ( format ! (
114+ "consider putting it inside a function: fn foo() {{ {} }}" ,
115+ pprust:: expr_to_string( expr)
116+ ) ) ;
117+ }
118+ StmtKind :: Empty => {
119+ unreachable ! (
120+ "Should have been handled by maybe_consume_incorrect_semicolon"
121+ ) ;
122+ }
123+ StmtKind :: Item ( _) | StmtKind :: MacCall ( _) => {
124+ unreachable ! ( "These should be valid." )
125+ }
126+ } ;
127+ }
128+ Ok ( None ) => { } // It's not a statement, not much we can do.
129+ Err ( e) => {
130+ // We don't really care about an error parsing this statement.
131+ e. cancel ( ) ;
132+ }
133+ }
134+ err. note ( "for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>" ) ;
135+
136+ err
137+ }
100138}
101139
102140pub ( super ) type ItemInfo = ( Ident , ItemKind ) ;
@@ -452,7 +490,11 @@ impl<'a> Parser<'a> {
452490 None
453491 } ;
454492
455- if let Some ( err) = err { Err ( self . dcx ( ) . create_err ( err) ) } else { Ok ( ( ) ) }
493+ if let Some ( err) = err {
494+ Err ( self . dcx ( ) . create_err ( err) )
495+ } else {
496+ Ok ( ( ) )
497+ }
456498 }
457499
458500 fn parse_item_builtin ( & mut self ) -> PResult < ' a , Option < ItemInfo > > {
@@ -1112,7 +1154,11 @@ impl<'a> Parser<'a> {
11121154 }
11131155
11141156 fn parse_rename ( & mut self ) -> PResult < ' a , Option < Ident > > {
1115- if self . eat_keyword ( kw:: As ) { self . parse_ident_or_underscore ( ) . map ( Some ) } else { Ok ( None ) }
1157+ if self . eat_keyword ( kw:: As ) {
1158+ self . parse_ident_or_underscore ( ) . map ( Some )
1159+ } else {
1160+ Ok ( None )
1161+ }
11161162 }
11171163
11181164 fn parse_ident_or_underscore ( & mut self ) -> PResult < ' a , Ident > {
@@ -1195,7 +1241,7 @@ impl<'a> Parser<'a> {
11951241 mut safety : Safety ,
11961242 ) -> PResult < ' a , ItemInfo > {
11971243 let abi = self . parse_abi ( ) ; // ABI?
1198- // FIXME: This recovery should be tested better.
1244+ // FIXME: This recovery should be tested better.
11991245 if safety == Safety :: Default
12001246 && self . token . is_keyword ( kw:: Unsafe )
12011247 && self . look_ahead ( 1 , |t| * t == token:: OpenDelim ( Delimiter :: Brace ) )
@@ -1897,10 +1943,10 @@ impl<'a> Parser<'a> {
18971943 // Try to recover extra trailing angle brackets
18981944 if let TyKind :: Path ( _, Path { segments, .. } ) = & a_var. ty . kind {
18991945 if let Some ( last_segment) = segments. last ( ) {
1900- let guar = self . check_trailing_angle_brackets ( last_segment , & [
1901- & token :: Comma ,
1902- & token:: CloseDelim ( Delimiter :: Brace ) ,
1903- ] ) ;
1946+ let guar = self . check_trailing_angle_brackets (
1947+ last_segment ,
1948+ & [ & token:: Comma , & token :: CloseDelim ( Delimiter :: Brace ) ] ,
1949+ ) ;
19041950 if let Some ( _guar) = guar {
19051951 // Handle a case like `Vec<u8>>,` where we can continue parsing fields
19061952 // after the comma
@@ -2107,7 +2153,7 @@ impl<'a> Parser<'a> {
21072153 self . unexpected ( ) ?;
21082154 }
21092155 let body = self . parse_token_tree ( ) ; // `MacBody`
2110- // Convert `MacParams MacBody` into `{ MacParams => MacBody }`.
2156+ // Convert `MacParams MacBody` into `{ MacParams => MacBody }`.
21112157 let bspan = body. span ( ) ;
21122158 let arrow = TokenTree :: token_alone ( token:: FatArrow , pspan. between ( bspan) ) ; // `=>`
21132159 let tokens = TokenStream :: new ( vec ! [ params, arrow, body] ) ;
0 commit comments