about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-08-29 05:05:17 +0000
committerbors <bors@rust-lang.org>2019-08-29 05:05:17 +0000
commit85ed538d6988c6c82aea8750b306cb793e874294 (patch)
tree6871fa85b73a88ec2d6d82b691b3309dd61f96f9
parent347654324dde17135072d2d704a71209dd3c5ca3 (diff)
parent73910092365b67fa897bc828b7a4ffa1f2c776cf (diff)
downloadrust-85ed538d6988c6c82aea8750b306cb793e874294.tar.gz
rust-85ed538d6988c6c82aea8750b306cb793e874294.zip
Auto merge of #63990 - Centril:rollup-q1nt0b0, r=Centril
Rollup of 11 pull requests

Successful merges:

 - #63811 (Correctly suggest adding bounds to `impl Trait` argument)
 - #63933 (Resolve some small issues related to #63580)
 - #63938 (or-pattern: fix typo in error message)
 - #63945 (Recover `mut $pat` and other improvements)
 - #63958 (const_prop: only call error_to_const_error if we are actually showing something)
 - #63961 (Add Option<Span> to `require_lang_item`)
 - #63963 (remove the reference to __cxa_thread_atexit_impl)
 - #63965 (Prevent syntax error in LD linker version script)
 - #63968 (rustc_apfloat: make the crate #![no_std] explicitly.)
 - #63970 (Notify me (flip1995) when Clippy toolstate changes)
 - #63980 (add missing `#[repr(C)]` on the Slices union)

Failed merges:

 - #63989 (Add Yaah to clippy toolstain notification list)

r? @ghost
-rw-r--r--src/libcore/str/mod.rs1
-rw-r--r--src/librustc/infer/mod.rs2
-rw-r--r--src/librustc/middle/lang_items.rs8
-rw-r--r--src/librustc/mir/mod.rs7
-rw-r--r--src/librustc/traits/select.rs2
-rw-r--r--src/librustc/ty/context.rs4
-rw-r--r--src/librustc/ty/instance.rs2
-rw-r--r--src/librustc/ty/mod.rs6
-rw-r--r--src/librustc/ty/util.rs6
-rw-r--r--src/librustc/ty/wf.rs2
-rw-r--r--src/librustc_apfloat/ieee.rs16
-rw-r--r--src/librustc_apfloat/lib.rs36
-rw-r--r--src/librustc_apfloat/ppc.rs6
-rw-r--r--src/librustc_codegen_ssa/back/linker.rs11
-rw-r--r--src/librustc_codegen_ssa/base.rs2
-rw-r--r--src/librustc_metadata/cstore_impl.rs20
-rw-r--r--src/librustc_metadata/decoder.rs38
-rw-r--r--src/librustc_mir/build/matches/test.rs2
-rw-r--r--src/librustc_mir/const_eval.rs3
-rw-r--r--src/librustc_mir/transform/const_prop.rs4
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs5
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs5
-rw-r--r--src/librustc_typeck/check/cast.rs2
-rw-r--r--src/librustc_typeck/check/closure.rs2
-rw-r--r--src/librustc_typeck/check/method/suggest.rs18
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/check/wfcheck.rs4
-rw-r--r--src/librustdoc/clean/auto_trait.rs8
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/libstd/sys/vxworks/fast_thread_local.rs27
-rw-r--r--src/libsyntax/parse/literal.rs4
-rw-r--r--src/libsyntax/parse/parser/pat.rs157
-rw-r--r--src/libsyntax/parse/parser/path.rs2
-rw-r--r--src/libsyntax/parse/token.rs43
-rw-r--r--src/libsyntax_pos/symbol.rs5
-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/lang-item-missing-generator.stderr4
-rw-r--r--src/test/ui/or-patterns/while-parsing-this-or-pattern.rs2
-rw-r--r--src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr2
-rw-r--r--src/test/ui/parser/issue-32501.rs3
-rw-r--r--src/test/ui/parser/issue-32501.stderr8
-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.rs41
-rw-r--r--src/test/ui/parser/mut-patterns.stderr101
-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.stderr32
-rw-r--r--src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed20
-rw-r--r--src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs20
-rw-r--r--src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr15
-rwxr-xr-xsrc/tools/publish_toolstate.py2
112 files changed, 741 insertions, 296 deletions
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index f20cb7bfbc3..752c372e93e 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -2170,6 +2170,7 @@ impl str {
     #[inline(always)]
     #[rustc_const_unstable(feature="const_str_as_bytes")]
     pub const fn as_bytes(&self) -> &[u8] {
+        #[repr(C)]
         union Slices<'a> {
             str: &'a str,
             slice: &'a [u8],
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index e1d77a97c11..cc28567e2fc 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1460,7 +1460,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
         }
 
-        let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem);
+        let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None);
 
         // this can get called from typeck (by euv), and moves_by_default
         // rightly refuses to work with inference variables, but
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index c5c86393243..334c06618bb 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -381,9 +381,13 @@ language_item_table! {
 impl<'tcx> TyCtxt<'tcx> {
     /// Returns the `DefId` for a given `LangItem`.
     /// If not found, fatally abort compilation.
-    pub fn require_lang_item(&self, lang_item: LangItem) -> DefId {
+    pub fn require_lang_item(&self, lang_item: LangItem, span: Option<Span>) -> DefId {
         self.lang_items().require(lang_item).unwrap_or_else(|msg| {
-            self.sess.fatal(&msg)
+            if let Some(span) = span {
+                self.sess.span_fatal(span, &msg)
+            } else {
+                self.sess.fatal(&msg)
+            }
         })
     }
 }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 858b77af804..5ac99ba1470 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1733,6 +1733,10 @@ pub enum PlaceBase<'tcx> {
 pub struct Static<'tcx> {
     pub ty: Ty<'tcx>,
     pub kind: StaticKind<'tcx>,
+    /// The `DefId` of the item this static was declared in. For promoted values, usually, this is
+    /// the same as the `DefId` of the `mir::Body` containing the `Place` this promoted appears in.
+    /// However, after inlining, that might no longer be the case as inlined `Place`s are copied
+    /// into the calling frame.
     pub def_id: DefId,
 }
 
@@ -1740,6 +1744,9 @@ pub struct Static<'tcx> {
     Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, RustcEncodable, RustcDecodable,
 )]
 pub enum StaticKind<'tcx> {
