@@ -21,7 +21,8 @@ use tracing::debug;
2121use  super :: diagnostics:: { ConsumeClosingDelim ,  dummy_arg} ; 
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} ; 
@@ -74,21 +75,11 @@ impl<'a> Parser<'a> {
7475            items. push ( item) ; 
7576        } 
7677
78+         // The last token should be `term`: either EOF or `}`. If it's not that means that we've had an error 
79+         // parsing an item 
7780        if  !self . eat ( term)  { 
78-             let  token_str = super :: token_descr ( & self . token ) ; 
7981            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-                 } ; 
82+                 let  err = self . fallback_incorrect_item ( ) ; 
9283                return  Err ( err) ; 
9384            } 
9485        } 
@@ -97,6 +88,64 @@ impl<'a> Parser<'a> {
9788        let  mod_spans = ModSpans  {  inner_span :  lo. to ( self . prev_token . span ) ,  inject_use_span } ; 
9889        Ok ( ( attrs,  items,  mod_spans) ) 
9990    } 
91+ 
92+     /// Tries to parse the item as a statement to provide further diagnostics. 
93+ fn  fallback_incorrect_item ( & mut  self )  -> rustc_errors:: Diag < ' a >  { 
94+         let  token_str = super :: token_descr ( & self . token ) ; 
95+         let  token_span = self . token . span ; 
96+         let  mut  err =
97+             self . dcx ( ) . struct_span_err ( token_span,  format ! ( "expected item, found {token_str}" ) ) ; 
98+ 
99+         let  mut  do_default_diag = true ; 
100+ 
101+         match  self . parse_full_stmt ( AttemptLocalParseRecovery :: No )  { 
102+             Ok ( Some ( stmt) )  => { 
103+                 do_default_diag = false ; 
104+                 let  span = stmt. span ; 
105+                 match  & stmt. kind  { 
106+                     StmtKind :: Let ( _)  => { 
107+                         err. span_label ( span,  "unexpected `let` binding outside of a function" ) 
108+                             . help ( format ! ( "consider using `const` or `static` instead of `let` for global variables, or put it inside of a function:  fn foo() {{ {} }}" , 
109+                             pprust:: stmt_to_string( & stmt) ) ) ; 
110+                     } 
111+                     StmtKind :: Semi ( expr)  => { 
112+                         err. span_label ( span,  "unexpected expression" ) . help ( format ! ( 
113+                             "consider putting it inside a function: fn foo() {{ {}; }}" , 
114+                             pprust:: expr_to_string( expr) 
115+                         ) ) ; 
116+                     } 
117+                     StmtKind :: Expr ( expr)  => { 
118+                         err. span_label ( span,  "unexpected expression" ) . help ( format ! ( 
119+                             "consider putting it inside a function: fn foo() {{ {} }}" , 
120+                             pprust:: expr_to_string( expr) 
121+                         ) ) ; 
122+                     } 
123+                     StmtKind :: Empty  => { 
124+                         unreachable ! ( 
125+                             "Should have been handled by maybe_consume_incorrect_semicolon" 
126+                         ) ; 
127+                     } 
128+                     StmtKind :: Item ( _)  | StmtKind :: MacCall ( _)  => { 
129+                         unreachable ! ( "These should be valid items!" ) 
130+                     } 
131+                 } ; 
132+             } 
133+             // It's not a statement, we can't do much recovery. 
134+             Ok ( None )  => { } 
135+             Err ( e)  => { 
136+                 // We don't really care about an error parsing this statement. 
137+                 e. cancel ( ) ; 
138+             } 
139+         } 
140+ 
141+         if  do_default_diag { 
142+             err. span_label ( token_span,  "expected item" ) ; 
143+         } 
144+ 
145+         err. note ( "for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>" ) ; 
146+ 
147+         err
148+     } 
100149} 
101150
102151pub ( super )  type  ItemInfo  = ( Ident ,  ItemKind ) ; 
0 commit comments