about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-08-27 13:04:48 +0200
committerMazdak Farrokhzad <twingoow@gmail.com>2019-08-27 13:04:48 +0200
commitf908aa9e8000dd7fd2c3de54fe1d914fddf4fe92 (patch)
treeedc7953aea9c42c82aa3c9a0e6b7f7d5d75413f3 /src
parente49b9581baba9d89519d17ac0d8400b6ae77e754 (diff)
downloadrust-f908aa9e8000dd7fd2c3de54fe1d914fddf4fe92.tar.gz
rust-f908aa9e8000dd7fd2c3de54fe1d914fddf4fe92.zip
recover on 'mut ' and improve recovery for keywords.
Diffstat (limited to 'src')
-rw-r--r--src/libsyntax/parse/parser/pat.rs136
-rw-r--r--src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs2
-rw-r--r--src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr8
-rw-r--r--src/test/ui/parser/issue-32501.rs3
-rw-r--r--src/test/ui/parser/issue-32501.stderr6
-rw-r--r--src/test/ui/parser/keyword-abstract.rs2
-rw-r--r--src/test/ui/parser/keyword-abstract.stderr8
-rw-r--r--src/test/ui/parser/keyword-as-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-as-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-break-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-break-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-const-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-const-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-continue-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-continue-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-else-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-else-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-enum-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-enum-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-final.rs2
-rw-r--r--src/test/ui/parser/keyword-final.stderr8
-rw-r--r--src/test/ui/parser/keyword-fn-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-fn-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-for-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-for-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-if-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-if-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-impl-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-impl-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-let-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-let-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-loop-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-loop-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-match-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-match-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-mod-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-mod-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-move-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-move-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-override.rs2
-rw-r--r--src/test/ui/parser/keyword-override.stderr8
-rw-r--r--src/test/ui/parser/keyword-pub-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-pub-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-return-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-return-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-static-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-static-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-struct-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-struct-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-trait-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-trait-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-try-as-identifier-edition2018.rs2
-rw-r--r--src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr8
-rw-r--r--src/test/ui/parser/keyword-type-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-type-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-typeof.rs2
-rw-r--r--src/test/ui/parser/keyword-typeof.stderr8
-rw-r--r--src/test/ui/parser/keyword-unsafe-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-unsafe-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-use-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-use-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-where-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-where-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/keyword-while-as-identifier.rs2
-rw-r--r--src/test/ui/parser/keyword-while-as-identifier.stderr8
-rw-r--r--src/test/ui/parser/mut-patterns.rs30
-rw-r--r--src/test/ui/parser/mut-patterns.stderr68
-rw-r--r--src/test/ui/reserved/reserved-become.rs2
-rw-r--r--src/test/ui/reserved/reserved-become.stderr8
-rw-r--r--src/test/ui/self/self_type_keyword.rs3
-rw-r--r--src/test/ui/self/self_type_keyword.stderr30
71 files changed, 449 insertions, 147 deletions
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index 78c9a289b37..7b228a700a7 100644
--- a/src/libsyntax/parse/parser/pat.rs
+++ b/src/libsyntax/parse/parser/pat.rs
@@ -4,6 +4,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use crate::ptr::P;
 use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac};
 use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind};
+use crate::mut_visit::{noop_visit_pat, MutVisitor};
 use crate::parse::token::{self};
 use crate::print::pprust;
 use crate::source_map::{respan, Span, Spanned};
@@ -273,7 +274,7 @@ impl<'a> Parser<'a> {
                 // Parse _
                 PatKind::Wild
             } else if self.eat_keyword(kw::Mut) {
-                self.recover_pat_ident_mut_first()?
+                self.parse_pat_ident_mut()?
             } else if self.eat_keyword(kw::Ref) {
                 // Parse ref ident @ pat / ref mut ident @ pat
                 let mutbl = self.parse_mutability();
@@ -281,13 +282,12 @@ impl<'a> Parser<'a> {
             } else if self.eat_keyword(kw::Box) {
                 // Parse `box pat`
                 PatKind::Box(self.parse_pat_with_range_pat(false, None)?)
-            } else if self.token.is_ident() && !self.token.is_reserved_ident() &&
-                      self.parse_as_ident() {
+            } else if self.can_be_ident_pat() {
                 // Parse `ident @ pat`
                 // This can give false positives and parse nullary enums,
                 // they are dealt with later in resolve.
                 self.parse_pat_ident(BindingMode::ByValue(Mutability::Immutable))?
-            } else if self.token.is_path_start() {
+            } else if self.is_start_of_pat_with_path() {
                 // Parse pattern starting with a path
                 let (qself, path) = if self.eat_lt() {
                     // Parse a qualified path
@@ -384,24 +384,85 @@ impl<'a> Parser<'a> {
         })
     }
 
+    fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
+        let mut_span = self.prev_span;
+
+        if self.eat_keyword(kw::Ref) {
+            return self.recover_mut_ref_ident(mut_span)
+        }
+
+        self.recover_additional_muts();
+
+        let mut pat = self.parse_pat(Some("identifier"))?;
+
+        // Add `mut` to any binding in the parsed pattern.
+        struct AddMut;
+        impl MutVisitor for AddMut {
+            fn visit_pat(&mut self, pat: &mut P<Pat>) {
+                if let PatKind::Ident(BindingMode::ByValue(ref mut m), ..) = pat.node {
+                    *m = Mutability::Mutable;
+                }
+                noop_visit_pat(pat, self);
+            }
+        }
+        AddMut.visit_pat(&mut pat);
+
+        // Unwrap; If we don't have `mut $ident`, error.
+        let pat = pat.into_inner();
+        match &pat.node {
+            PatKind::Ident(..) => {}
+            _ => self.ban_mut_general_pat(mut_span, &pat),
+        }
+
+        Ok(pat.node)
+    }
+
     /// Recover on `mut ref? ident @ pat` and suggest
     /// that the order of `mut` and `ref` is incorrect.
