@@ -1346,9 +1346,6 @@ impl<'a> Parser<'a> {
1346
1346
err. span_label ( sp, "while parsing this `loop` expression" ) ;
1347
1347
err
1348
1348
} )
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) )
1352
1349
} else if self . eat_keyword ( kw:: Match ) {
1353
1350
let match_sp = self . prev_token . span ;
1354
1351
self . parse_match_expr ( ) . map_err ( |mut err| {
@@ -1372,6 +1369,8 @@ impl<'a> Parser<'a> {
1372
1369
self . parse_try_block ( lo)
1373
1370
} else if self . eat_keyword ( kw:: Return ) {
1374
1371
self . parse_return_expr ( )
1372
+ } else if self . eat_keyword ( kw:: Continue ) {
1373
+ self . parse_continue_expr ( lo)
1375
1374
} else if self . eat_keyword ( kw:: Break ) {
1376
1375
self . parse_break_expr ( )
1377
1376
} else if self . eat_keyword ( kw:: Yield ) {
@@ -1724,8 +1723,8 @@ impl<'a> Parser<'a> {
1724
1723
} else if self . token != token:: OpenDelim ( Delimiter :: Brace )
1725
1724
|| !self . restrictions . contains ( Restrictions :: NO_STRUCT_LITERAL )
1726
1725
{
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 {
1729
1728
if label. is_some ( )
1730
1729
&& matches ! (
1731
1730
expr. kind,
@@ -1743,7 +1742,19 @@ impl<'a> Parser<'a> {
1743
1742
BuiltinLintDiagnostics :: BreakWithLabelAndLoop ( expr. span ) ,
1744
1743
) ;
1745
1744
}
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
+ }
1746
1756
}
1757
+
1747
1758
expr
1748
1759
} else {
1749
1760
None
@@ -1752,6 +1763,23 @@ impl<'a> Parser<'a> {
1752
1763
self . maybe_recover_from_bad_qpath ( expr)
1753
1764
}
1754
1765
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
+
1755
1783
/// Parse `"yield" expr?`.
1756
1784
fn parse_yield_expr ( & mut self ) -> PResult < ' a , P < Expr > > {
1757
1785
let lo = self . prev_token . span ;
@@ -3037,6 +3065,25 @@ impl<'a> Parser<'a> {
3037
3065
false
3038
3066
}
3039
3067
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
+
3040
3087
/// Parses `ident (COLON expr)?`.
3041
3088
fn parse_expr_field ( & mut self ) -> PResult < ' a , ExprField > {
3042
3089
let attrs = self . parse_outer_attributes ( ) ?;
0 commit comments