about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/parser/expr.rs')
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs54
1 files changed, 48 insertions, 6 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 47869f775fe..cfd7ad48222 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -585,7 +585,7 @@ impl<'a> Parser<'a> {
         lhs_span: Span,
         expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
     ) -> PResult<'a, P<Expr>> {
-        let mk_expr = |this: &mut Self, rhs: P<Ty>| {
+        let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
             this.mk_expr(
                 this.mk_expr_sp(&lhs, lhs_span, rhs.span),
                 expr_kind(lhs, rhs),
@@ -597,13 +597,49 @@ impl<'a> Parser<'a> {
         // LessThan comparison after this cast.
         let parser_snapshot_before_type = self.clone();
         let cast_expr = match self.parse_ty_no_plus() {
-            Ok(rhs) => mk_expr(self, rhs),
+            Ok(rhs) => mk_expr(self, lhs, rhs),
             Err(mut type_err) => {
                 // Rewind to before attempting to parse the type with generics, to recover
                 // from situations like `x as usize < y` in which we first tried to parse
                 // `usize < y` as a type with generic arguments.
                 let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
 
+                // Check for typo of `'a: loop { break 'a }` with a missing `'`.
+                match (&lhs.kind, &self.token.kind) {
+                    (
+                        // `foo: `
+                        ExprKind::Path(None, ast::Path { segments, .. }),
+                        TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
+                    ) if segments.len() == 1 => {
+                        let snapshot = self.clone();
+                        let label = Label {
+                            ident: Ident::from_str_and_span(
+                                &format!("'{}", segments[0].ident),
+                                segments[0].ident.span,
+                            ),
+                        };
+                        match self.parse_labeled_expr(label, AttrVec::new(), false) {
+                            Ok(expr) => {
+                                type_err.cancel();
+                                self.struct_span_err(label.ident.span, "malformed loop label")
+                                    .span_suggestion(
+                                        label.ident.span,
+                                        "use the correct loop label format",
+                                        label.ident.to_string(),
+                                        Applicability::MachineApplicable,
+                                    )
+                                    .emit();
+                                return Ok(expr);
+                            }
+                            Err(mut err) => {
+                                err.cancel();
+                                *self = snapshot;
+                            }
+                        }
+                    }
+                    _ => {}
+                }
+
                 match self.parse_path(PathStyle::Expr) {
                     Ok(path) => {
                         let (op_noun, op_verb) = match self.token.kind {
@@ -630,7 +666,8 @@ impl<'a> Parser<'a> {
                             op_noun,
                         );
                         let span_after_type = parser_snapshot_after_type.token.span;
-                        let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path)));
+                        let expr =
+                            mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
 
                         let expr_str = self
                             .span_to_snippet(expr.span)
@@ -1067,7 +1104,7 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(kw::While) {
             self.parse_while_expr(None, self.prev_token.span, attrs)
         } else if let Some(label) = self.eat_label() {
-            self.parse_labeled_expr(label, attrs)
+            self.parse_labeled_expr(label, attrs, true)
         } else if self.eat_keyword(kw::Loop) {
             self.parse_loop_expr(None, self.prev_token.span, attrs)
         } else if self.eat_keyword(kw::Continue) {
@@ -1228,7 +1265,12 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse `'label: $expr`. The label is already parsed.
-    fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+    fn parse_labeled_expr(
+        &mut self,
+        label: Label,
+        attrs: AttrVec,
+        consume_colon: bool,
+    ) -> PResult<'a, P<Expr>> {
         let lo = label.ident.span;
         let label = Some(label);
         let ate_colon = self.eat(&token::Colon);
@@ -1247,7 +1289,7 @@ impl<'a> Parser<'a> {
             self.parse_expr()
         }?;
 
-        if !ate_colon {
+        if !ate_colon && consume_colon {
             self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
         }