@@ -1346,9 +1346,6 @@ impl<'a> Parser<'a> {
13461346 err. span_label ( sp, "while parsing this `loop` expression" ) ;
13471347 err
13481348 } )
1349- } else if self . eat_keyword ( kw:: Continue ) {
1350- let kind = ExprKind :: Continue ( self . eat_label ( ) ) ;
1351- Ok ( self . mk_expr ( lo. to ( self . prev_token . span ) , kind) )
13521349 } else if self . eat_keyword ( kw:: Match ) {
13531350 let match_sp = self . prev_token . span ;
13541351 self . parse_match_expr ( ) . map_err ( |mut err| {
@@ -1372,6 +1369,8 @@ impl<'a> Parser<'a> {
13721369 self . parse_try_block ( lo)
13731370 } else if self . eat_keyword ( kw:: Return ) {
13741371 self . parse_return_expr ( )
1372+ } else if self . eat_keyword ( kw:: Continue ) {
1373+ self . parse_continue_expr ( lo)
13751374 } else if self . eat_keyword ( kw:: Break ) {
13761375 self . parse_break_expr ( )
13771376 } else if self . eat_keyword ( kw:: Yield ) {
@@ -1724,8 +1723,8 @@ impl<'a> Parser<'a> {
17241723 } else if self . token != token:: OpenDelim ( Delimiter :: Brace )
17251724 || !self . restrictions . contains ( Restrictions :: NO_STRUCT_LITERAL )
17261725 {
1727- let expr = self . parse_expr_opt ( ) ?;
1728- if let Some ( expr) = & expr {
1726+ let mut expr = self . parse_expr_opt ( ) ?;
1727+ if let Some ( expr) = & mut expr {
17291728 if label. is_some ( )
17301729 && matches ! (
17311730 expr. kind,
@@ -1743,7 +1742,19 @@ impl<'a> Parser<'a> {
17431742 BuiltinLintDiagnostics :: BreakWithLabelAndLoop ( expr. span ) ,
17441743 ) ;
17451744 }
1745+
1746+ // Recover `break label aaaaa`
1747+ if self . may_recover ( )
1748+ && let ExprKind :: Path ( None , p) = & expr. kind
1749+ && let [ segment] = & * p. segments
1750+ && let & ast:: PathSegment { ident, args : None , .. } = segment
1751+ && let Some ( next) = self . parse_expr_opt ( ) ?
1752+ {
1753+ label = Some ( self . recover_ident_into_label ( ident) ) ;
1754+ * expr = next;
1755+ }
17461756 }
1757+
17471758 expr
17481759 } else {
17491760 None
@@ -1752,6 +1763,23 @@ impl<'a> Parser<'a> {
17521763 self . maybe_recover_from_bad_qpath ( expr)
17531764 }
17541765
1766+ /// Parse `"continue" label?`.
1767+ fn parse_continue_expr ( & mut self , lo : Span ) -> PResult < ' a , P < Expr > > {
1768+ let mut label = self . eat_label ( ) ;
1769+
1770+ // Recover `continue label` -> `continue 'label`
1771+ if self . may_recover ( )
1772+ && label. is_none ( )
1773+ && let Some ( ( ident, _) ) = self . token . ident ( )
1774+ {
1775+ self . bump ( ) ;
1776+ label = Some ( self . recover_ident_into_label ( ident) ) ;
1777+ }
1778+
1779+ let kind = ExprKind :: Continue ( label) ;
1780+ Ok ( self . mk_expr ( lo. to ( self . prev_token . span ) , kind) )
1781+ }
1782+
17551783 /// Parse `"yield" expr?`.
17561784 fn parse_yield_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
17571785 let lo = self . prev_token . span ;
@@ -3037,6 +3065,25 @@ impl<'a> Parser<'a> {
30373065 false
30383066 }
30393067
3068+ /// Converts an ident into 'label and emits an "expected a label, found an identifier" error.
3069+ fn recover_ident_into_label ( & mut self , ident : Ident ) -> Label {
3070+ // Convert `label` -> `'label`,
3071+ // so that nameres doesn't complain about non-existing label
3072+ let label = format ! ( "'{}" , ident. name) ;
3073+ let ident = Ident { name : Symbol :: intern ( & label) , span : ident. span } ;
3074+
3075+ self . struct_span_err ( ident. span , "expected a label, found an identifier" )
3076+ . span_suggestion (
3077+ ident. span ,
3078+ "labels start with a tick" ,
3079+ label,
3080+ Applicability :: MachineApplicable ,
3081+ )
3082+ . emit ( ) ;
3083+
3084+ Label { ident }
3085+ }
3086+
30403087 /// Parses `ident (COLON expr)?`.
30413088 fn parse_expr_field ( & mut self ) -> PResult < ' a , ExprField > {
30423089 let attrs = self . parse_outer_attributes ( ) ?;
0 commit comments