@@ -10,18 +10,19 @@ use rustc_ast::util::case::Case;
10
10
use rustc_ast:: { self as ast} ;
11
11
use rustc_ast_pretty:: pprust;
12
12
use 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 } ;
14
14
use rustc_span:: edit_distance:: edit_distance;
15
15
use 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 } ;
19
19
use tracing:: debug;
20
20
21
- use super :: diagnostics:: { ConsumeClosingDelim , dummy_arg } ;
21
+ use super :: diagnostics:: { dummy_arg , ConsumeClosingDelim } ;
22
22
use super :: ty:: { AllowPlus , RecoverQPath , RecoverReturnSign } ;
23
23
use super :: {
24
- AttrWrapper , FollowedByType , ForceCollect , Parser , PathStyle , Trailing , UsePreAttrPos ,
24
+ AttemptLocalParseRecovery , AttrWrapper , FollowedByType , ForceCollect , Parser , PathStyle ,
25
+ Trailing , UsePreAttrPos ,
25
26
} ;
26
27
use crate :: errors:: { self , MacroExpandsToAdtField } ;
27
28
use crate :: { fluent_generated as fluent, maybe_whole} ;
@@ -75,20 +76,8 @@ impl<'a> Parser<'a> {
75
76
}
76
77
77
78
if !self . eat ( term) {
78
- let token_str = super :: token_descr ( & self . token ) ;
79
79
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 ( ) ;
92
81
return Err ( err) ;
93
82
}
94
83
}
@@ -97,6 +86,55 @@ impl<'a> Parser<'a> {
97
86
let mod_spans = ModSpans { inner_span : lo. to ( self . prev_token . span ) , inject_use_span } ;
98
87
Ok ( ( attrs, items, mod_spans) )
99
88
}
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
+ }
100
138
}
101
139
102
140
pub ( super ) type ItemInfo = ( Ident , ItemKind ) ;
@@ -452,7 +490,11 @@ impl<'a> Parser<'a> {
452
490
None
453
491
} ;
454
492
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
+ }
456
498
}
457
499
458
500
fn parse_item_builtin ( & mut self ) -> PResult < ' a , Option < ItemInfo > > {
@@ -1112,7 +1154,11 @@ impl<'a> Parser<'a> {
1112
1154
}
1113
1155
1114
1156
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
+ }
1116
1162
}
1117
1163
1118
1164
fn parse_ident_or_underscore ( & mut self ) -> PResult < ' a , Ident > {
@@ -1195,7 +1241,7 @@ impl<'a> Parser<'a> {
1195
1241
mut safety : Safety ,
1196
1242
) -> PResult < ' a , ItemInfo > {
1197
1243
let abi = self . parse_abi ( ) ; // ABI?
1198
- // FIXME: This recovery should be tested better.
1244
+ // FIXME: This recovery should be tested better.
1199
1245
if safety == Safety :: Default
1200
1246
&& self . token . is_keyword ( kw:: Unsafe )
1201
1247
&& self . look_ahead ( 1 , |t| * t == token:: OpenDelim ( Delimiter :: Brace ) )
@@ -1897,10 +1943,10 @@ impl<'a> Parser<'a> {
1897
1943
// Try to recover extra trailing angle brackets
1898
1944
if let TyKind :: Path ( _, Path { segments, .. } ) = & a_var. ty . kind {
1899
1945
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
+ ) ;
1904
1950
if let Some ( _guar) = guar {
1905
1951
// Handle a case like `Vec<u8>>,` where we can continue parsing fields
1906
1952
// after the comma
@@ -2107,7 +2153,7 @@ impl<'a> Parser<'a> {
2107
2153
self . unexpected ( ) ?;
2108
2154
}
2109
2155
let body = self . parse_token_tree ( ) ; // `MacBody`
2110
- // Convert `MacParams MacBody` into `{ MacParams => MacBody }`.
2156
+ // Convert `MacParams MacBody` into `{ MacParams => MacBody }`.
2111
2157
let bspan = body. span ( ) ;
2112
2158
let arrow = TokenTree :: token_alone ( token:: FatArrow , pspan. between ( bspan) ) ; // `=>`
2113
2159
let tokens = TokenStream :: new ( vec ! [ params, arrow, body] ) ;
0 commit comments