@@ -1353,9 +1353,6 @@ impl<'a> Parser<'a> {
1353
1353
err. span_label ( sp, "while parsing this `loop` expression" ) ;
1354
1354
err
1355
1355
} )
1356
- } else if self . eat_keyword ( kw:: Continue ) {
1357
- let kind = ExprKind :: Continue ( self . eat_label ( ) ) ;
1358
- Ok ( self . mk_expr ( lo. to ( self . prev_token . span ) , kind) )
1359
1356
} else if self . eat_keyword ( kw:: Match ) {
1360
1357
let match_sp = self . prev_token . span ;
1361
1358
self . parse_match_expr ( ) . map_err ( |mut err| {
@@ -1379,6 +1376,8 @@ impl<'a> Parser<'a> {
1379
1376
self . parse_try_block ( lo)
1380
1377
} else if self . eat_keyword ( kw:: Return ) {
1381
1378
self . parse_return_expr ( )
1379
+ } else if self . eat_keyword ( kw:: Continue ) {
1380
+ self . parse_continue_expr ( lo)
1382
1381
} else if self . eat_keyword ( kw:: Break ) {
1383
1382
self . parse_break_expr ( )
1384
1383
} else if self . eat_keyword ( kw:: Yield ) {
@@ -1715,10 +1714,10 @@ impl<'a> Parser<'a> {
1715
1714
fn parse_break_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
1716
1715
let lo = self . prev_token . span ;
1717
1716
let mut label = self . eat_label ( ) ;
1718
- let kind = if label . is_some ( ) && self . token == token:: Colon {
1717
+ let kind = if self . token == token:: Colon && let Some ( label ) = label . take ( ) {
1719
1718
// The value expression can be a labeled loop, see issue #86948, e.g.:
1720
1719
// `loop { break 'label: loop { break 'label 42; }; }`
1721
- let lexpr = self . parse_labeled_expr ( label. take ( ) . unwrap ( ) , true ) ?;
1720
+ let lexpr = self . parse_labeled_expr ( label, true ) ?;
1722
1721
self . sess . emit_err ( LabeledLoopInBreak {
1723
1722
span : lexpr. span ,
1724
1723
sub : WrapExpressionInParentheses {
@@ -1730,8 +1729,8 @@ impl<'a> Parser<'a> {
1730
1729
} else if self . token != token:: OpenDelim ( Delimiter :: Brace )
1731
1730
|| !self . restrictions . contains ( Restrictions :: NO_STRUCT_LITERAL )
1732
1731
{
1733
- let expr = self . parse_expr_opt ( ) ?;
1734
- if let Some ( expr) = & expr {
1732
+ let mut expr = self . parse_expr_opt ( ) ?;
1733
+ if let Some ( expr) = & mut expr {
1735
1734
if label. is_some ( )
1736
1735
&& matches ! (
1737
1736
expr. kind,
@@ -1749,7 +1748,19 @@ impl<'a> Parser<'a> {
1749
1748
BuiltinLintDiagnostics :: BreakWithLabelAndLoop ( expr. span ) ,
1750
1749
) ;
1751
1750
}
1751
+
1752
+ // Recover `break label aaaaa`
1753
+ if self . may_recover ( )
1754
+ && let ExprKind :: Path ( None , p) = & expr. kind
1755
+ && let [ segment] = & * p. segments
1756
+ && let & ast:: PathSegment { ident, args : None , .. } = segment
1757
+ && let Some ( next) = self . parse_expr_opt ( ) ?
1758
+ {
1759
+ label = Some ( self . recover_ident_into_label ( ident) ) ;
1760
+ * expr = next;
1761
+ }
1752
1762
}
1763
+
1753
1764
expr
1754
1765
} else {
1755
1766
None
@@ -1758,6 +1769,23 @@ impl<'a> Parser<'a> {
1758
1769
self . maybe_recover_from_bad_qpath ( expr)
1759
1770
}
1760
1771
1772
+ /// Parse `"continue" label?`.
1773
+ fn parse_continue_expr ( & mut self , lo : Span ) -> PResult < ' a , P < Expr > > {
1774
+ let mut label = self . eat_label ( ) ;
1775
+
1776
+ // Recover `continue label` -> `continue 'label`
1777
+ if self . may_recover ( )
1778
+ && label. is_none ( )
1779
+ && let Some ( ( ident, _) ) = self . token . ident ( )
1780
+ {
1781
+ self . bump ( ) ;
1782
+ label = Some ( self . recover_ident_into_label ( ident) ) ;
1783
+ }
1784
+
1785
+ let kind = ExprKind :: Continue ( label) ;
1786
+ Ok ( self . mk_expr ( lo. to ( self . prev_token . span ) , kind) )
1787
+ }
1788
+
1761
1789
/// Parse `"yield" expr?`.
1762
1790
fn parse_yield_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
1763
1791
let lo = self . prev_token . span ;
@@ -3046,6 +3074,25 @@ impl<'a> Parser<'a> {
3046
3074
false
3047
3075
}
3048
3076
3077
+ /// Converts an ident into 'label and emits an "expected a label, found an identifier" error.
3078
+ fn recover_ident_into_label ( & mut self , ident : Ident ) -> Label {
3079
+ // Convert `label` -> `'label`,
3080
+ // so that nameres doesn't complain about non-existing label
3081
+ let label = format ! ( "'{}" , ident. name) ;
3082
+ let ident = Ident { name : Symbol :: intern ( & label) , span : ident. span } ;
3083
+
3084
+ self . struct_span_err ( ident. span , "expected a label, found an identifier" )
3085
+ . span_suggestion (
3086
+ ident. span ,
3087
+ "labels start with a tick" ,
3088
+ label,
3089
+ Applicability :: MachineApplicable ,
3090
+ )
3091
+ . emit ( ) ;
3092
+
3093
+ Label { ident }
3094
+ }
3095
+
3049
3096
/// Parses `ident (COLON expr)?`.
3050
3097
fn parse_expr_field ( & mut self ) -> PResult < ' a , ExprField > {
3051
3098
let attrs = self . parse_outer_attributes ( ) ?;
0 commit comments