@@ -171,6 +171,12 @@ impl RecoverQPath for Expr {
171
171
}
172
172
}
173
173
174
+ /// Control whether the closing delimiter should be consumed when calling `Parser::consume_block`.
175
+ crate enum ConsumeClosingDelim {
176
+ Yes ,
177
+ No ,
178
+ }
179
+
174
180
impl < ' a > Parser < ' a > {
175
181
pub fn fatal ( & self , m : & str ) -> DiagnosticBuilder < ' a > {
176
182
self . span_fatal ( self . token . span , m)
@@ -1105,8 +1111,8 @@ impl<'a> Parser<'a> {
1105
1111
Ok ( x) => x,
1106
1112
Err ( mut err) => {
1107
1113
err. emit ( ) ;
1108
- // Recover from parse error.
1109
- self . consume_block ( delim) ;
1114
+ // Recover from parse error, callers expect the closing delim to be consumed .
1115
+ self . consume_block ( delim, ConsumeClosingDelim :: Yes ) ;
1110
1116
self . mk_expr ( lo. to ( self . prev_span ) , ExprKind :: Err , ThinVec :: new ( ) )
1111
1117
}
1112
1118
}
@@ -1135,6 +1141,11 @@ impl<'a> Parser<'a> {
1135
1141
// Don't attempt to recover from this unclosed delimiter more than once.
1136
1142
let unmatched = self . unclosed_delims . remove ( pos) ;
1137
1143
let delim = TokenType :: Token ( token:: CloseDelim ( unmatched. expected_delim ) ) ;
1144
+ if unmatched. found_delim . is_none ( ) {
1145
+ // We encountered `Eof`, set this fact here to avoid complaining about missing
1146
+ // `fn main()` when we found place to suggest the closing brace.
1147
+ * self . sess . reached_eof . borrow_mut ( ) = true ;
1148
+ }
1138
1149
1139
1150
// We want to suggest the inclusion of the closing delimiter where it makes
1140
1151
// the most sense, which is immediately after the last token:
@@ -1154,17 +1165,29 @@ impl<'a> Parser<'a> {
1154
1165
delim. to_string ( ) ,
1155
1166
Applicability :: MaybeIncorrect ,
1156
1167
) ;
1157
- err. emit ( ) ;
1158
- self . expected_tokens . clear ( ) ; // reduce errors
1159
- Ok ( true )
1168
+ if unmatched. found_delim . is_none ( ) {
1169
+ // Encountered `Eof` when lexing blocks. Do not recover here to avoid knockdown
1170
+ // errors which would be emitted elsewhere in the parser and let other error
1171
+ // recovery consume the rest of the file.
1172
+ Err ( err)
1173
+ } else {
1174
+ err. emit ( ) ;
1175
+ self . expected_tokens . clear ( ) ; // Reduce the number of errors.
1176
+ Ok ( true )
1177
+ }
1160
1178
}
1161
1179
_ => Err ( err) ,
1162
1180
}
1163
1181
}
1164
1182
1165
1183
/// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid.
1166
1184
pub ( super ) fn eat_bad_pub ( & mut self ) {
1167
- if self . token . is_keyword ( kw:: Pub ) {
1185
+ // When `unclosed_delims` is populated, it means that the code being parsed is already
1186
+ // quite malformed, which might mean that, for example, a pub struct definition could be
1187
+ // parsed as being a trait item, which is invalid and this error would trigger
1188
+ // unconditionally, resulting in misleading diagnostics. Because of this, we only attempt
1189
+ // this nice to have recovery for code that is otherwise well formed.
1190
+ if self . token . is_keyword ( kw:: Pub ) && self . unclosed_delims . is_empty ( ) {
1168
1191
match self . parse_visibility ( false ) {
1169
1192
Ok ( vis) => {
1170
1193
self . diagnostic ( )
@@ -1422,15 +1445,26 @@ impl<'a> Parser<'a> {
1422
1445
Ok ( param)
1423
1446
}
1424
1447
1425
- pub ( super ) fn consume_block ( & mut self , delim : token:: DelimToken ) {
1448
+ pub ( super ) fn consume_block (
1449
+ & mut self ,
1450
+ delim : token:: DelimToken ,
1451
+ consume_close : ConsumeClosingDelim ,
1452
+ ) {
1426
1453
let mut brace_depth = 0 ;
1427
1454
loop {
1428
1455
if self . eat ( & token:: OpenDelim ( delim) ) {
1429
1456
brace_depth += 1 ;
1430
- } else if self . eat ( & token:: CloseDelim ( delim) ) {
1457
+ } else if self . check ( & token:: CloseDelim ( delim) ) {
1431
1458
if brace_depth == 0 {
1459
+ if let ConsumeClosingDelim :: Yes = consume_close {
1460
+ // Some of the callers of this method expect to be able to parse the
1461
+ // closing delimiter themselves, so we leave it alone. Otherwise we advance
1462
+ // the parser.
1463
+ self . bump ( ) ;
1464
+ }
1432
1465
return ;
1433
1466
} else {
1467
+ self . bump ( ) ;
1434
1468
brace_depth -= 1 ;
1435
1469
continue ;
1436
1470
}
0 commit comments