@@ -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
}
@@ -1154,17 +1160,29 @@ impl<'a> Parser<'a> {
1154
1160
delim. to_string ( ) ,
1155
1161
Applicability :: MaybeIncorrect ,
1156
1162
) ;
1157
- err. emit ( ) ;
1158
- self . expected_tokens . clear ( ) ; // reduce errors
1159
- Ok ( true )
1163
+ if unmatched. found_delim . is_none ( ) {
1164
+ // Encountered `Eof` when lexing blocks. Do not recover here to avoid knockdown
1165
+ // errors which would be emitted elsewhere in the parser and let other error
1166
+ // recovery consume the rest of the file.
1167
+ Err ( err)
1168
+ } else {
1169
+ err. emit ( ) ;
1170
+ self . expected_tokens . clear ( ) ; // Reduce the number of errors.
1171
+ Ok ( true )
1172
+ }
1160
1173
}
1161
1174
_ => Err ( err) ,
1162
1175
}
1163
1176
}
1164
1177
1165
1178
/// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid.
1166
1179
pub ( super ) fn eat_bad_pub ( & mut self ) {
1167
- if self . token . is_keyword ( kw:: Pub ) {
1180
+ // When `unclosed_delims` is populated, it means that the code being parsed is already
1181
+ // quite malformed, which might mean that, for example, a pub struct definition could be
1182
+ // parsed as being a trait item, which is invalid and this error would trigger
1183
+ // unconditionally, resulting in misleading diagnostics. Because of this, we only attempt
1184
+ // this nice to have recovery for code that is otherwise well formed.
1185
+ if self . token . is_keyword ( kw:: Pub ) && self . unclosed_delims . is_empty ( ) {
1168
1186
match self . parse_visibility ( false ) {
1169
1187
Ok ( vis) => {
1170
1188
self . diagnostic ( )
@@ -1422,15 +1440,26 @@ impl<'a> Parser<'a> {
1422
1440
Ok ( param)
1423
1441
}
1424
1442
1425
- pub ( super ) fn consume_block ( & mut self , delim : token:: DelimToken ) {
1443
+ pub ( super ) fn consume_block (
1444
+ & mut self ,
1445
+ delim : token:: DelimToken ,
1446
+ consume_close : ConsumeClosingDelim ,
1447
+ ) {
1426
1448
let mut brace_depth = 0 ;
1427
1449
loop {
1428
1450
if self . eat ( & token:: OpenDelim ( delim) ) {
1429
1451
brace_depth += 1 ;
1430
- } else if self . eat ( & token:: CloseDelim ( delim) ) {
1452
+ } else if self . check ( & token:: CloseDelim ( delim) ) {
1431
1453
if brace_depth == 0 {
1454
+ if let ConsumeClosingDelim :: Yes = consume_close {
1455
+ // Some of the callers of this method expect to be able to parse the
1456
+ // closing delimiter themselves, so we leave it alone. Otherwise we advance
1457
+ // the parser.
1458
+ self . bump ( ) ;
1459
+ }
1432
1460
return ;
1433
1461
} else {
1462
+ self . bump ( ) ;
1434
1463
brace_depth -= 1 ;
1435
1464
continue ;
1436
1465
}
0 commit comments