+    /// Promoted references consist of an id (`Promoted`) and the substs necessary to monomorphize
+    /// it. Usually, these substs are just the identity substs for the item. However, the inliner
+    /// will adjust these substs when it inlines a function based on the substs at the callsite.
     Promoted(Promoted, SubstsRef<'tcx>),
     Static,
 }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index d4ae366262c..217c887d525 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -3513,7 +3513,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // We can only make objects from sized types.
                 let tr = ty::TraitRef {
-                    def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem),
+                    def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
                     substs: tcx.mk_substs_trait(source, &[]),
                 };
                 nested.push(predicate_to_obligation(tr.to_predicate()));
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 9f316e93111..c0d86a79882 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -2385,13 +2385,13 @@ impl<'tcx> TyCtxt<'tcx> {
 
     #[inline]
     pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
+        let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem, None);
         self.mk_generic_adt(def_id, ty)
     }
 
     #[inline]
     pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem);
+        let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None);
         self.mk_generic_adt(def_id, ty)
     }
 
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index c71e1ea4e58..a26fa72f330 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -327,7 +327,7 @@ impl<'tcx> Instance<'tcx> {
     }
 
     pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> {
-        let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
+        let def_id = tcx.require_lang_item(DropInPlaceFnLangItem, None);
         let substs = tcx.intern_substs(&[ty.into()]);
         Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap()
     }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 0b81f193df4..90b3b7ebb06 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2588,12 +2588,12 @@ impl<'tcx> ClosureKind {
 
     pub fn trait_did(&self, tcx: TyCtxt<'tcx>) -> DefId {
         match *self {
-            ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem),
+            ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem, None),
             ClosureKind::FnMut => {
-                tcx.require_lang_item(FnMutTraitLangItem)
+                tcx.require_lang_item(FnMutTraitLangItem, None)
             }
             ClosureKind::FnOnce => {
-                tcx.require_lang_item(FnOnceTraitLangItem)
+                tcx.require_lang_item(FnOnceTraitLangItem, None)
             }
         }
     }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 96e16efd130..7a77418050c 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -998,7 +998,7 @@ impl<'tcx> ty::TyS<'tcx> {
 
 fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
     let (param_env, ty) = query.into_parts();
-    let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem);
+    let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem, None);
     tcx.infer_ctxt()
         .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions(
             &infcx,
@@ -1011,7 +1011,7 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
 
 fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
     let (param_env, ty) = query.into_parts();
-    let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem);
+    let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
     tcx.infer_ctxt()
         .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions(
             &infcx,
@@ -1024,7 +1024,7 @@ fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
 
 fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
     let (param_env, ty) = query.into_parts();
-    let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem);
+    let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem, None);
     tcx.infer_ctxt()
         .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions(
             &infcx,
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index d32c32af29e..d6de217f79c 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -221,7 +221,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         if !subty.has_escaping_bound_vars() {
             let cause = self.cause(cause);
             let trait_ref = ty::TraitRef {
-                def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
+                def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
                 substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
             };
             self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate()));
diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs
index 9f68d770b9e..18d968fbddd 100644
--- a/src/librustc_apfloat/ieee.rs
+++ b/src/librustc_apfloat/ieee.rs
@@ -1,13 +1,13 @@
 use crate::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO};
 use crate::{Float, FloatConvert, ParseError, Round, Status, StatusAnd};
 
+use core::cmp::{self, Ordering};
+use core::convert::TryFrom;
+use core::fmt::{self, Write};
+use core::marker::PhantomData;
+use core::mem;
+use core::ops::Neg;
 use smallvec::{SmallVec, smallvec};