-    fn recover_pat_ident_mut_first(&mut self) -> PResult<'a, PatKind> {
-        let mutref_span = self.prev_span.to(self.token.span);
-        let binding_mode = if self.eat_keyword(kw::Ref) {
-            self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
-                .span_suggestion(
-                    mutref_span,
-                    "try switching the order",
-                    "ref mut".into(),
-                    Applicability::MachineApplicable
-                )
-                .emit();
-            BindingMode::ByRef(Mutability::Mutable)
-        } else {
-            BindingMode::ByValue(Mutability::Mutable)
-        };
-        self.parse_pat_ident(binding_mode)
+    fn recover_mut_ref_ident(&mut self, lo: Span) -> PResult<'a, PatKind> {
+        let mutref_span = lo.to(self.prev_span);
+        self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect")
+            .span_suggestion(
+                mutref_span,
+                "try switching the order",
+                "ref mut".into(),
+                Applicability::MachineApplicable
+            )
+            .emit();
+
+        self.parse_pat_ident(BindingMode::ByRef(Mutability::Mutable))
+    }
+
+    /// Error on `mut $pat` where `$pat` is not an ident.
+    fn ban_mut_general_pat(&self, lo: Span, pat: &Pat) {
+        let span = lo.to(pat.span);
+        self.struct_span_err(span, "`mut` must be attached to each individual binding")
+            .span_suggestion(
+                span,
+                "add `mut` to each binding",
+                pprust::pat_to_string(&pat),
+                Applicability::MachineApplicable,
+            )
+            .emit();
+    }
+
+    /// Eat any extraneous `mut`s and error + recover if we ate any.
+    fn recover_additional_muts(&mut self) {
+        let lo = self.token.span;
+        while self.eat_keyword(kw::Mut) {}
+        if lo == self.token.span {
+            return;
+        }
+
+        let span = lo.to(self.prev_span);
+        self.struct_span_err(span, "`mut` on a binding may not be repeated")
+            .span_suggestion(
+                span,
+                "remove the additional `mut`s",
+                String::new(),
+                Applicability::MachineApplicable,
+            )
+            .emit();
     }
 
     /// Parse macro invocation
@@ -479,17 +540,6 @@ impl<'a> Parser<'a> {
         Err(err)
     }
 
