@@ -171,6 +171,12 @@ impl RecoverQPath for Expr {
171171 }
172172}
173173
174+ /// Control whether the closing delimiter should be consumed when calling `Parser::consume_block`.
175+ crate enum ConsumeClosingDelim {
176+ Yes ,
177+ No ,
178+ }
179+
174180impl < ' a > Parser < ' a > {
175181 pub fn fatal ( & self , m : & str ) -> DiagnosticBuilder < ' a > {
176182 self . span_fatal ( self . token . span , m)
@@ -1105,8 +1111,8 @@ impl<'a> Parser<'a> {
11051111 Ok ( x) => x,
11061112 Err ( mut err) => {
11071113 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 ) ;
11101116 self . mk_expr ( lo. to ( self . prev_span ) , ExprKind :: Err , ThinVec :: new ( ) )
11111117 }
11121118 }
@@ -1154,17 +1160,29 @@ impl<'a> Parser<'a> {
11541160 delim. to_string ( ) ,
11551161 Applicability :: MaybeIncorrect ,
11561162 ) ;
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+ }
11601173 }
11611174 _ => Err ( err) ,
11621175 }
11631176 }
11641177
11651178 /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid.
11661179 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 ( ) {
11681186 match self . parse_visibility ( false ) {
11691187 Ok ( vis) => {
11701188 self . diagnostic ( )
@@ -1422,15 +1440,26 @@ impl<'a> Parser<'a> {
14221440 Ok ( param)
14231441 }
14241442
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+ ) {
14261448 let mut brace_depth = 0 ;
14271449 loop {
14281450 if self . eat ( & token:: OpenDelim ( delim) ) {
14291451 brace_depth += 1 ;
1430- } else if self . eat ( & token:: CloseDelim ( delim) ) {
1452+ } else if self . check ( & token:: CloseDelim ( delim) ) {
14311453 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+ }
14321460 return ;
14331461 } else {
1462+ self . bump ( ) ;
14341463 brace_depth -= 1 ;
14351464 continue ;
14361465 }
0 commit comments