about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs61
-rw-r--r--src/test/ui/parser/keyword-box-as-identifier.rs9
-rw-r--r--src/test/ui/parser/keyword-box-as-identifier.stderr64
3 files changed, 126 insertions, 8 deletions
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 2ad3f3ec19d..ca7915ed17a 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -360,10 +360,7 @@ impl<'a> Parser<'a> {
             let mutbl = self.parse_mutability();
             self.parse_pat_ident(BindingMode::ByRef(mutbl))?
         } else if self.eat_keyword(kw::Box) {
-            // Parse `box pat`
-            let pat = self.parse_pat_with_range_pat(false, None)?;
-            self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span));
-            PatKind::Box(pat)
+            self.parse_pat_box()?
         } else if self.check_inline_const(0) {
             // Parse `const pat`
             let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
@@ -915,6 +912,62 @@ impl<'a> Parser<'a> {
         Ok(PatKind::TupleStruct(qself, path, fields))
     }
 
+    /// Are we sure this could not possibly be the start of a pattern?
+    ///
+    /// Currently, this only accounts for tokens that can follow identifiers
+    /// in patterns, but this can be extended as necessary.
+    fn isnt_pattern_start(&self) -> bool {
+        [
+            token::Eq,
+            token::Colon,
+            token::Comma,
+            token::Semi,
+            token::At,
+            token::OpenDelim(Delimiter::Brace),
+            token::CloseDelim(Delimiter::Brace),
+            token::CloseDelim(Delimiter::Parenthesis),
+        ]
+        .contains(&self.token.kind)
+    }
+
+    /// Parses `box pat`
+    fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
+        let box_span = self.prev_token.span;
+
+        if self.isnt_pattern_start() {
+            self.struct_span_err(
+                self.token.span,
+                format!("expected pattern, found {}", super::token_descr(&self.token)),
+            )
+            .span_note(box_span, "`box` is a reserved keyword")
+            .span_suggestion_verbose(
+                box_span.shrink_to_lo(),
+                "escape `box` to use it as an identifier",
+                "r#",
+                Applicability::MaybeIncorrect,
+            )
+            .emit();
+
+            // We cannot use `parse_pat_ident()` since it will complain `box`
+            // is not an identifier.
+            let sub = if self.eat(&token::At) {
+                Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
+            } else {
+                None
+            };
+
+            Ok(PatKind::Ident(
+                BindingMode::ByValue(Mutability::Not),
+                Ident::new(kw::Box, box_span),
+                sub,
+            ))
+        } else {
+            let pat = self.parse_pat_with_range_pat(false, None)?;
+            self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
+            Ok(PatKind::Box(pat))
+        }
+    }
+
     /// Parses the fields of a struct-like pattern.
     fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
         let mut fields = Vec::new();
diff --git a/src/test/ui/parser/keyword-box-as-identifier.rs b/src/test/ui/parser/keyword-box-as-identifier.rs
index 33961bb3084..2cf49b66be6 100644
--- a/src/test/ui/parser/keyword-box-as-identifier.rs
+++ b/src/test/ui/parser/keyword-box-as-identifier.rs
@@ -1,3 +1,10 @@
 fn main() {
-    let box = "foo"; //~ error: expected pattern, found `=`
+    let box = 0;
+    //~^ ERROR expected pattern, found `=`
+    let box: bool;
+    //~^ ERROR expected pattern, found `:`
+    let mut box = 0;
+    //~^ ERROR expected pattern, found `=`
+    let (box,) = (0,);
+    //~^ ERROR expected pattern, found `,`
 }
diff --git a/src/test/ui/parser/keyword-box-as-identifier.stderr b/src/test/ui/parser/keyword-box-as-identifier.stderr
index 8b185948498..eaa1f8003c5 100644
--- a/src/test/ui/parser/keyword-box-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-box-as-identifier.stderr
@@ -1,8 +1,66 @@
 error: expected pattern, found `=`
   --> $DIR/keyword-box-as-identifier.rs:2:13
    |
-LL |     let box = "foo";
-   |             ^ expected pattern
+LL |     let box = 0;
+   |             ^
+   |
+note: `box` is a reserved keyword
+  --> $DIR/keyword-box-as-identifier.rs:2:9
+   |
+LL |     let box = 0;
+   |         ^^^
+help: escape `box` to use it as an identifier
+   |
+LL |     let r#box = 0;
+   |         ++
+
+error: expected pattern, found `:`
+  --> $DIR/keyword-box-as-identifier.rs:4:12
+   |
+LL |     let box: bool;
+   |            ^
+   |
+note: `box` is a reserved keyword
+  --> $DIR/keyword-box-as-identifier.rs:4:9
+   |
+LL |     let box: bool;
+   |         ^^^
+help: escape `box` to use it as an identifier
+   |
+LL |     let r#box: bool;
+   |         ++
+
+error: expected pattern, found `=`
+  --> $DIR/keyword-box-as-identifier.rs:6:17
+   |
+LL |     let mut box = 0;
+   |                 ^
+   |
+note: `box` is a reserved keyword
+  --> $DIR/keyword-box-as-identifier.rs:6:13
+   |
+LL |     let mut box = 0;
+   |             ^^^
+help: escape `box` to use it as an identifier
+   |
+LL |     let mut r#box = 0;
+   |             ++
+
+error: expected pattern, found `,`
+  --> $DIR/keyword-box-as-identifier.rs:8:13
+   |
+LL |     let (box,) = (0,);
+   |             ^
+   |
+note: `box` is a reserved keyword
+  --> $DIR/keyword-box-as-identifier.rs:8:10
+   |
+LL |     let (box,) = (0,);
+   |          ^^^
+help: escape `box` to use it as an identifier
+   |
+LL |     let (r#box,) = (0,);
+   |          ++
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors