about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-05 07:54:22 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-03-10 08:32:34 +0100
commit055733f3b3dc5d0841b9284da0c628f9d362461d (patch)
tree08e0b7154750bb5b34271bb2e60b0802a4a4e4b6
parent8ee220c447911c519ebbd118e1415d961317b18d (diff)
downloadrust-055733f3b3dc5d0841b9284da0c628f9d362461d.tar.gz
rust-055733f3b3dc5d0841b9284da0c628f9d362461d.zip
parse: recover on `&'lt $expr` / `'lt $expr`.
-rw-r--r--src/librustc_parse/parser/expr.rs35
-rw-r--r--src/test/ui/parser/labeled-no-colon-expr.rs17
-rw-r--r--src/test/ui/parser/labeled-no-colon-expr.stderr70
-rw-r--r--src/test/ui/parser/regions-out-of-scope-slice.rs2
-rw-r--r--src/test/ui/parser/regions-out-of-scope-slice.stderr9
-rw-r--r--src/test/ui/parser/trait-object-lifetime-parens.rs3
-rw-r--r--src/test/ui/parser/trait-object-lifetime-parens.stderr12
7 files changed, 136 insertions, 12 deletions
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index b1c5eaf8973..5b39701001f 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -673,10 +673,28 @@ impl<'a> Parser<'a> {
     /// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
     fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         self.expect_and()?;
+        let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
+        let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.
         let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo);
         let expr = self.parse_prefix_expr(None);
-        let (span, expr) = self.interpolated_or_expr_span(expr)?;
-        Ok((lo.to(span), ExprKind::AddrOf(borrow_kind, mutbl, expr)))
+        let (hi, expr) = self.interpolated_or_expr_span(expr)?;
+        let span = lo.to(hi);
+        if let Some(lt) = lifetime {
+            self.error_remove_borrow_lifetime(span, lt.ident.span);
+        }
+        Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
+    }
+
+    fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
+        self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes")
+            .span_label(lt_span, "annotated with lifetime here")
+            .span_suggestion(
+                lt_span,
+                "remove the lifetime annotation",
+                String::new(),
+                Applicability::MachineApplicable,
+            )
+            .emit();
     }
 
     /// Parse `mut?` or `raw [ const | mut ]`.
@@ -1067,11 +1085,12 @@ impl<'a> Parser<'a> {
         self.maybe_recover_from_bad_qpath(expr, true)
     }
 
+    /// Parse `'label: $expr`. The label is already parsed.
     fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = label.ident.span;
         let label = Some(label);