-use std::cmp::{self, Ordering};
-use std::convert::TryFrom;
-use std::fmt::{self, Write};
-use std::marker::PhantomData;
-use std::mem;
-use std::ops::Neg;
 
 #[must_use]
 pub struct IeeeFloat<S> {
@@ -2287,8 +2287,8 @@ impl Loss {
 /// Implementation details of IeeeFloat significands, such as big integer arithmetic.
 /// As a rule of thumb, no functions in this module should dynamically allocate.
 mod sig {
-    use std::cmp::Ordering;
-    use std::mem;
+    use core::cmp::Ordering;
+    use core::mem;
     use super::{ExpInt, Limb, LIMB_BITS, limbs_for_bits, Loss};
 
     pub(super) fn is_all_zeros(limbs: &[Limb]) -> bool {
diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs
index 9e6d5a6f624..1190cea21ac 100644
--- a/src/librustc_apfloat/lib.rs
+++ b/src/librustc_apfloat/lib.rs
@@ -31,15 +31,19 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![no_std]
 #![forbid(unsafe_code)]
 
 #![feature(nll)]
 
-use std::cmp::Ordering;
-use std::fmt;
-use std::ops::{Neg, Add, Sub, Mul, Div, Rem};
-use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
-use std::str::FromStr;
+#[macro_use]
+extern crate alloc;
+
+use core::cmp::Ordering;
+use core::fmt;
+use core::ops::{Neg, Add, Sub, Mul, Div, Rem};
+use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
+use core::str::FromStr;
 
 bitflags::bitflags! {
     /// IEEE-754R 7: Default exception handling.
@@ -587,7 +591,7 @@ macro_rules! float_common_impls {
             }
         }
 
-        impl<$t> ::std::str::FromStr for $ty<$t> where Self: Float {
+        impl<$t> ::core::str::FromStr for $ty<$t> where Self: Float {
             type Err = ParseError;
             fn from_str(s: &str) -> Result<Self, ParseError> {
                 Self::from_str_r(s, Round::NearestTiesToEven).map(|x| x.value)
@@ -596,66 +600,66 @@ macro_rules! float_common_impls {
 
         // Rounding ties to the nearest even, by default.
 
-        impl<$t> ::std::ops::Add for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::Add for $ty<$t> where Self: Float {
             type Output = StatusAnd<Self>;
             fn add(self, rhs: Self) -> StatusAnd<Self> {
                 self.add_r(rhs, Round::NearestTiesToEven)
             }
         }
 
-        impl<$t> ::std::ops::Sub for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::Sub for $ty<$t> where Self: Float {
             type Output = StatusAnd<Self>;
             fn sub(self, rhs: Self) -> StatusAnd<Self> {
                 self.sub_r(rhs, Round::NearestTiesToEven)
             }
         }
 
-        impl<$t> ::std::ops::Mul for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::Mul for $ty<$t> where Self: Float {
             type Output = StatusAnd<Self>;
             fn mul(self, rhs: Self) -> StatusAnd<Self> {
                 self.mul_r(rhs, Round::NearestTiesToEven)
             }
         }
 
-        impl<$t> ::std::ops::Div for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::Div for $ty<$t> where Self: Float {
             type Output = StatusAnd<Self>;
             fn div(self, rhs: Self) -> StatusAnd<Self> {
                 self.div_r(rhs, Round::NearestTiesToEven)
             }
         }
 
-        impl<$t> ::std::ops::Rem for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::Rem for $ty<$t> where Self: Float {
             type Output = StatusAnd<Self>;
             fn rem(self, rhs: Self) -> StatusAnd<Self> {
                 self.c_fmod(rhs)
             }
         }
 
-        impl<$t> ::std::ops::AddAssign for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::AddAssign for $ty<$t> where Self: Float {
             fn add_assign(&mut self, rhs: Self) {
                 *self = (*self + rhs).value;
             }
         }
 
-        impl<$t> ::std::ops::SubAssign for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::SubAssign for $ty<$t> where Self: Float {
             fn sub_assign(&mut self, rhs: Self) {
                 *self = (*self - rhs).value;
             }
         }
 
-        impl<$t> ::std::ops::MulAssign for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::MulAssign for $ty<$t> where Self: Float {
             fn mul_assign(&mut self, rhs: Self) {
                 *self = (*self * rhs).value;
             }
         }
 
-        impl<$t> ::std::ops::DivAssign for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::DivAssign for $ty<$t> where Self: Float {
             fn div_assign(&mut self, rhs: Self) {
                 *self = (*self / rhs).value;
             }
         }
 
-        impl<$t> ::std::ops::RemAssign for $ty<$t> where Self: Float {
+        impl<$t> ::core::ops::RemAssign for $ty<$t> where Self: Float {
             fn rem_assign(&mut self, rhs: Self) {
                 *self = (*self % rhs).value;
             }
diff --git a/src/librustc_apfloat/ppc.rs b/src/librustc_apfloat/ppc.rs
index ddccfd6ca62..8e2e390568e 100644
--- a/src/librustc_apfloat/ppc.rs
+++ b/src/librustc_apfloat/ppc.rs
@@ -1,9 +1,9 @@
 use crate::{Category, ExpInt, Float, FloatConvert, Round, ParseError, Status, StatusAnd};
 use crate::ieee;
 
-use std::cmp::Ordering;
-use std::fmt;
-use std::ops::Neg;
+use core::cmp::Ordering;
+use core::fmt;
+use core::ops::Neg;
 
 #[must_use]
 #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 26091005f25..de481d22624 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -430,10 +430,13 @@ impl<'a> Linker for GccLinker<'a> {
             // Write an LD version script
             let res: io::Result<()> = try {
                 let mut f = BufWriter::new(File::create(&path)?);
-                writeln!(f, "{{\n  global:")?;
-                for sym in self.info.exports[&crate_type].iter() {
-                    debug!("    {};", sym);
-                    writeln!(f, "    {};", sym)?;
+                writeln!(f, "{{")?;
+                if !self.info.exports[&crate_type].is_empty() {
+                    writeln!(f, "  global:")?;
+                    for sym in self.info.exports[&crate_type].iter() {
+                        debug!("    {};", sym);
+                        writeln!(f, "    {};", sym)?;
+                    }
                 }
                 writeln!(f, "\n  local:\n    *;\n}};")?;
             };
diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs
index cdc54bb179e..4acbe0356b4 100644
--- a/src/librustc_codegen_ssa/base.rs
+++ b/src/librustc_codegen_ssa/base.rs
@@ -456,7 +456,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
         let arg_argv = param_argv;
 
         let (start_fn, args) = if use_start_lang_item {
-            let start_def_id = cx.tcx().require_lang_item(StartFnLangItem);
+            let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None);
             let start_fn = callee::resolve_and_get_fn(
                 cx,
                 start_def_id,
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 326140d09b6..ca0cf0a5a66 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -125,24 +125,8 @@ provide! { <'tcx> tcx, def_id, other, cdata,
             bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
         })
     }
-    optimized_mir => {
-        let mir = cdata.maybe_get_optimized_mir(tcx, def_id.index).unwrap_or_else(|| {
-            bug!("get_optimized_mir: missing MIR for `{:?}`", def_id)
-        });
-
-        let mir = tcx.arena.alloc(mir);
-
-        mir
-    }
-    promoted_mir => {
-        let promoted = cdata.maybe_get_promoted_mir(tcx, def_id.index).unwrap_or_else(|| {
-            bug!("get_promoted_mir: missing promoted MIR for `{:?}`", def_id)
-        });
-
-        let promoted = tcx.arena.alloc(promoted);
-
-        promoted
-    }
+    optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
+    promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
     mir_const_qualif => {
         (cdata.mir_const_qualif(def_id.index), tcx.arena.alloc(BitSet::new_empty(0)))
     }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index ce0dc51eb2b..9977a7fa1dc 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -450,11 +450,19 @@ impl<'a, 'tcx> CrateMetadata {
     pub fn is_proc_macro_crate(&self) -> bool {
         self.root.proc_macro_decls_static.is_some()
     }
+
     fn is_proc_macro(&self, id: DefIndex) -> bool {
         self.is_proc_macro_crate() &&
             self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some()
     }
 
+    fn entry_unless_proc_macro(&self, id: DefIndex) -> Option<Entry<'tcx>> {
+        match self.is_proc_macro(id) {
+            true => None,
+            false => Some(self.entry(id)),
+        }
+    }
+
     fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
         self.root.entries_index.lookup(self.blob.raw_bytes(), item_id)
     }
@@ -689,10 +697,8 @@ impl<'a, 'tcx> CrateMetadata {
     }
 
     pub fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
-        match self.is_proc_macro(id) {
-            true => None,
-            false => self.entry(id).deprecation.map(|depr| depr.decode(self)),
-        }
+        self.entry_unless_proc_macro(id)
+            .and_then(|entry| entry.deprecation.map(|depr| depr.decode(self)))
     }
 
     pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
@@ -902,22 +908,24 @@ impl<'a, 'tcx> CrateMetadata {
         self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
     }
 
-    pub fn maybe_get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Option<Body<'tcx>> {
-        match self.is_proc_macro(id) {
-            true => None,
-            false => self.entry(id).mir.map(|mir| mir.decode((self, tcx))),
-        }
+    pub fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
+        self.entry_unless_proc_macro(id)
+            .and_then(|entry| entry.mir.map(|mir| mir.decode((self, tcx))))
+            .unwrap_or_else(|| {
+                bug!("get_optimized_mir: missing MIR for `{:?}", self.local_def_id(id))
+            })
     }
 
-    pub fn maybe_get_promoted_mir(
+    pub fn get_promoted_mir(
         &self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
-    ) -> Option<IndexVec<Promoted, Body<'tcx>>> {
-        match self.is_proc_macro(id) {
-            true => None,
-            false => self.entry(id).promoted_mir.map(|promoted| promoted.decode((self, tcx)),)
-        }
+    ) -> IndexVec<Promoted, Body<'tcx>> {
+        self.entry_unless_proc_macro(id)
+            .and_then(|entry| entry.promoted_mir.map(|promoted| promoted.decode((self, tcx))))
+            .unwrap_or_else(|| {
+                bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id))
+            })
     }
 
     pub fn mir_const_qualif(&self, id: DefIndex) -> u8 {
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index ec85daccd47..d5890d00ea8 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -443,7 +443,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             _ => bug!("non_scalar_compare called on non-reference type: {}", ty),
         };
 
-        let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem);
+        let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem, None);
         let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]);
 
         let bool_ty = self.hir.bool_ty();
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 67d63e52b2b..5aa487d9016 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -519,6 +519,9 @@ pub fn const_variant_index<'tcx>(
     ecx.read_discriminant(op).unwrap().1
 }
 
+/// Turn an interpreter error into something to report to the user.
+/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
+/// Should be called only if the error is actually going to to be reported!
 pub fn error_to_const_error<'mir, 'tcx>(
     ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
     mut error: InterpErrorInfo<'tcx>,
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index b6146b6b722..f261fdc268b 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -237,9 +237,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         let r = match f(self) {
             Ok(val) => Some(val),
             Err(error) => {
-                let diagnostic = error_to_const_error(&self.ecx, error);
                 use rustc::mir::interpret::InterpError::*;
-                match diagnostic.error {
+                match error.kind {
                     Exit(_) => bug!("the CTFE program cannot exit"),
                     Unsupported(_)
                     | UndefinedBehavior(_)
@@ -248,6 +247,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                         // Ignore these errors.
                     }
                     Panic(_) => {
+                        let diagnostic = error_to_const_error(&self.ecx, error);
                         diagnostic.report_as_lint(
                             self.ecx.tcx,
                             "this expression will panic at runtime",
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 7f8ae883429..a77421ce150 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1752,7 +1752,10 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants<'tcx> {
                 fulfillment_cx.register_bound(&infcx,
                                               param_env,
                                               ty,
-                                              tcx.require_lang_item(lang_items::SyncTraitLangItem),
+                                              tcx.require_lang_item(
+                                                  lang_items::SyncTraitLangItem,
+                                                  Some(body.span)
+                                              ),
                                               cause);
                 if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
                     infcx.report_fulfillment_errors(&err, None, false);
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index c5561a1ae0d..f3e03e7f81d 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -897,7 +897,10 @@ where
     ) -> BasicBlock {
         let tcx = self.tcx();
         let unit_temp = Place::from(self.new_temp(tcx.mk_unit()));
-        let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
+        let free_func = tcx.require_lang_item(
+            lang_items::BoxFreeFnLangItem,
+            Some(self.source_info.span)
+        );
         let args = adt.variants[VariantIdx::new(0)].fields.iter().enumerate().map(|(i, f)| {
             let field = Field::new(i);
             let field_ty = f.ty(self.tcx(), substs);
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 53101499af1..55e7a10f1aa 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -649,7 +649,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
-        let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem);
+        let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
         traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span)
     }
 }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 06b1e7bfd4e..e9370429f3f 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -266,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let trait_ref = projection.to_poly_trait_ref(tcx);
 
         let is_fn = tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_some();
-        let gen_trait = tcx.require_lang_item(lang_items::GeneratorTraitLangItem);
+        let gen_trait = tcx.require_lang_item(lang_items::GeneratorTraitLangItem, cause_span);
         let is_gen = gen_trait == trait_ref.def_id();
         if !is_fn && !is_gen {
             debug!("deduce_sig_from_projection: not fn or generator");
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 53024d97c3b..440e7e5d0e3 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -743,8 +743,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // We do this to avoid suggesting code that ends up as `T: FooBar`,
                         // instead we suggest `T: Foo + Bar` in that case.
                         let mut has_bounds = false;
+                        let mut impl_trait = false;
                         if let Node::GenericParam(ref param) = hir.get(id) {
-                            has_bounds = !param.bounds.is_empty();
+                            match param.kind {
+                                hir::GenericParamKind::Type { synthetic: Some(_), .. } => {
+                                    // We've found `fn foo(x: impl Trait)` instead of
+                                    // `fn foo<T>(x: T)`. We want to suggest the correct
+                                    // `fn foo(x: impl Trait + TraitBound)` instead of
+                                    // `fn foo<T: TraitBound>(x: T)`. (#63706)
+                                    impl_trait = true;
+                                    has_bounds = param.bounds.len() > 1;
+                                }
+                                _ => {
+                                    has_bounds = !param.bounds.is_empty();
+                                }
+                            }
                         }
                         let sp = hir.span(id);
                         // `sp` only covers `T`, change it so that it covers
@@ -765,8 +778,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             sp,
                             &msg[..],
                             candidates.iter().map(|t| format!(
-                                "{}: {}{}",
+                                "{}{} {}{}",
                                 param,
+                                if impl_trait { " +" } else { ":" },
                                 self.tcx.def_path_str(t.def_id),
                                 if has_bounds { " +"} else { "" },
                             )),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2a3c422fe04..01fda54b1ea 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2622,7 +2622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                  span: Span,
                                  code: traits::ObligationCauseCode<'tcx>)
     {
-        let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem);
+        let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
         self.require_type_meets(ty, span, code, lang_item);
     }
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 9c6ea7d30cc..f95b3e44bf0 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -287,7 +287,7 @@ fn check_type_defn<'tcx, F>(
                 let last = idx == variant.fields.len() - 1;
                 fcx.register_bound(
                     field.ty,
-                    fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
+                    fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
                     traits::ObligationCause::new(
                         field.span,
                         fcx.body_id,
@@ -375,7 +375,7 @@ fn check_item_type(
         if forbid_unsized {
             fcx.register_bound(
                 item_ty,
-                fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
+                fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
                 traits::ObligationCause::new(ty_span, fcx.body_id, traits::MiscObligation),
             );
         }
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 5a4dc7be326..516be99ed6a 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -464,7 +464,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
         // it is *not* required (i.e., '?Sized')
         let sized_trait = self.cx
             .tcx
-            .require_lang_item(lang_items::SizedTraitLangItem);
+            .require_lang_item(lang_items::SizedTraitLangItem, None);
 
         let mut replacer = RegionReplacer {
             vid_to_region: &vid_to_region,
@@ -777,9 +777,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
     fn is_fn_ty(&self, tcx: TyCtxt<'_>, ty: &Type) -> bool {
         match &ty {
             &&Type::ResolvedPath { ref did, .. } => {
-                *did == tcx.require_lang_item(lang_items::FnTraitLangItem)
-                    || *did == tcx.require_lang_item(lang_items::FnMutTraitLangItem)
-                    || *did == tcx.require_lang_item(lang_items::FnOnceTraitLangItem)
+                *did == tcx.require_lang_item(lang_items::FnTraitLangItem, None)
+                    || *did == tcx.require_lang_item(lang_items::FnMutTraitLangItem, None)
+                    || *did == tcx.require_lang_item(lang_items::FnOnceTraitLangItem, None)
             }
             _ => false,
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b2ffede5eda..49711551132 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1037,7 +1037,7 @@ pub enum GenericBound {
 
 impl GenericBound {
     fn maybe_sized(cx: &DocContext<'_>) -> GenericBound {
-        let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem);
+        let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None);
         let empty = cx.tcx.intern_substs(&[]);
         let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
             Some(did), false, vec![], empty);
diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/fast_thread_local.rs
index f5a2e263d25..2e021980778 100644
--- a/src/libstd/sys/vxworks/fast_thread_local.rs
+++ b/src/libstd/sys/vxworks/fast_thread_local.rs
@@ -1,33 +1,10 @@
+// Copyright (c) 2019 Wind River Systems, Inc.
+
 #![cfg(target_thread_local)]
 #![unstable(feature = "thread_local_internals", issue = "0")]
 
-// Since what appears to be glibc 2.18 this symbol has been shipped which
-// GCC and clang both use to invoke destructors in thread_local globals, so
-// let's do the same!
-//
-// Note, however, that we run on lots older linuxes, as well as cross
-// compiling from a newer linux to an older linux, so we also have a
-// fallback implementation to use as well.
-//
-// Due to rust-lang/rust#18804, make sure this is not generic!
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
-    use crate::mem;
     use crate::sys_common::thread_local::register_dtor_fallback;
-
-    extern {
-        #[linkage = "extern_weak"]
-        static __dso_handle: *mut u8;
-        #[linkage = "extern_weak"]
-        static __cxa_thread_atexit_impl: *const libc::c_void;
-    }
-    if !__cxa_thread_atexit_impl.is_null() {
-        type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
-                                  arg: *mut u8,
-                                  dso_handle: *mut u8) -> libc::c_int;
-        mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
-            (dtor, t, &__dso_handle as *const _ as *mut _);
-        return
-    }
     register_dtor_fallback(t, dtor);
 }
 
diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs
index 6409acba573..36233de3cfb 100644
--- a/src/libsyntax/parse/literal.rs
+++ b/src/libsyntax/parse/literal.rs
@@ -104,7 +104,7 @@ impl LitKind {
 
         Ok(match kind {
             token::Bool => {
-                assert!(symbol == kw::True || symbol == kw::False);
+                assert!(symbol.is_bool_lit());
                 LitKind::Bool(symbol == kw::True)
             }
             token::Byte => return unescape_byte(&symbol.as_str())
@@ -261,7 +261,7 @@ impl Lit {
     /// Converts arbitrary token into an AST literal.
     crate fn from_token(token: &Token) -> Result<Lit, LitError> {
         let lit = match token.kind {
-            token::Ident(name, false) if name == kw::True || name == kw::False =>
+            token::Ident(name, false) if name.is_bool_lit() =>
                 token::Lit::new(token::Bool, name, None),
             token::Literal(lit) =>
                 lit,
diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs
index 78c9a289b37..823f880337d 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};
@@ -113,7 +114,7 @@ impl<'a> Parser<'a> {
         let mut pats = vec![first_pat];
         while self.eat_or_separator() {
             let pat = self.parse_pat(expected).map_err(|mut err| {
-                err.span_label(lo, "while parsing this or-pattern staring here");
+                err.span_label(lo, "while parsing this or-pattern starting here");
                 err
             })?;
             self.maybe_recover_unexpected_comma(pat.span, rc)?;
@@ -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,108 @@ impl<'a> Parser<'a> {
         })
     }
 
+    /// Parse a mutable binding with the `mut` token already eaten.
+    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();
+
+        // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
+        if let token::Interpolated(ref nt) = self.token.kind {
+             if let token::NtPat(_) = **nt {
+                 self.expected_ident_found().emit();
+             }
+        }
+
+        // Parse the pattern we hope to be an identifier.
+        let mut pat = self.parse_pat(Some("identifier"))?;
+
+        // Add `mut` to any binding in the parsed pattern.
+        let changed_any_binding = Self::make_all_value_bindings_mutable(&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, changed_any_binding),
+        }
+
+        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)
+    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))
+    }
+
+    /// Turn all by-value immutable bindings in a pattern into mutable bindings.
+    /// Returns `true` if any change was made.
+    fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool {
+        struct AddMut(bool);
+        impl MutVisitor for AddMut {
+            fn visit_pat(&mut self, pat: &mut P<Pat>) {
+                if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Immutable), ..)
+                    = pat.node
+                {
+                    *m = Mutability::Mutable;
+                    self.0 = true;
+                }
+                noop_visit_pat(pat, self);
+            }
+        }
+
+        let mut add_mut = AddMut(false);
+        add_mut.visit_pat(pat);
+        add_mut.0
+    }
+
+    /// Error on `mut $pat` where `$pat` is not an ident.
+    fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) {
+        let span = lo.to(pat.span);
+        let fix = pprust::pat_to_string(&pat);
+        let (problem, suggestion) = if changed_any_binding {
+            ("`mut` must be attached to each individual binding", "add `mut` to each binding")
         } else {
-            BindingMode::ByValue(Mutability::Mutable)
+            ("`mut` must be followed by a named binding", "remove the `mut` prefix")
         };
-        self.parse_pat_ident(binding_mode)
+        self.struct_span_err(span, problem)
+            .span_suggestion(span, suggestion, fix, Applicability::MachineApplicable)
+            .note("`mut` may be followed by `variable` and `variable @ pattern`")
+            .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 +563,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 +636,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/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs
index 3eb4d45045a..d4b13cc2e01 100644
--- a/src/libsyntax/parse/parser/path.rs
+++ b/src/libsyntax/parse/parser/path.rs
@@ -423,7 +423,7 @@ impl<'a> Parser<'a> {
                     // FIXME(const_generics): to distinguish between idents for types and consts,
                     // we should introduce a GenericArg::Ident in the AST and distinguish when
                     // lowering to the HIR. For now, idents for const args are not permitted.
-                    if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) {
+                    if self.token.is_bool_lit() {
                         self.parse_literal_maybe_minus()?
                     } else {
                         return Err(
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 1865f925165..fe3b51aa246 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -409,7 +409,7 @@ impl Token {
     crate fn expect_lit(&self) -> Lit {
         match self.kind {
             Literal(lit) => lit,
-            _=> panic!("`expect_lit` called on non-literal"),
+            _ => panic!("`expect_lit` called on non-literal"),
         }
     }
 
@@ -417,10 +417,8 @@ impl Token {
     /// for example a '-42', or one of the boolean idents).
     crate fn can_begin_literal_or_bool(&self) -> bool {
         match self.kind {
-            Literal(..)  => true,
-            BinOp(Minus) => true,
-            Ident(name, false) if name == kw::True => true,
-            Ident(name, false) if name == kw::False => true,
+            Literal(..) | BinOp(Minus) => true,
+            Ident(name, false) if name.is_bool_lit() => true,
             Interpolated(ref nt) => match **nt {
                 NtLiteral(..) => true,
                 _             => false,
@@ -457,6 +455,7 @@ impl Token {
     pub fn is_ident(&self) -> bool {
         self.ident().is_some()
     }
+
     /// Returns `true` if the token is a lifetime.
     crate fn is_lifetime(&self) -> bool {
         self.lifetime().is_some()
@@ -508,45 +507,43 @@ impl Token {
 
     /// Returns `true` if the token is a given keyword, `kw`.
     pub fn is_keyword(&self, kw: Symbol) -> bool {
-        self.ident().map(|(id, is_raw)| id.name == kw && !is_raw).unwrap_or(false)
+        self.is_non_raw_ident_where(|id| id.name == kw)
     }
 
     crate fn is_path_segment_keyword(&self) -> bool {
-        match self.ident() {
-            Some((id, false)) => id.is_path_segment_keyword(),
-            _ => false,
-        }
+        self.is_non_raw_ident_where(ast::Ident::is_path_segment_keyword)
     }
 
     // Returns true for reserved identifiers used internally for elided lifetimes,
     // unnamed method parameters, crate root module, error recovery etc.
     crate fn is_special_ident(&self) -> bool {
-        match self.ident() {
-            Some((id, false)) => id.is_special(),
-            _ => false,
-        }
+        self.is_non_raw_ident_where(ast::Ident::is_special)
     }
 
     /// Returns `true` if the token is a keyword used in the language.
     crate fn is_used_keyword(&self) -> bool {
-        match self.ident() {
-            Some((id, false)) => id.is_used_keyword(),
-            _ => false,
-        }
+        self.is_non_raw_ident_where(ast::Ident::is_used_keyword)
     }
 
     /// Returns `true` if the token is a keyword reserved for possible future use.
     crate fn is_unused_keyword(&self) -> bool {
-        match self.ident() {
-            Some((id, false)) => id.is_unused_keyword(),
-            _ => false,
-        }
+        self.is_non_raw_ident_where(ast::Ident::is_unused_keyword)
     }
 
     /// Returns `true` if the token is either a special identifier or a keyword.
     pub fn is_reserved_ident(&self) -> bool {
+        self.is_non_raw_ident_where(ast::Ident::is_reserved)
+    }
+
+    /// Returns `true` if the token is the identifier `true` or `false`.
+    crate fn is_bool_lit(&self) -> bool {
+        self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
+    }
+
+    /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
+    fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool {
         match self.ident() {
-            Some((id, false)) => id.is_reserved(),
+            Some((id, false)) => pred(id),
             _ => false,
         }
     }
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 2d8e97c1800..8833e03c72b 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -1083,6 +1083,11 @@ impl Symbol {
         self == kw::DollarCrate
     }
 
+    /// Returns `true` if the symbol is `true` or `false`.
+    pub fn is_bool_lit(self) -> bool {
+        self == kw::True || self == kw::False
+    }
+
     /// This symbol can be a raw identifier.
     pub fn can_be_raw(self) -> bool {
         self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword()
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/lang-item-missing-generator.stderr b/src/test/ui/lang-item-missing-generator.stderr
index d0cc4b81be6..fa13bf0b127 100644
--- a/src/test/ui/lang-item-missing-generator.stderr
+++ b/src/test/ui/lang-item-missing-generator.stderr
@@ -1,4 +1,8 @@
 error: requires `generator` lang_item
+  --> $DIR/lang-item-missing-generator.rs:15:17
+   |
+LL | pub fn abc() -> impl FnOnce(f32) {
+   |                 ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs
index 4a9fae1406a..b9bfb8638b2 100644
--- a/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs
+++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs
@@ -3,7 +3,7 @@
 fn main() {
     match Some(42) {
         Some(42) | .=. => {} //~ ERROR expected pattern, found `.`
-        //~^ while parsing this or-pattern staring here
+        //~^ while parsing this or-pattern starting here
         //~| NOTE expected pattern
     }
 }
diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr
index 21fece6c64f..7ad62ff99ee 100644
--- a/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr
+++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr
@@ -4,7 +4,7 @@ error: expected pattern, found `.`
 LL |         Some(42) | .=. => {}
    |         --------   ^ expected pattern
    |         |
-   |         while parsing this or-pattern staring here
+   |         while parsing this or-pattern starting here
 
 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..500242030c6 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 followed by a named binding
 }
diff --git a/src/test/ui/parser/issue-32501.stderr b/src/test/ui/parser/issue-32501.stderr
index 97efb895935..d53302449a8 100644
--- a/src/test/ui/parser/issue-32501.stderr
+++ b/src/test/ui/parser/issue-32501.stderr
@@ -1,8 +1,10 @@
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-32501.rs:7:13
+error: `mut` must be followed by a named binding
+  --> $DIR/issue-32501.rs:7:9
    |
 LL |     let mut _ = 0;
-   |             ^ expected identifier, found reserved identifier
+   |         ^^^^^ help: remove the `mut` prefix: `_`
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
 
 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..d46186a0fea 100644
--- a/src/test/ui/parser/mut-patterns.rs
+++ b/src/test/ui/parser/mut-patterns.rs
@@ -1,7 +1,46 @@
 // Can't put mut in non-ident pattern
 
+// edition:2018
+
+#![feature(box_patterns)]
+#![allow(warnings)]
+
 pub fn main() {
+    let mut _ = 0; //~ ERROR `mut` must be followed by a named binding
+    let mut (_, _) = (0, 0); //~ ERROR `mut` must be followed by a named binding
+
+    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) }))));
+
+    // Make sure we don't accidentally allow `mut $p` where `$p:pat`.
+    macro_rules! foo {
+        ($p:pat) => {
+            let mut $p = 0; //~ ERROR expected identifier, found `x`
+        }
+    }
+    foo!(x);
 }
diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr
index b39209afd42..18ffaa52558 100644
--- a/src/test/ui/parser/mut-patterns.stderr
+++ b/src/test/ui/parser/mut-patterns.stderr
@@ -1,8 +1,101 @@
-error: expected one of `:`, `;`, `=`, `@`, or `|`, found `{`
-  --> $DIR/mut-patterns.rs:5:17
+error: `mut` must be followed by a named binding
+  --> $DIR/mut-patterns.rs:9:9
+   |
+LL |     let mut _ = 0;
+   |         ^^^^^ help: remove the `mut` prefix: `_`
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: `mut` must be followed by a named binding
+  --> $DIR/mut-patterns.rs:10:9
+   |
+LL |     let mut (_, _) = (0, 0);
+   |         ^^^^^^^^^^ help: remove the `mut` prefix: `(_, _)`
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: `mut` on a binding may not be repeated
+  --> $DIR/mut-patterns.rs:12: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:17: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 }`
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: `mut` must be attached to each individual binding
+  --> $DIR/mut-patterns.rs:21:9
+   |
+LL |     let mut Foo { x } = Foo { x: 3 };
+   |         ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }`
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: `mut` on a binding may not be repeated
+  --> $DIR/mut-patterns.rs:26: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:26: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:26: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:26: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:26: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)`
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: `mut` must be attached to each individual binding
+  --> $DIR/mut-patterns.rs:35: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 }))))`
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
+
+error: expected identifier, found `x`
+  --> $DIR/mut-patterns.rs:42:21
+   |
+LL |             let mut $p = 0;
+   |                     ^^ expected identifier
+...
+LL |     foo!(x);
+   |     -------- in this macro invocation
 
-error: aborting due to previous error
+error: aborting due to 12 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..844f13c2f89 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 followed by a named 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..bb631194bf3 100644
--- a/src/test/ui/self/self_type_keyword.stderr
+++ b/src/test/ui/self/self_type_keyword.stderr
@@ -10,38 +10,40 @@ 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 followed by a named binding
+  --> $DIR/self_type_keyword.rs:16:9
    |
 LL |         mut Self => (),
-   |             ^^^^ expected identifier, found keyword
+   |         ^^^^^^^^ help: remove the `mut` prefix: `Self`
+   |
+   = note: `mut` may be followed by `variable` and `variable @ pattern`
 
 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 +55,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 +78,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`.
diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed
new file mode 100644
index 00000000000..5109511f95a
--- /dev/null
+++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+
+trait Foo {}
+
+trait Bar {
+    fn hello(&self) {}
+}
+
+struct S;
+
+impl Foo for S {}
+impl Bar for S {}
+
+fn test(foo: impl Foo + Bar) {
+    foo.hello(); //~ ERROR E0599
+}
+
+fn main() {
+    test(S);
+}
diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs
new file mode 100644
index 00000000000..cd05b773861
--- /dev/null
+++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs
@@ -0,0 +1,20 @@
+// run-rustfix
+
+trait Foo {}
+
+trait Bar {
+    fn hello(&self) {}
+}
+
+struct S;
+
+impl Foo for S {}
+impl Bar for S {}
+
+fn test(foo: impl Foo) {
+    foo.hello(); //~ ERROR E0599
+}
+
+fn main() {
+    test(S);
+}
diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
new file mode 100644
index 00000000000..48c2503e8eb
--- /dev/null
+++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr
@@ -0,0 +1,15 @@
+error[E0599]: no method named `hello` found for type `impl Foo` in the current scope
+  --> $DIR/impl-trait-with-missing-trait-bounds-in-arg.rs:15:9
+   |
+LL |     foo.hello();
+   |         ^^^^^
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `hello`, perhaps you need to restrict type parameter `impl Foo` with it:
+   |
+LL | fn test(foo: impl Foo + Bar) {
+   |              ^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 648838d26ef..1411f4c0b05 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -22,7 +22,7 @@ except ImportError:
 # List of people to ping when the status of a tool or a book changed.
 MAINTAINERS = {
     'miri': '@oli-obk @RalfJung @eddyb',
-    'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch',
+    'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch @flip1995',
     'rls': '@Xanewok',
     'rustfmt': '@topecongiro',
     'book': '@carols10cents @steveklabnik',