-    // Helper function to decide whether to parse as ident binding
-    // or to try to do something more complex like range patterns.
-    fn parse_as_ident(&mut self) -> bool {
-        self.look_ahead(1, |t| match t.kind {
-            token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
-            token::DotDotDot | token::DotDotEq | token::DotDot |
-            token::ModSep | token::Not => false,
-            _ => true,
-        })
-    }
-
     /// Is the current token suitable as the start of a range patterns end?
     fn is_pat_range_end_start(&self) -> bool {
         self.token.is_path_start() // e.g. `MY_CONST`;
@@ -563,6 +613,30 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Is this the start of a pattern beginning with a path?
+    fn is_start_of_pat_with_path(&mut self) -> bool {
+        self.check_path()
+        // Just for recovery (see `can_be_ident`).
+        || self.token.is_ident() && !self.token.is_bool_lit() && !self.token.is_keyword(kw::In)
+    }
+
+    /// Would `parse_pat_ident` be appropriate here?
+    fn can_be_ident_pat(&mut self) -> bool {
+        self.check_ident()
+        && !self.token.is_bool_lit() // Avoid `true` or `false` as a binding as it is a literal.
+        && !self.token.is_path_segment_keyword() // Avoid e.g. `Self` as it is a path.
+        // Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`.
+        && !self.token.is_keyword(kw::In)
+        && self.look_ahead(1, |t| match t.kind { // Try to do something more complex?
+            token::OpenDelim(token::Paren) // A tuple struct pattern.
+            | token::OpenDelim(token::Brace) // A struct pattern.
+            | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern.
+            | token::ModSep // A tuple / struct variant pattern.
+            | token::Not => false, // A macro expanding to a pattern.
+            _ => true,
+        })
+    }
+
     /// Parses `ident` or `ident @ pat`.
     /// Used by the copy foo and ref foo patterns to give a good
     /// error message when parsing mistakes like `ref foo(a, b)`.
diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs
index f9b6bad7c25..8a420f7203c 100644
--- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs
+++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs
@@ -1,3 +1,3 @@
 fn main() {
-    let extern = 0; //~ ERROR expected pattern, found keyword `extern`
+    let extern = 0; //~ ERROR expected identifier, found keyword `extern`
 }
diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr
index d7b9ad2abe9..73ac113f1b1 100644
--- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr
+++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `extern`
+error: expected identifier, found keyword `extern`
   --> $DIR/keyword-extern-as-identifier-pat.rs:2:9
    |
 LL |     let extern = 0;
-   |         ^^^^^^ expected pattern
+   |         ^^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#extern = 0;
+   |         ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-32501.rs b/src/test/ui/parser/issue-32501.rs
index 9c01a5c6d20..695baf81872 100644
--- a/src/test/ui/parser/issue-32501.rs
+++ b/src/test/ui/parser/issue-32501.rs
@@ -4,5 +4,6 @@ fn main() {
     let _ = 0;
     let mut b = 0;
     let mut _b = 0;
-    let mut _ = 0; //~ ERROR expected identifier, found reserved identifier `_`
+    let mut _ = 0;
+    //~^ ERROR `mut` must be attached to each individual binding
 }
diff --git a/src/test/ui/parser/issue-32501.stderr b/src/test/ui/parser/issue-32501.stderr
index 97efb895935..f5d3300cf9c 100644
--- a/src/test/ui/parser/issue-32501.stderr
+++ b/src/test/ui/parser/issue-32501.stderr
@@ -1,8 +1,8 @@
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-32501.rs:7:13
+error: `mut` must be attached to each individual binding
+  --> $DIR/issue-32501.rs:7:9
    |
 LL |     let mut _ = 0;
-   |             ^ expected identifier, found reserved identifier
+   |         ^^^^^ help: add `mut` to each binding: `_`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-abstract.rs b/src/test/ui/parser/keyword-abstract.rs
index 890802ac134..570206575ab 100644
--- a/src/test/ui/parser/keyword-abstract.rs
+++ b/src/test/ui/parser/keyword-abstract.rs
@@ -1,3 +1,3 @@
 fn main() {
-    let abstract = (); //~ ERROR expected pattern, found reserved keyword `abstract`
+    let abstract = (); //~ ERROR expected identifier, found reserved keyword `abstract`
 }
diff --git a/src/test/ui/parser/keyword-abstract.stderr b/src/test/ui/parser/keyword-abstract.stderr
index 2c79598a81b..eb2c810099e 100644
--- a/src/test/ui/parser/keyword-abstract.stderr
+++ b/src/test/ui/parser/keyword-abstract.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found reserved keyword `abstract`
+error: expected identifier, found reserved keyword `abstract`
   --> $DIR/keyword-abstract.rs:2:9
    |
 LL |     let abstract = ();
-   |         ^^^^^^^^ expected pattern
+   |         ^^^^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#abstract = ();
+   |         ^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-as-as-identifier.rs b/src/test/ui/parser/keyword-as-as-identifier.rs
index 23ff259db30..cd47c8a3907 100644
--- a/src/test/ui/parser/keyword-as-as-identifier.rs
+++ b/src/test/ui/parser/keyword-as-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py as'
 
 fn main() {
-    let as = "foo"; //~ error: expected pattern, found keyword `as`
+    let as = "foo"; //~ error: expected identifier, found keyword `as`
 }
diff --git a/src/test/ui/parser/keyword-as-as-identifier.stderr b/src/test/ui/parser/keyword-as-as-identifier.stderr
index ef466488ad0..5648652be9b 100644
--- a/src/test/ui/parser/keyword-as-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-as-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `as`
+error: expected identifier, found keyword `as`
   --> $DIR/keyword-as-as-identifier.rs:4:9
    |
 LL |     let as = "foo";
-   |         ^^ expected pattern
+   |         ^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#as = "foo";
+   |         ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-break-as-identifier.rs b/src/test/ui/parser/keyword-break-as-identifier.rs
index 5ee111d38c9..04b25a7aaf6 100644
--- a/src/test/ui/parser/keyword-break-as-identifier.rs
+++ b/src/test/ui/parser/keyword-break-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py break'
 
 fn main() {
-    let break = "foo"; //~ error: expected pattern, found keyword `break`
+    let break = "foo"; //~ error: expected identifier, found keyword `break`
 }
diff --git a/src/test/ui/parser/keyword-break-as-identifier.stderr b/src/test/ui/parser/keyword-break-as-identifier.stderr
index 690bd84221a..820193db70b 100644
--- a/src/test/ui/parser/keyword-break-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-break-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `break`
+error: expected identifier, found keyword `break`
   --> $DIR/keyword-break-as-identifier.rs:4:9
    |
 LL |     let break = "foo";
-   |         ^^^^^ expected pattern
+   |         ^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#break = "foo";
+   |         ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-const-as-identifier.rs b/src/test/ui/parser/keyword-const-as-identifier.rs
index 48fc142cf64..6a2d926bf57 100644
--- a/src/test/ui/parser/keyword-const-as-identifier.rs
+++ b/src/test/ui/parser/keyword-const-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py const'
 
 fn main() {
-    let const = "foo"; //~ error: expected pattern, found keyword `const`
+    let const = "foo"; //~ error: expected identifier, found keyword `const`
 }
diff --git a/src/test/ui/parser/keyword-const-as-identifier.stderr b/src/test/ui/parser/keyword-const-as-identifier.stderr
index 6da47f88d04..95b536c99c7 100644
--- a/src/test/ui/parser/keyword-const-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-const-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `const`
+error: expected identifier, found keyword `const`
   --> $DIR/keyword-const-as-identifier.rs:4:9
    |
 LL |     let const = "foo";
-   |         ^^^^^ expected pattern
+   |         ^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#const = "foo";
+   |         ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-continue-as-identifier.rs b/src/test/ui/parser/keyword-continue-as-identifier.rs
index 06315a48349..cfdd62a2d1b 100644
--- a/src/test/ui/parser/keyword-continue-as-identifier.rs
+++ b/src/test/ui/parser/keyword-continue-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py continue'
 
 fn main() {
-    let continue = "foo"; //~ error: expected pattern, found keyword `continue`
+    let continue = "foo"; //~ error: expected identifier, found keyword `continue`
 }
diff --git a/src/test/ui/parser/keyword-continue-as-identifier.stderr b/src/test/ui/parser/keyword-continue-as-identifier.stderr
index 4b0a659f9ad..6b24422a555 100644
--- a/src/test/ui/parser/keyword-continue-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-continue-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `continue`
+error: expected identifier, found keyword `continue`
   --> $DIR/keyword-continue-as-identifier.rs:4:9
    |
 LL |     let continue = "foo";
-   |         ^^^^^^^^ expected pattern
+   |         ^^^^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#continue = "foo";
+   |         ^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-else-as-identifier.rs b/src/test/ui/parser/keyword-else-as-identifier.rs
index 0c69105cf94..f12dac3ff75 100644
--- a/src/test/ui/parser/keyword-else-as-identifier.rs
+++ b/src/test/ui/parser/keyword-else-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py else'
 
 fn main() {
-    let else = "foo"; //~ error: expected pattern, found keyword `else`
+    let else = "foo"; //~ error: expected identifier, found keyword `else`
 }
diff --git a/src/test/ui/parser/keyword-else-as-identifier.stderr b/src/test/ui/parser/keyword-else-as-identifier.stderr
index bec7b7ba01e..f28635cd08c 100644
--- a/src/test/ui/parser/keyword-else-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-else-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `else`
+error: expected identifier, found keyword `else`
   --> $DIR/keyword-else-as-identifier.rs:4:9
    |
 LL |     let else = "foo";
-   |         ^^^^ expected pattern
+   |         ^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#else = "foo";
+   |         ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-enum-as-identifier.rs b/src/test/ui/parser/keyword-enum-as-identifier.rs
index d1675800a27..fe66230d028 100644
--- a/src/test/ui/parser/keyword-enum-as-identifier.rs
+++ b/src/test/ui/parser/keyword-enum-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py enum'
 
 fn main() {
-    let enum = "foo"; //~ error: expected pattern, found keyword `enum`
+    let enum = "foo"; //~ error: expected identifier, found keyword `enum`
 }
diff --git a/src/test/ui/parser/keyword-enum-as-identifier.stderr b/src/test/ui/parser/keyword-enum-as-identifier.stderr
index 51a834f797c..fc54dce1b68 100644
--- a/src/test/ui/parser/keyword-enum-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-enum-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `enum`
+error: expected identifier, found keyword `enum`
   --> $DIR/keyword-enum-as-identifier.rs:4:9
    |
 LL |     let enum = "foo";
-   |         ^^^^ expected pattern
+   |         ^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#enum = "foo";
+   |         ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-final.rs b/src/test/ui/parser/keyword-final.rs
index e1cecd0e8e0..a79a11032a0 100644
--- a/src/test/ui/parser/keyword-final.rs
+++ b/src/test/ui/parser/keyword-final.rs
@@ -1,3 +1,3 @@
 fn main() {
-    let final = (); //~ ERROR expected pattern, found reserved keyword `final`
+    let final = (); //~ ERROR expected identifier, found reserved keyword `final`
 }
diff --git a/src/test/ui/parser/keyword-final.stderr b/src/test/ui/parser/keyword-final.stderr
index e8372643be6..291710d05cb 100644
--- a/src/test/ui/parser/keyword-final.stderr
+++ b/src/test/ui/parser/keyword-final.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found reserved keyword `final`
+error: expected identifier, found reserved keyword `final`
   --> $DIR/keyword-final.rs:2:9
    |
 LL |     let final = ();
-   |         ^^^^^ expected pattern
+   |         ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#final = ();
+   |         ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-fn-as-identifier.rs b/src/test/ui/parser/keyword-fn-as-identifier.rs
index bca2d5996a5..f30e115f794 100644
--- a/src/test/ui/parser/keyword-fn-as-identifier.rs
+++ b/src/test/ui/parser/keyword-fn-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py fn'
 
 fn main() {
-    let fn = "foo"; //~ error: expected pattern, found keyword `fn`
+    let fn = "foo"; //~ error: expected identifier, found keyword `fn`
 }
diff --git a/src/test/ui/parser/keyword-fn-as-identifier.stderr b/src/test/ui/parser/keyword-fn-as-identifier.stderr
index a071a40a70e..692f195b288 100644
--- a/src/test/ui/parser/keyword-fn-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-fn-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `fn`
+error: expected identifier, found keyword `fn`
   --> $DIR/keyword-fn-as-identifier.rs:4:9
    |
 LL |     let fn = "foo";
-   |         ^^ expected pattern
+   |         ^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#fn = "foo";
+   |         ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-for-as-identifier.rs b/src/test/ui/parser/keyword-for-as-identifier.rs
index ce49fd90d91..9e8a2ad5342 100644
--- a/src/test/ui/parser/keyword-for-as-identifier.rs
+++ b/src/test/ui/parser/keyword-for-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py for'
 
 fn main() {
-    let for = "foo"; //~ error: expected pattern, found keyword `for`
+    let for = "foo"; //~ error: expected identifier, found keyword `for`
 }
diff --git a/src/test/ui/parser/keyword-for-as-identifier.stderr b/src/test/ui/parser/keyword-for-as-identifier.stderr
index 090046cebdc..bcaf421286e 100644
--- a/src/test/ui/parser/keyword-for-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-for-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `for`
+error: expected identifier, found keyword `for`
   --> $DIR/keyword-for-as-identifier.rs:4:9
    |
 LL |     let for = "foo";
-   |         ^^^ expected pattern
+   |         ^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#for = "foo";
+   |         ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-if-as-identifier.rs b/src/test/ui/parser/keyword-if-as-identifier.rs
index a1302970689..0bd5756afce 100644
--- a/src/test/ui/parser/keyword-if-as-identifier.rs
+++ b/src/test/ui/parser/keyword-if-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py if'
 
 fn main() {
-    let if = "foo"; //~ error: expected pattern, found keyword `if`
+    let if = "foo"; //~ error: expected identifier, found keyword `if`
 }
diff --git a/src/test/ui/parser/keyword-if-as-identifier.stderr b/src/test/ui/parser/keyword-if-as-identifier.stderr
index 98bfdb46e97..43fbcd7148a 100644
--- a/src/test/ui/parser/keyword-if-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-if-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `if`
+error: expected identifier, found keyword `if`
   --> $DIR/keyword-if-as-identifier.rs:4:9
    |
 LL |     let if = "foo";
-   |         ^^ expected pattern
+   |         ^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#if = "foo";
+   |         ^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-impl-as-identifier.rs b/src/test/ui/parser/keyword-impl-as-identifier.rs
index 95a34483ad2..df529bae072 100644
--- a/src/test/ui/parser/keyword-impl-as-identifier.rs
+++ b/src/test/ui/parser/keyword-impl-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py impl'
 
 fn main() {
-    let impl = "foo"; //~ error: expected pattern, found keyword `impl`
+    let impl = "foo"; //~ error: expected identifier, found keyword `impl`
 }
diff --git a/src/test/ui/parser/keyword-impl-as-identifier.stderr b/src/test/ui/parser/keyword-impl-as-identifier.stderr
index 2672959b7c6..01886eb45cb 100644
--- a/src/test/ui/parser/keyword-impl-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-impl-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `impl`
+error: expected identifier, found keyword `impl`
   --> $DIR/keyword-impl-as-identifier.rs:4:9
    |
 LL |     let impl = "foo";
-   |         ^^^^ expected pattern
+   |         ^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#impl = "foo";
+   |         ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-let-as-identifier.rs b/src/test/ui/parser/keyword-let-as-identifier.rs
index 07c0ddf8ce5..9b1183501b2 100644
--- a/src/test/ui/parser/keyword-let-as-identifier.rs
+++ b/src/test/ui/parser/keyword-let-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py let'
 
 fn main() {
-    let let = "foo"; //~ error: expected pattern, found keyword `let`
+    let let = "foo"; //~ error: expected identifier, found keyword `let`
 }
diff --git a/src/test/ui/parser/keyword-let-as-identifier.stderr b/src/test/ui/parser/keyword-let-as-identifier.stderr
index 99dbc0530f3..f6c39077be2 100644
--- a/src/test/ui/parser/keyword-let-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-let-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `let`
+error: expected identifier, found keyword `let`
   --> $DIR/keyword-let-as-identifier.rs:4:9
    |
 LL |     let let = "foo";
-   |         ^^^ expected pattern
+   |         ^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#let = "foo";
+   |         ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-loop-as-identifier.rs b/src/test/ui/parser/keyword-loop-as-identifier.rs
index 8643ffe4345..46914a19be2 100644
--- a/src/test/ui/parser/keyword-loop-as-identifier.rs
+++ b/src/test/ui/parser/keyword-loop-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py loop'
 
 fn main() {
-    let loop = "foo"; //~ error: expected pattern, found keyword `loop`
+    let loop = "foo"; //~ error: expected identifier, found keyword `loop`
 }
diff --git a/src/test/ui/parser/keyword-loop-as-identifier.stderr b/src/test/ui/parser/keyword-loop-as-identifier.stderr
index 783507eb35c..f0c282faa29 100644
--- a/src/test/ui/parser/keyword-loop-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-loop-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `loop`
+error: expected identifier, found keyword `loop`
   --> $DIR/keyword-loop-as-identifier.rs:4:9
    |
 LL |     let loop = "foo";
-   |         ^^^^ expected pattern
+   |         ^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#loop = "foo";
+   |         ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-match-as-identifier.rs b/src/test/ui/parser/keyword-match-as-identifier.rs
index 8ef6b6810a5..d3cecb991b8 100644
--- a/src/test/ui/parser/keyword-match-as-identifier.rs
+++ b/src/test/ui/parser/keyword-match-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py match'
 
 fn main() {
-    let match = "foo"; //~ error: expected pattern, found keyword `match`
+    let match = "foo"; //~ error: expected identifier, found keyword `match`
 }
diff --git a/src/test/ui/parser/keyword-match-as-identifier.stderr b/src/test/ui/parser/keyword-match-as-identifier.stderr
index e56a115c916..f1f4397d194 100644
--- a/src/test/ui/parser/keyword-match-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-match-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `match`
+error: expected identifier, found keyword `match`
   --> $DIR/keyword-match-as-identifier.rs:4:9
    |
 LL |     let match = "foo";
-   |         ^^^^^ expected pattern
+   |         ^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#match = "foo";
+   |         ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-mod-as-identifier.rs b/src/test/ui/parser/keyword-mod-as-identifier.rs
index 96bcdccf0a0..b9c7b6c78ed 100644
--- a/src/test/ui/parser/keyword-mod-as-identifier.rs
+++ b/src/test/ui/parser/keyword-mod-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py mod'
 
 fn main() {
-    let mod = "foo"; //~ error: expected pattern, found keyword `mod`
+    let mod = "foo"; //~ error: expected identifier, found keyword `mod`
 }
diff --git a/src/test/ui/parser/keyword-mod-as-identifier.stderr b/src/test/ui/parser/keyword-mod-as-identifier.stderr
index a8be2ceb037..65ae3baa8c2 100644
--- a/src/test/ui/parser/keyword-mod-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-mod-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `mod`
+error: expected identifier, found keyword `mod`
   --> $DIR/keyword-mod-as-identifier.rs:4:9
    |
 LL |     let mod = "foo";
-   |         ^^^ expected pattern
+   |         ^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#mod = "foo";
+   |         ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-move-as-identifier.rs b/src/test/ui/parser/keyword-move-as-identifier.rs
index 2193af530bd..65be02e3c70 100644
--- a/src/test/ui/parser/keyword-move-as-identifier.rs
+++ b/src/test/ui/parser/keyword-move-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py move'
 
 fn main() {
-    let move = "foo"; //~ error: expected pattern, found keyword `move`
+    let move = "foo"; //~ error: expected identifier, found keyword `move`
 }
diff --git a/src/test/ui/parser/keyword-move-as-identifier.stderr b/src/test/ui/parser/keyword-move-as-identifier.stderr
index e0687e27eb5..216f7c931ee 100644
--- a/src/test/ui/parser/keyword-move-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-move-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `move`
+error: expected identifier, found keyword `move`
   --> $DIR/keyword-move-as-identifier.rs:4:9
    |
 LL |     let move = "foo";
-   |         ^^^^ expected pattern
+   |         ^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#move = "foo";
+   |         ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-override.rs b/src/test/ui/parser/keyword-override.rs
index 948a20095f1..009bebd7ddb 100644
--- a/src/test/ui/parser/keyword-override.rs
+++ b/src/test/ui/parser/keyword-override.rs
@@ -1,3 +1,3 @@
 fn main() {
-    let override = (); //~ ERROR expected pattern, found reserved keyword `override`
+    let override = (); //~ ERROR expected identifier, found reserved keyword `override`
 }
diff --git a/src/test/ui/parser/keyword-override.stderr b/src/test/ui/parser/keyword-override.stderr
index 1bfc6c9b385..3183fa510c2 100644
--- a/src/test/ui/parser/keyword-override.stderr
+++ b/src/test/ui/parser/keyword-override.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found reserved keyword `override`
+error: expected identifier, found reserved keyword `override`
   --> $DIR/keyword-override.rs:2:9
    |
 LL |     let override = ();
-   |         ^^^^^^^^ expected pattern
+   |         ^^^^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#override = ();
+   |         ^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-pub-as-identifier.rs b/src/test/ui/parser/keyword-pub-as-identifier.rs
index 2ed8cc6b268..2b2bb14118d 100644
--- a/src/test/ui/parser/keyword-pub-as-identifier.rs
+++ b/src/test/ui/parser/keyword-pub-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py pub'
 
 fn main() {
-    let pub = "foo"; //~ error: expected pattern, found keyword `pub`
+    let pub = "foo"; //~ error: expected identifier, found keyword `pub`
 }
diff --git a/src/test/ui/parser/keyword-pub-as-identifier.stderr b/src/test/ui/parser/keyword-pub-as-identifier.stderr
index 526ddcd6ee0..f81078b12bd 100644
--- a/src/test/ui/parser/keyword-pub-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-pub-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `pub`
+error: expected identifier, found keyword `pub`
   --> $DIR/keyword-pub-as-identifier.rs:4:9
    |
 LL |     let pub = "foo";
-   |         ^^^ expected pattern
+   |         ^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#pub = "foo";
+   |         ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-return-as-identifier.rs b/src/test/ui/parser/keyword-return-as-identifier.rs
index 920931b00f9..e1a2db5e4d8 100644
--- a/src/test/ui/parser/keyword-return-as-identifier.rs
+++ b/src/test/ui/parser/keyword-return-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py return'
 
 fn main() {
-    let return = "foo"; //~ error: expected pattern, found keyword `return`
+    let return = "foo"; //~ error: expected identifier, found keyword `return`
 }
diff --git a/src/test/ui/parser/keyword-return-as-identifier.stderr b/src/test/ui/parser/keyword-return-as-identifier.stderr
index c0156a63fa9..8cc4d12fbbb 100644
--- a/src/test/ui/parser/keyword-return-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-return-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `return`
+error: expected identifier, found keyword `return`
   --> $DIR/keyword-return-as-identifier.rs:4:9
    |
 LL |     let return = "foo";
-   |         ^^^^^^ expected pattern
+   |         ^^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#return = "foo";
+   |         ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-static-as-identifier.rs b/src/test/ui/parser/keyword-static-as-identifier.rs
index 3ccbfccfc93..423b9854b8a 100644
--- a/src/test/ui/parser/keyword-static-as-identifier.rs
+++ b/src/test/ui/parser/keyword-static-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py static'
 
 fn main() {
-    let static = "foo"; //~ error: expected pattern, found keyword `static`
+    let static = "foo"; //~ error: expected identifier, found keyword `static`
 }
diff --git a/src/test/ui/parser/keyword-static-as-identifier.stderr b/src/test/ui/parser/keyword-static-as-identifier.stderr
index 00a65977732..7d22bc97d66 100644
--- a/src/test/ui/parser/keyword-static-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-static-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `static`
+error: expected identifier, found keyword `static`
   --> $DIR/keyword-static-as-identifier.rs:4:9
    |
 LL |     let static = "foo";
-   |         ^^^^^^ expected pattern
+   |         ^^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#static = "foo";
+   |         ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-struct-as-identifier.rs b/src/test/ui/parser/keyword-struct-as-identifier.rs
index 69d8f190655..18cfe11592a 100644
--- a/src/test/ui/parser/keyword-struct-as-identifier.rs
+++ b/src/test/ui/parser/keyword-struct-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py struct'
 
 fn main() {
-    let struct = "foo"; //~ error: expected pattern, found keyword `struct`
+    let struct = "foo"; //~ error: expected identifier, found keyword `struct`
 }
diff --git a/src/test/ui/parser/keyword-struct-as-identifier.stderr b/src/test/ui/parser/keyword-struct-as-identifier.stderr
index b2d6639e72e..b109fa6247d 100644
--- a/src/test/ui/parser/keyword-struct-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-struct-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `struct`
+error: expected identifier, found keyword `struct`
   --> $DIR/keyword-struct-as-identifier.rs:4:9
    |
 LL |     let struct = "foo";
-   |         ^^^^^^ expected pattern
+   |         ^^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#struct = "foo";
+   |         ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-trait-as-identifier.rs b/src/test/ui/parser/keyword-trait-as-identifier.rs
index f62858442d2..67f81167dbd 100644
--- a/src/test/ui/parser/keyword-trait-as-identifier.rs
+++ b/src/test/ui/parser/keyword-trait-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py trait'
 
 fn main() {
-    let trait = "foo"; //~ error: expected pattern, found keyword `trait`
+    let trait = "foo"; //~ error: expected identifier, found keyword `trait`
 }
diff --git a/src/test/ui/parser/keyword-trait-as-identifier.stderr b/src/test/ui/parser/keyword-trait-as-identifier.stderr
index b31c0df28c0..ccc675cdb3a 100644
--- a/src/test/ui/parser/keyword-trait-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-trait-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `trait`
+error: expected identifier, found keyword `trait`
   --> $DIR/keyword-trait-as-identifier.rs:4:9
    |
 LL |     let trait = "foo";
-   |         ^^^^^ expected pattern
+   |         ^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#trait = "foo";
+   |         ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs b/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs
index 13a938b2e09..4fa37bdb057 100644
--- a/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs
+++ b/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs
@@ -1,5 +1,5 @@
 // compile-flags: --edition 2018
 
 fn main() {
-    let try = "foo"; //~ error: expected pattern, found reserved keyword `try`
+    let try = "foo"; //~ error: expected identifier, found reserved keyword `try`
 }
diff --git a/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr b/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr
index c342e3a76fb..f71b889a30d 100644
--- a/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr
+++ b/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found reserved keyword `try`
+error: expected identifier, found reserved keyword `try`
   --> $DIR/keyword-try-as-identifier-edition2018.rs:4:9
    |
 LL |     let try = "foo";
-   |         ^^^ expected pattern
+   |         ^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#try = "foo";
+   |         ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-type-as-identifier.rs b/src/test/ui/parser/keyword-type-as-identifier.rs
index 992547e6f59..04adddf72c6 100644
--- a/src/test/ui/parser/keyword-type-as-identifier.rs
+++ b/src/test/ui/parser/keyword-type-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py type'
 
 fn main() {
-    let type = "foo"; //~ error: expected pattern, found keyword `type`
+    let type = "foo"; //~ error: expected identifier, found keyword `type`
 }
diff --git a/src/test/ui/parser/keyword-type-as-identifier.stderr b/src/test/ui/parser/keyword-type-as-identifier.stderr
index b749c708d44..88099d949a8 100644
--- a/src/test/ui/parser/keyword-type-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-type-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `type`
+error: expected identifier, found keyword `type`
   --> $DIR/keyword-type-as-identifier.rs:4:9
    |
 LL |     let type = "foo";
-   |         ^^^^ expected pattern
+   |         ^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#type = "foo";
+   |         ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-typeof.rs b/src/test/ui/parser/keyword-typeof.rs
index 4ef102646ef..29dc77d276c 100644
--- a/src/test/ui/parser/keyword-typeof.rs
+++ b/src/test/ui/parser/keyword-typeof.rs
@@ -1,3 +1,3 @@
 fn main() {
-    let typeof = (); //~ ERROR expected pattern, found reserved keyword `typeof`
+    let typeof = (); //~ ERROR expected identifier, found reserved keyword `typeof`
 }
diff --git a/src/test/ui/parser/keyword-typeof.stderr b/src/test/ui/parser/keyword-typeof.stderr
index e7b18023e61..4a1b63d5c93 100644
--- a/src/test/ui/parser/keyword-typeof.stderr
+++ b/src/test/ui/parser/keyword-typeof.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found reserved keyword `typeof`
+error: expected identifier, found reserved keyword `typeof`
   --> $DIR/keyword-typeof.rs:2:9
    |
 LL |     let typeof = ();
-   |         ^^^^^^ expected pattern
+   |         ^^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#typeof = ();
+   |         ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-unsafe-as-identifier.rs b/src/test/ui/parser/keyword-unsafe-as-identifier.rs
index adb20ebe48c..0ff6d188c64 100644
--- a/src/test/ui/parser/keyword-unsafe-as-identifier.rs
+++ b/src/test/ui/parser/keyword-unsafe-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py unsafe'
 
 fn main() {
-    let unsafe = "foo"; //~ error: expected pattern, found keyword `unsafe`
+    let unsafe = "foo"; //~ error: expected identifier, found keyword `unsafe`
 }
diff --git a/src/test/ui/parser/keyword-unsafe-as-identifier.stderr b/src/test/ui/parser/keyword-unsafe-as-identifier.stderr
index 67935ce43ba..205bb81df40 100644
--- a/src/test/ui/parser/keyword-unsafe-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-unsafe-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `unsafe`
+error: expected identifier, found keyword `unsafe`
   --> $DIR/keyword-unsafe-as-identifier.rs:4:9
    |
 LL |     let unsafe = "foo";
-   |         ^^^^^^ expected pattern
+   |         ^^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#unsafe = "foo";
+   |         ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-use-as-identifier.rs b/src/test/ui/parser/keyword-use-as-identifier.rs
index 198444bafc5..821bedee088 100644
--- a/src/test/ui/parser/keyword-use-as-identifier.rs
+++ b/src/test/ui/parser/keyword-use-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py use'
 
 fn main() {
-    let use = "foo"; //~ error: expected pattern, found keyword `use`
+    let use = "foo"; //~ error: expected identifier, found keyword `use`
 }
diff --git a/src/test/ui/parser/keyword-use-as-identifier.stderr b/src/test/ui/parser/keyword-use-as-identifier.stderr
index 2c69d0a8744..85a0492f573 100644
--- a/src/test/ui/parser/keyword-use-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-use-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `use`
+error: expected identifier, found keyword `use`
   --> $DIR/keyword-use-as-identifier.rs:4:9
    |
 LL |     let use = "foo";
-   |         ^^^ expected pattern
+   |         ^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#use = "foo";
+   |         ^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-where-as-identifier.rs b/src/test/ui/parser/keyword-where-as-identifier.rs
index 5624a8fc460..56301bd20ad 100644
--- a/src/test/ui/parser/keyword-where-as-identifier.rs
+++ b/src/test/ui/parser/keyword-where-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py where'
 
 fn main() {
-    let where = "foo"; //~ error: expected pattern, found keyword `where`
+    let where = "foo"; //~ error: expected identifier, found keyword `where`
 }
diff --git a/src/test/ui/parser/keyword-where-as-identifier.stderr b/src/test/ui/parser/keyword-where-as-identifier.stderr
index fc01183ca04..b8b85069076 100644
--- a/src/test/ui/parser/keyword-where-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-where-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `where`
+error: expected identifier, found keyword `where`
   --> $DIR/keyword-where-as-identifier.rs:4:9
    |
 LL |     let where = "foo";
-   |         ^^^^^ expected pattern
+   |         ^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#where = "foo";
+   |         ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/keyword-while-as-identifier.rs b/src/test/ui/parser/keyword-while-as-identifier.rs
index c0a539d3507..22026d15dcb 100644
--- a/src/test/ui/parser/keyword-while-as-identifier.rs
+++ b/src/test/ui/parser/keyword-while-as-identifier.rs
@@ -1,5 +1,5 @@
 // This file was auto-generated using 'src/etc/generate-keyword-tests.py while'
 
 fn main() {
-    let while = "foo"; //~ error: expected pattern, found keyword `while`
+    let while = "foo"; //~ error: expected identifier, found keyword `while`
 }
diff --git a/src/test/ui/parser/keyword-while-as-identifier.stderr b/src/test/ui/parser/keyword-while-as-identifier.stderr
index f72ac877420..bb0c0ac668a 100644
--- a/src/test/ui/parser/keyword-while-as-identifier.stderr
+++ b/src/test/ui/parser/keyword-while-as-identifier.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found keyword `while`
+error: expected identifier, found keyword `while`
   --> $DIR/keyword-while-as-identifier.rs:4:9
    |
 LL |     let while = "foo";
-   |         ^^^^^ expected pattern
+   |         ^^^^^ expected identifier, found keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#while = "foo";
+   |         ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs
index bffeb1e2e7c..87e127f9d36 100644
--- a/src/test/ui/parser/mut-patterns.rs
+++ b/src/test/ui/parser/mut-patterns.rs
@@ -1,7 +1,35 @@
 // Can't put mut in non-ident pattern
 
+// edition:2018
+
+#![feature(box_patterns)]
+#![allow(warnings)]
+
 pub fn main() {
+    let mut mut x = 0;
+    //~^ ERROR `mut` on a binding may not be repeated
+    //~| remove the additional `mut`s
+
     struct Foo { x: isize }
     let mut Foo { x: x } = Foo { x: 3 };
-    //~^ ERROR: expected one of `:`, `;`, `=`, `@`, or `|`, found `{`
+    //~^ ERROR `mut` must be attached to each individual binding
+    //~| add `mut` to each binding
+
+    let mut Foo { x } = Foo { x: 3 };
+    //~^ ERROR `mut` must be attached to each individual binding
+    //~| add `mut` to each binding
+
+    struct r#yield(u8, u8);
+    let mut mut yield(become, await) = r#yield(0, 0);
+    //~^ ERROR `mut` on a binding may not be repeated
+    //~| ERROR `mut` must be attached to each individual binding
+    //~| ERROR expected identifier, found reserved keyword `yield`
+    //~| ERROR expected identifier, found reserved keyword `become`
+    //~| ERROR expected identifier, found reserved keyword `await`
+
+    struct W<T, U>(T, U);
+    struct B { f: Box<u8> }
+    let mut W(mut a, W(b, W(ref c, W(d, B { box f }))))
+    //~^ ERROR `mut` must be attached to each individual binding
+        = W(0, W(1, W(2, W(3, B { f: Box::new(4u8) }))));
 }
diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr
index b39209afd42..a251e2908f0 100644
--- a/src/test/ui/parser/mut-patterns.stderr
+++ b/src/test/ui/parser/mut-patterns.stderr
@@ -1,8 +1,68 @@
-error: expected one of `:`, `;`, `=`, `@`, or `|`, found `{`
-  --> $DIR/mut-patterns.rs:5:17
+error: `mut` on a binding may not be repeated
+  --> $DIR/mut-patterns.rs:9:13
+   |
+LL |     let mut mut x = 0;
+   |             ^^^ help: remove the additional `mut`s
+
+error: `mut` must be attached to each individual binding
+  --> $DIR/mut-patterns.rs:14:9
    |
 LL |     let mut Foo { x: x } = Foo { x: 3 };
-   |                 ^ expected one of `:`, `;`, `=`, `@`, or `|` here
+   |         ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }`
+
+error: `mut` must be attached to each individual binding
+  --> $DIR/mut-patterns.rs:18:9
+   |
+LL |     let mut Foo { x } = Foo { x: 3 };
+   |         ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }`
+
+error: `mut` on a binding may not be repeated
+  --> $DIR/mut-patterns.rs:23:13
+   |
+LL |     let mut mut yield(become, await) = r#yield(0, 0);
+   |             ^^^ help: remove the additional `mut`s
+
+error: expected identifier, found reserved keyword `yield`
+  --> $DIR/mut-patterns.rs:23:17
+   |
+LL |     let mut mut yield(become, await) = r#yield(0, 0);
+   |                 ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let mut mut r#yield(become, await) = r#yield(0, 0);
+   |                 ^^^^^^^
+
+error: expected identifier, found reserved keyword `become`
+  --> $DIR/mut-patterns.rs:23:23
+   |
+LL |     let mut mut yield(become, await) = r#yield(0, 0);
+   |                       ^^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let mut mut yield(r#become, await) = r#yield(0, 0);
+   |                       ^^^^^^^^
+
+error: expected identifier, found reserved keyword `await`
+  --> $DIR/mut-patterns.rs:23:31
+   |
+LL |     let mut mut yield(become, await) = r#yield(0, 0);
+   |                               ^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let mut mut yield(become, r#await) = r#yield(0, 0);
+   |                               ^^^^^^^
+
+error: `mut` must be attached to each individual binding
+  --> $DIR/mut-patterns.rs:23:9
+   |
+LL |     let mut mut yield(become, await) = r#yield(0, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)`
+
+error: `mut` must be attached to each individual binding
+  --> $DIR/mut-patterns.rs:32:9
+   |
+LL |     let mut W(mut a, W(b, W(ref c, W(d, B { box f }))))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))`
 
-error: aborting due to previous error
+error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/reserved/reserved-become.rs b/src/test/ui/reserved/reserved-become.rs
index 2279a05e6b2..56645255ee5 100644
--- a/src/test/ui/reserved/reserved-become.rs
+++ b/src/test/ui/reserved/reserved-become.rs
@@ -1,4 +1,4 @@
 fn main() {
     let become = 0;
-    //~^ ERROR expected pattern, found reserved keyword `become`
+    //~^ ERROR expected identifier, found reserved keyword `become`
 }
diff --git a/src/test/ui/reserved/reserved-become.stderr b/src/test/ui/reserved/reserved-become.stderr
index f9fe78e18b3..3ce9fb33c28 100644
--- a/src/test/ui/reserved/reserved-become.stderr
+++ b/src/test/ui/reserved/reserved-become.stderr
@@ -1,8 +1,12 @@
-error: expected pattern, found reserved keyword `become`
+error: expected identifier, found reserved keyword `become`
   --> $DIR/reserved-become.rs:2:9
    |
 LL |     let become = 0;
-   |         ^^^^^^ expected pattern
+   |         ^^^^^^ expected identifier, found reserved keyword
+help: you can escape reserved keywords to use them as identifiers
+   |
+LL |     let r#become = 0;
+   |         ^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/self/self_type_keyword.rs b/src/test/ui/self/self_type_keyword.rs
index 01b3309fcac..d479905932b 100644
--- a/src/test/ui/self/self_type_keyword.rs
+++ b/src/test/ui/self/self_type_keyword.rs
@@ -14,7 +14,8 @@ pub fn main() {
         ref Self => (),
         //~^ ERROR expected identifier, found keyword `Self`
         mut Self => (),
-        //~^ ERROR expected identifier, found keyword `Self`
+        //~^ ERROR `mut` must be attached to each individual binding
+        //~| ERROR cannot find unit struct/variant or constant `Self`
         ref mut Self => (),
         //~^ ERROR expected identifier, found keyword `Self`
         Self!() => (),
diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr
index b63de98b8e7..fdae06ccdd9 100644
--- a/src/test/ui/self/self_type_keyword.stderr
+++ b/src/test/ui/self/self_type_keyword.stderr
@@ -10,38 +10,38 @@ error: expected identifier, found keyword `Self`
 LL |         ref Self => (),
    |             ^^^^ expected identifier, found keyword
 
-error: expected identifier, found keyword `Self`
-  --> $DIR/self_type_keyword.rs:16:13
+error: `mut` must be attached to each individual binding
+  --> $DIR/self_type_keyword.rs:16:9
    |
 LL |         mut Self => (),
-   |             ^^^^ expected identifier, found keyword
+   |         ^^^^^^^^ help: add `mut` to each binding: `Self`
 
 error: expected identifier, found keyword `Self`
-  --> $DIR/self_type_keyword.rs:18:17
+  --> $DIR/self_type_keyword.rs:19:17
    |
 LL |         ref mut Self => (),
    |                 ^^^^ expected identifier, found keyword
 
 error: expected identifier, found keyword `Self`
-  --> $DIR/self_type_keyword.rs:22:15
+  --> $DIR/self_type_keyword.rs:23:15
    |
 LL |         Foo { Self } => (),
    |               ^^^^ expected identifier, found keyword
 
 error: expected identifier, found keyword `Self`
-  --> $DIR/self_type_keyword.rs:28:26
+  --> $DIR/self_type_keyword.rs:29:26
    |
 LL |     extern crate core as Self;
    |                          ^^^^ expected identifier, found keyword
 
 error: expected identifier, found keyword `Self`
-  --> $DIR/self_type_keyword.rs:33:32
+  --> $DIR/self_type_keyword.rs:34:32
    |
 LL |     use std::option::Option as Self;
    |                                ^^^^ expected identifier, found keyword
 
 error: expected identifier, found keyword `Self`
-  --> $DIR/self_type_keyword.rs:38:11
+  --> $DIR/self_type_keyword.rs:39:11
    |
 LL |     trait Self {}
    |           ^^^^ expected identifier, found keyword
@@ -53,11 +53,21 @@ LL | struct Bar<'Self>;
    |            ^^^^^
 
 error: cannot find macro `Self!` in this scope
-  --> $DIR/self_type_keyword.rs:20:9
+  --> $DIR/self_type_keyword.rs:21:9
    |
 LL |         Self!() => (),
    |         ^^^^
 
+error[E0531]: cannot find unit struct/variant or constant `Self` in this scope
+  --> $DIR/self_type_keyword.rs:16:13
+   |
+LL |         mut Self => (),
+   |             ^^^^ not found in this scope
+help: possible candidate is found in another module, you can import it into scope
+   |
+LL | use foo::Self;
+   |
+
 error[E0392]: parameter `'Self` is never used
   --> $DIR/self_type_keyword.rs:6:12
    |
@@ -66,6 +76,6 @@ LL | struct Bar<'Self>;
    |
    = help: consider removing `'Self` or using a marker such as `std::marker::PhantomData`
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0392`.