-        self.expect(&token::Colon)?;
-        if self.eat_keyword(kw::While) {
+        let ate_colon = self.eat(&token::Colon);
+        let expr = if self.eat_keyword(kw::While) {
             self.parse_while_expr(label, lo, attrs)
         } else if self.eat_keyword(kw::For) {
             self.parse_for_expr(label, lo, attrs)
@@ -1084,7 +1103,15 @@ impl<'a> Parser<'a> {
             self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
             // Continue as an expression in an effort to recover on `'label: non_block_expr`.
             self.parse_expr()
+        }?;
+
+        if !ate_colon {
+            self.struct_span_err(expr.span, "labeled expression must be followed by `:`")
+                .span_label(lo, "the label")
+                .emit();
         }
+
+        Ok(expr)
     }
 
     /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
diff --git a/src/test/ui/parser/labeled-no-colon-expr.rs b/src/test/ui/parser/labeled-no-colon-expr.rs
new file mode 100644
index 00000000000..db9ef52c1ae
--- /dev/null
+++ b/src/test/ui/parser/labeled-no-colon-expr.rs
@@ -0,0 +1,17 @@
+#![feature(label_break_value)]
+
+fn main() {
+    'l0 while false {} //~ ERROR labeled expression must be followed by `:`
+    'l1 for _ in 0..1 {} //~ ERROR labeled expression must be followed by `:`
+    'l2 loop {} //~ ERROR labeled expression must be followed by `:`
+    'l3 {} //~ ERROR labeled expression must be followed by `:`
+    'l4 0; //~ ERROR labeled expression must be followed by `:`
+    //~^ ERROR expected `while`, `for`, `loop` or `{`
+
+    macro_rules! m {
+        ($b:block) => {
+            'l5 $b; //~ ERROR cannot use a `block` macro fragment here
+        }
+    }
+    m!({}); //~ ERROR labeled expression must be followed by `:`
+}
diff --git a/src/test/ui/parser/labeled-no-colon-expr.stderr b/src/test/ui/parser/labeled-no-colon-expr.stderr
new file mode 100644
index 00000000000..8a9e2b32400
--- /dev/null
+++ b/src/test/ui/parser/labeled-no-colon-expr.stderr
@@ -0,0 +1,70 @@
+error: labeled expression must be followed by `:`
+  --> $DIR/labeled-no-colon-expr.rs:4:5
+   |
+LL |     'l0 while false {}
+   |     ---^^^^^^^^^^^^^^^
+   |     |
+   |     the label
+
+error: labeled expression must be followed by `:`
+  --> $DIR/labeled-no-colon-expr.rs:5:5
+   |
+LL |     'l1 for _ in 0..1 {}
+   |     ---^^^^^^^^^^^^^^^^^
+   |     |
+   |     the label
+
+error: labeled expression must be followed by `:`
+  --> $DIR/labeled-no-colon-expr.rs:6:5
+   |
+LL |     'l2 loop {}
+   |     ---^^^^^^^^
+   |     |
+   |     the label
+
+error: labeled expression must be followed by `:`
+  --> $DIR/labeled-no-colon-expr.rs:7:5
+   |
+LL |     'l3 {}
+   |     ---^^^
+   |     |
+   |     the label
+
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/labeled-no-colon-expr.rs:8:9
+   |
+LL |     'l4 0;
+   |         ^ expected `while`, `for`, `loop` or `{` after a label
+
+error: labeled expression must be followed by `:`
+  --> $DIR/labeled-no-colon-expr.rs:8:9
+   |
+LL |     'l4 0;
+   |     --- ^
+   |     |
+   |     the label
+
+error: cannot use a `block` macro fragment here
+  --> $DIR/labeled-no-colon-expr.rs:13:17
+   |
+LL |             'l5 $b;
+   |             ----^^
+   |             |
+   |             the `block` fragment is within this context
+...
+LL |     m!({});
+   |     ------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: labeled expression must be followed by `:`
+  --> $DIR/labeled-no-colon-expr.rs:16:8
+   |
+LL |             'l5 $b;
+   |             --- the label
+...
+LL |     m!({});
+   |        ^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/parser/regions-out-of-scope-slice.rs b/src/test/ui/parser/regions-out-of-scope-slice.rs
index 21369d0be61..d223619e1de 100644
--- a/src/test/ui/parser/regions-out-of-scope-slice.rs
+++ b/src/test/ui/parser/regions-out-of-scope-slice.rs
@@ -4,7 +4,7 @@ fn foo(cond: bool) {
     let mut x;
 
     if cond {
-        x = &'blk [1,2,3]; //~ ERROR expected `:`, found `[`
+        x = &'blk [1,2,3]; //~ ERROR borrow expressions cannot be annotated with lifetimes
     }
 }
 
diff --git a/src/test/ui/parser/regions-out-of-scope-slice.stderr b/src/test/ui/parser/regions-out-of-scope-slice.stderr
index 8d9bf0b7a04..bbc657ffd61 100644
--- a/src/test/ui/parser/regions-out-of-scope-slice.stderr
+++ b/src/test/ui/parser/regions-out-of-scope-slice.stderr
@@ -1,8 +1,11 @@
-error: expected `:`, found `[`
-  --> $DIR/regions-out-of-scope-slice.rs:7:19
+error: borrow expressions cannot be annotated with lifetimes
+  --> $DIR/regions-out-of-scope-slice.rs:7:13
    |
 LL |         x = &'blk [1,2,3];
-   |                   ^ expected `:`
+   |             ^----^^^^^^^^
+   |              |
+   |              annotated with lifetime here
+   |              help: remove the lifetime annotation
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/trait-object-lifetime-parens.rs b/src/test/ui/parser/trait-object-lifetime-parens.rs
index c8b0eb684f3..dbed17f634a 100644
--- a/src/test/ui/parser/trait-object-lifetime-parens.rs
+++ b/src/test/ui/parser/trait-object-lifetime-parens.rs
@@ -8,7 +8,8 @@ fn check<'a>() {
     let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
     let _: Box<('a) + Trait>;
     //~^ ERROR expected type, found `'a`
-    //~| ERROR expected `:`, found `)`
+    //~| ERROR expected `while`, `for`, `loop` or `{` after a label
+    //~| ERROR expected expression, found `)`
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr
index 319a308c013..367fcc28555 100644
--- a/src/test/ui/parser/trait-object-lifetime-parens.stderr
+++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr
@@ -10,11 +10,17 @@ error: parenthesized lifetime bounds are not supported
 LL |     let _: Box<Trait + ('a)>;
    |                        ^^^^ help: remove the parentheses
 
-error: expected `:`, found `)`
+error: expected `while`, `for`, `loop` or `{` after a label
   --> $DIR/trait-object-lifetime-parens.rs:9:19
    |
 LL |     let _: Box<('a) + Trait>;
-   |                   ^ expected `:`
+   |                   ^ expected `while`, `for`, `loop` or `{` after a label
+
+error: expected expression, found `)`
+  --> $DIR/trait-object-lifetime-parens.rs:9:19
+   |
+LL |     let _: Box<('a) + Trait>;
+   |                   ^ expected expression
 
 error: expected type, found `'a`
   --> $DIR/trait-object-lifetime-parens.rs:9:17
@@ -24,5 +30,5 @@ LL |     let _: Box<('a) + Trait>;
    |         |
    |         while parsing the type for `_`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors