about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ty/util.rs40
-rw-r--r--src/librustc_ast_lowering/item.rs102
-rw-r--r--src/librustc_ast_lowering/lib.rs2
-rw-r--r--src/librustc_ast_passes/ast_validation.rs97
-rw-r--r--src/librustc_ast_passes/feature_gate.rs10
-rw-r--r--src/librustc_ast_pretty/pprust.rs135
-rw-r--r--src/librustc_builtin_macros/deriving/generic/mod.rs5
-rw-r--r--src/librustc_builtin_macros/test.rs148
-rw-r--r--src/librustc_expand/build.rs4
-rw-r--r--src/librustc_expand/mbe/macro_parser.rs2
-rw-r--r--src/librustc_expand/mbe/macro_rules.rs1
-rw-r--r--src/librustc_expand/placeholders.rs3
-rw-r--r--src/librustc_interface/util.rs2
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs25
-rw-r--r--src/librustc_parse/lib.rs7
-rw-r--r--src/librustc_parse/parser/expr.rs4
-rw-r--r--src/librustc_parse/parser/item.rs215
-rw-r--r--src/librustc_parse/parser/mod.rs100
-rw-r--r--src/librustc_parse/parser/pat.rs29
-rw-r--r--src/librustc_parse/parser/path.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs9
-rw-r--r--src/librustc_resolve/def_collector.rs10
-rw-r--r--src/librustc_resolve/late.rs194
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs32
-rw-r--r--src/librustc_save_analysis/lib.rs4
-rw-r--r--src/librustc_save_analysis/sig.rs23
-rw-r--r--src/librustc_typeck/check/op.rs33
-rw-r--r--src/librustc_typeck/collect.rs50
-rw-r--r--src/libsyntax/ast.rs101
-rw-r--r--src/libsyntax/mut_visit.rs51
-rw-r--r--src/libsyntax/visit.rs56
-rw-r--r--src/test/run-make-fulldeps/min-global-align/min_global_align.rs10
-rw-r--r--src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs11
-rw-r--r--src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr23
-rw-r--r--src/test/ui/autoderef-full-lval.stderr4
-rw-r--r--src/test/ui/binop/binop-bitxor-str.stderr2
-rw-r--r--src/test/ui/binop/binop-mul-bool.stderr2
-rw-r--r--src/test/ui/binop/binop-typeck.stderr2
-rw-r--r--src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr4
-rw-r--r--src/test/ui/destructuring-assignment/note-unsupported.stderr4
-rw-r--r--src/test/ui/did_you_mean/issue-40006.rs4
-rw-r--r--src/test/ui/did_you_mean/issue-40006.stderr24
-rw-r--r--src/test/ui/error-codes/E0067.stderr2
-rw-r--r--src/test/ui/error-festival.stderr2
-rw-r--r--src/test/ui/extern/extern-const.stderr8
-rw-r--r--src/test/ui/for/for-loop-type-error.stderr2
-rw-r--r--src/test/ui/issues/issue-14915.stderr2
-rw-r--r--src/test/ui/issues/issue-24363.stderr2
-rw-r--r--src/test/ui/issues/issue-31076.stderr4
-rw-r--r--src/test/ui/issues/issue-35668.stderr2
-rw-r--r--src/test/ui/issues/issue-40610.stderr2
-rw-r--r--src/test/ui/issues/issue-41394.stderr2
-rw-r--r--src/test/ui/issues/issue-58856-2.stderr4
-rw-r--r--src/test/ui/issues/issue-59488.stderr3
-rw-r--r--src/test/ui/issues/issue-60075.stderr2
-rw-r--r--src/test/ui/issues/issue-6596-1.rs2
-rw-r--r--src/test/ui/issues/issue-6596-1.stderr4
-rw-r--r--src/test/ui/issues/issue-6596-2.rs2
-rw-r--r--src/test/ui/issues/issue-6596-2.stderr4
-rw-r--r--src/test/ui/macros/issue-54441.rs2
-rw-r--r--src/test/ui/macros/issue-54441.stderr4
-rw-r--r--src/test/ui/minus-string.stderr2
-rw-r--r--src/test/ui/parser/assoc-const-underscore-semantic-fail.rs17
-rw-r--r--src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr27
-rw-r--r--src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs18
-rw-r--r--src/test/ui/parser/assoc-static-semantic-fail.rs43
-rw-r--r--src/test/ui/parser/assoc-static-semantic-fail.stderr99
-rw-r--r--src/test/ui/parser/assoc-static-syntactic-fail.rs27
-rw-r--r--src/test/ui/parser/assoc-static-syntactic-fail.stderr74
-rw-r--r--src/test/ui/parser/default.rs2
-rw-r--r--src/test/ui/parser/default.stderr4
-rw-r--r--src/test/ui/parser/duplicate-visibility.rs2
-rw-r--r--src/test/ui/parser/duplicate-visibility.stderr4
-rw-r--r--src/test/ui/parser/extern-no-fn.rs3
-rw-r--r--src/test/ui/parser/extern-no-fn.stderr5
-rw-r--r--src/test/ui/parser/foreign-const-semantic-fail.rs8
-rw-r--r--src/test/ui/parser/foreign-const-semantic-fail.stderr22
-rw-r--r--src/test/ui/parser/foreign-const-syntactic-fail.rs9
-rw-r--r--src/test/ui/parser/foreign-const-syntactic-fail.stderr22
-rw-r--r--src/test/ui/parser/foreign-static-semantic-fail.rs8
-rw-r--r--src/test/ui/parser/foreign-static-semantic-fail.stderr27
-rw-r--r--src/test/ui/parser/foreign-static-syntactic-pass.rs11
-rw-r--r--src/test/ui/parser/foreign-ty-semantic-fail.rs18
-rw-r--r--src/test/ui/parser/foreign-ty-semantic-fail.stderr65
-rw-r--r--src/test/ui/parser/foreign-ty-syntactic-pass.rs12
-rw-r--r--src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs4
-rw-r--r--src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr4
-rw-r--r--src/test/ui/parser/issue-19398.rs2
-rw-r--r--src/test/ui/parser/issue-19398.stderr4
-rw-r--r--src/test/ui/parser/issue-21153.rs3
-rw-r--r--src/test/ui/parser/issue-21153.stderr5
-rw-r--r--src/test/ui/parser/issue-32446.stderr4
-rw-r--r--src/test/ui/parser/issue-41155.stderr4
-rw-r--r--src/test/ui/parser/item-free-const-no-body-semantic-fail.rs7
-rw-r--r--src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr24
-rw-r--r--src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs8
-rw-r--r--src/test/ui/parser/item-free-static-no-body-semantic-fail.rs11
-rw-r--r--src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr46
-rw-r--r--src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs8
-rw-r--r--src/test/ui/parser/macro/trait-non-item-macros.stderr4
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs2
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr4
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs2
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr4
-rw-r--r--src/test/ui/parser/mut-patterns.rs2
-rw-r--r--src/test/ui/parser/mut-patterns.stderr30
-rw-r--r--src/test/ui/parser/removed-syntax-extern-const.rs6
-rw-r--r--src/test/ui/parser/removed-syntax-extern-const.stderr8
-rw-r--r--src/test/ui/parser/removed-syntax-static-fn.rs4
-rw-r--r--src/test/ui/parser/removed-syntax-static-fn.stderr25
-rw-r--r--src/test/ui/parser/underscore_item_not_const.rs16
-rw-r--r--src/test/ui/parser/underscore_item_not_const.stderr44
-rw-r--r--src/test/ui/pattern/pattern-tyvar-2.stderr2
-rw-r--r--src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs17
-rw-r--r--src/test/ui/proc-macro/generate-dollar-ident.rs18
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr6
-rw-r--r--src/test/ui/span/issue-39018.stderr4
-rw-r--r--src/test/ui/traits/trait-resolution-in-overloaded-op.stderr2
-rw-r--r--src/test/ui/unop-neg-bool.stderr2
-rw-r--r--src/test/ui/vec/vec-res-add.stderr2
122 files changed, 1576 insertions, 936 deletions
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index f3c3d04931a..cb43f7475b8 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -697,7 +697,7 @@ impl<'tcx> ty::TyS<'tcx> {
     /// strange rules like `<T as Foo<'static>>::Bar: Sized` that
     /// actually carry lifetime requirements.
     pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-        tcx_at.is_sized_raw(param_env.and(self))
+        self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self))
     }
 
     /// Checks whether values of this type `T` implement the `Freeze`
@@ -713,7 +713,43 @@ impl<'tcx> ty::TyS<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         span: Span,
     ) -> bool {
-        tcx.at(span).is_freeze_raw(param_env.and(self))
+        self.is_trivially_freeze() || tcx.at(span).is_freeze_raw(param_env.and(self))
+    }
+
+    /// Fast path helper for testing if a type is `Freeze`.
+    ///
+    /// Returning true means the type is known to be `Freeze`. Returning
+    /// `false` means nothing -- could be `Freeze`, might not be.
+    fn is_trivially_freeze(&self) -> bool {
+        match self.kind {
+            ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Bool
+            | ty::Char
+            | ty::Str
+            | ty::Never
+            | ty::Ref(..)
+            | ty::RawPtr(_)
+            | ty::FnDef(..)
+            | ty::Error
+            | ty::FnPtr(_) => true,
+            ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze),
+            ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
+            ty::Adt(..)
+            | ty::Bound(..)
+            | ty::Closure(..)
+            | ty::Dynamic(..)
+            | ty::Foreign(_)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(_)
+            | ty::Infer(_)
+            | ty::Opaque(..)
+            | ty::Param(_)
+            | ty::Placeholder(_)
+            | ty::Projection(_)
+            | ty::UnnormalizedProjection(_) => false,
+        }
     }
 
     /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index 426659fd924..e0db8606bc2 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -269,26 +269,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs)
             }
             ItemKind::Static(ref t, m, ref e) => {
-                let ty = self.lower_ty(
-                    t,
-                    if self.sess.features_untracked().impl_trait_in_bindings {
-                        ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
-                    } else {
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
-                    },
-                );
-                hir::ItemKind::Static(ty, m, self.lower_const_body(span, Some(e)))
+                let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
+                hir::ItemKind::Static(ty, m, body_id)
             }
             ItemKind::Const(ref t, ref e) => {
-                let ty = self.lower_ty(
-                    t,
-                    if self.sess.features_untracked().impl_trait_in_bindings {
-                        ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
-                    } else {
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
-                    },
-                );
-                hir::ItemKind::Const(ty, self.lower_const_body(span, Some(e)))
+                let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
+                hir::ItemKind::Const(ty, body_id)
             }
             ItemKind::Fn(FnSig { ref decl, header }, ref generics, ref body) => {
                 let fn_def_id = self.resolver.definitions().local_def_id(id);
@@ -457,6 +443,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
         //     not cause an assertion failure inside the `lower_defaultness` function.
     }
 
+    fn lower_const_item(
+        &mut self,
+        ty: &Ty,
+        span: Span,
+        body: Option<&Expr>,
+    ) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
+        let itctx = if self.sess.features_untracked().impl_trait_in_bindings {
+            ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
+        } else {
+            ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
+        };
+        let ty = self.lower_ty(ty, itctx);
+        (ty, self.lower_const_body(span, body))
+    }
+
     fn lower_use_tree(
         &mut self,
         tree: &UseTree,
@@ -678,11 +679,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
                     hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
                 }
-                ForeignItemKind::Static(ref t, m) => {
+                ForeignItemKind::Static(ref t, m, _) => {
                     let ty = self.lower_ty(t, ImplTraitContext::disallowed());
                     hir::ForeignItemKind::Static(ty, m)
                 }
-                ForeignItemKind::Ty => hir::ForeignItemKind::Type,
+                ForeignItemKind::Const(ref t, _) => {
+                    // For recovery purposes.
+                    let ty = self.lower_ty(t, ImplTraitContext::disallowed());
+                    hir::ForeignItemKind::Static(ty, Mutability::Not)
+                }
+                ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
                 ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"),
             },
             vis: self.lower_visibility(&i.vis, None),
@@ -759,32 +765,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let trait_item_def_id = self.resolver.definitions().local_def_id(i.id);
 
         let (generics, kind) = match i.kind {
-            AssocItemKind::Const(ref ty, ref default) => {
-                let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
+            AssocItemKind::Static(ref ty, _, ref default) // Let's pretend this is a `const`.
+            | AssocItemKind::Const(ref ty, ref default) => {
                 let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
-                (
-                    generics,
-                    hir::TraitItemKind::Const(
-                        ty,
-                        default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))),
-                    ),
-                )
+                let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
+                (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
             }
-            AssocItemKind::Fn(ref sig, None) => {
+            AssocItemKind::Fn(ref sig, ref generics, None) => {
                 let names = self.lower_fn_params_to_names(&sig.decl);
                 let (generics, sig) =
-                    self.lower_method_sig(&i.generics, sig, trait_item_def_id, false, None);
+                    self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names)))
             }
-            AssocItemKind::Fn(ref sig, Some(ref body)) => {
+            AssocItemKind::Fn(ref sig, ref generics, Some(ref body)) => {
                 let body_id = self.lower_fn_body_block(i.span, &sig.decl, Some(body));
                 let (generics, sig) =
-                    self.lower_method_sig(&i.generics, sig, trait_item_def_id, false, None);
+                    self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
                 (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
             }
-            AssocItemKind::TyAlias(ref bounds, ref default) => {
+            AssocItemKind::TyAlias(ref generics, ref bounds, ref default) => {
                 let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
-                let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
+                let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
                 let kind = hir::TraitItemKind::Type(
                     self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
                     ty,
@@ -806,10 +807,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
-        let (kind, has_default) = match i.kind {
-            AssocItemKind::Const(_, ref default) => (hir::AssocItemKind::Const, default.is_some()),
-            AssocItemKind::TyAlias(_, ref default) => (hir::AssocItemKind::Type, default.is_some()),
-            AssocItemKind::Fn(ref sig, ref default) => {
+        let (kind, has_default) = match &i.kind {
+            AssocItemKind::Static(_, _, default) // Let's pretend this is a `const` for recovery.
+            | AssocItemKind::Const(_, default) => {
+                (hir::AssocItemKind::Const, default.is_some())
+            }
+            AssocItemKind::TyAlias(_, _, default) => (hir::AssocItemKind::Type, default.is_some()),
+            AssocItemKind::Fn(sig, _, default) => {
                 (hir::AssocItemKind::Method { has_self: sig.decl.has_self() }, default.is_some())
             }
             AssocItemKind::Macro(..) => unimplemented!(),
@@ -832,22 +836,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let impl_item_def_id = self.resolver.definitions().local_def_id(i.id);
 
         let (generics, kind) = match i.kind {
-            AssocItemKind::Const(ref ty, ref expr) => {
-                let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
+            AssocItemKind::Static(ref ty, _, ref expr) | AssocItemKind::Const(ref ty, ref expr) => {
                 let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
                 (
-                    generics,
+                    hir::Generics::empty(),
                     hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
                 )
             }
-            AssocItemKind::Fn(ref sig, ref body) => {
+            AssocItemKind::Fn(ref sig, ref generics, ref body) => {
                 self.current_item = Some(i.span);
                 let asyncness = sig.header.asyncness;
                 let body_id =
                     self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref());
                 let impl_trait_return_allow = !self.is_in_trait_impl;
                 let (generics, sig) = self.lower_method_sig(
-                    &i.generics,
+                    generics,
                     sig,
                     impl_item_def_id,
                     impl_trait_return_allow,
@@ -856,8 +859,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
             }
-            AssocItemKind::TyAlias(_, ref ty) => {
-                let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed());
+            AssocItemKind::TyAlias(ref generics, _, ref ty) => {
+                let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
                 let kind = match ty {
                     None => {
                         let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err));
@@ -901,14 +904,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
             vis: self.lower_visibility(&i.vis, Some(i.id)),
             defaultness: self.lower_defaultness(i.defaultness, true /* [1] */),
             kind: match &i.kind {
-                AssocItemKind::Const(..) => hir::AssocItemKind::Const,
-                AssocItemKind::TyAlias(_, ty) => {
+                AssocItemKind::Static(..) // Let's pretend this is a `const` for recovery.
+                | AssocItemKind::Const(..) => hir::AssocItemKind::Const,
+                AssocItemKind::TyAlias(_, _, ty) => {
                     match ty.as_deref().and_then(|ty| ty.kind.opaque_top_hack()) {
                         None => hir::AssocItemKind::Type,
                         Some(_) => hir::AssocItemKind::OpaqueTy,
                     }
                 }
-                AssocItemKind::Fn(sig, _) => {
+                AssocItemKind::Fn(sig, _, _) => {
                     hir::AssocItemKind::Method { has_self: sig.decl.has_self() }
                 }
                 AssocItemKind::Macro(..) => unimplemented!(),
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 56c844b37da..ac4ca30382f 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -490,7 +490,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 self.lctx.allocate_hir_id_counter(item.id);
                 let owner = match (&item.kind, ctxt) {
                     // Ignore patterns in trait methods without bodies.
-                    (AssocItemKind::Fn(_, None), AssocCtxt::Trait) => None,
+                    (AssocItemKind::Fn(_, _, None), AssocCtxt::Trait) => None,
                     _ => Some(item.id),
                 };
                 self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt));
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 584f7b4b4bb..1194269e0ee 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -22,6 +22,9 @@ use syntax::expand::is_proc_macro_attr;
 use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use syntax::walk_list;
 
+const MORE_EXTERN: &str =
+    "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
+
 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
 enum SelfSemantic {
     Yes,
@@ -423,14 +426,62 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
+    fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
         let span = match bounds {
             [] => return,
             [b0] => b0.span(),
             [b0, .., bl] => b0.span().to(bl.span()),
         };
         self.err_handler()
-            .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
+            .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
+            .emit();
+    }
+
+    fn check_foreign_ty_genericless(&self, generics: &Generics) {
+        let cannot_have = |span, descr, remove_descr| {
+            self.err_handler()
+                .struct_span_err(
+                    span,
+                    &format!("`type`s inside `extern` blocks cannot have {}", descr),
+                )
+                .span_suggestion(
+                    span,
+                    &format!("remove the {}", remove_descr),
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                )
+                .span_label(self.current_extern_span(), "`extern` block begins here")
+                .note(MORE_EXTERN)
+                .emit();
+        };
+
+        if !generics.params.is_empty() {
+            cannot_have(generics.span, "generic parameters", "generic parameters");
+        }
+
+        if !generics.where_clause.predicates.is_empty() {
+            cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
+        }
+    }
+
+    fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
+        let body = match body {
+            None => return,
+            Some(body) => body,
+        };
+        self.err_handler()
+            .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
+            .span_label(ident.span, "cannot have a body")
+            .span_label(body, "the invalid body")
+            .span_label(
+                self.current_extern_span(),
+                format!(
+                    "`extern` blocks define existing foreign {0}s and {0}s \
+                    inside of them cannot have a body",
+                    kind
+                ),
+            )
+            .note(MORE_EXTERN)
             .emit();
     }
 
@@ -458,7 +509,7 @@ impl<'a> AstValidator<'a> {
                 "`extern` blocks define existing foreign functions and functions \
                 inside of them cannot have a body",
             )
-            .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
+            .note(MORE_EXTERN)
             .emit();
     }
 
@@ -531,6 +582,16 @@ impl<'a> AstValidator<'a> {
             }
         }
     }
+
+    fn check_item_named(&self, ident: Ident, kind: &str) {
+        if ident.name != kw::Underscore {
+            return;
+        }
+        self.err_handler()
+            .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
+            .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
+            .emit();
+    }
 }
 
 enum GenericPosition {
@@ -900,6 +961,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     self.err_handler().span_err(item.span, "unions cannot have zero fields");
                 }
             }
+            ItemKind::Const(.., None) => {
+                let msg = "free constant item without body";
+                self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
+            }
+            ItemKind::Static(.., None) => {
+                let msg = "free static item without body";
+                self.error_item_without_body(item.span, "static", msg, " = <expr>;");
+            }
             _ => {}
         }
 
@@ -912,7 +981,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
                 self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
             }
-            ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
+            ForeignItemKind::TyAlias(generics, bounds, body) => {
+                self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
+                self.check_type_no_bounds(bounds, "`extern` blocks");
+                self.check_foreign_ty_genericless(generics);
+            }
+            ForeignItemKind::Static(_, _, body) => {
+                self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
+            }
+            ForeignItemKind::Const(..) | ForeignItemKind::Macro(..) => {}
         }
 
         visit::walk_foreign_item(self, fi)
@@ -1154,12 +1231,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 AssocItemKind::Const(_, body) => {
                     self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
                 }
-                AssocItemKind::Fn(_, body) => {
+                AssocItemKind::Fn(_, _, body) => {
                     self.check_impl_item_provided(item.span, body, "function", " { <body> }");
                 }
-                AssocItemKind::TyAlias(bounds, body) => {
+                AssocItemKind::TyAlias(_, bounds, body) => {
                     self.check_impl_item_provided(item.span, body, "type", " = <type>;");
-                    self.check_impl_assoc_type_no_bounds(bounds);
+                    self.check_type_no_bounds(bounds, "`impl`s");
                 }
                 _ => {}
             }
@@ -1167,12 +1244,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
         if ctxt == AssocCtxt::Trait || self.in_trait_impl {
             self.invalid_visibility(&item.vis, None);
-            if let AssocItemKind::Fn(sig, _) = &item.kind {
+            if let AssocItemKind::Fn(sig, _, _) = &item.kind {
                 self.check_trait_fn_not_const(sig.header.constness);
                 self.check_trait_fn_not_async(item.span, sig.header.asyncness);
             }
         }
 
+        if let AssocItemKind::Const(..) = item.kind {
+            self.check_item_named(item.ident, "const");
+        }
+
         self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
     }
 }
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index d57c7495a07..3c924847a73 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -397,10 +397,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     );
                 }
             }
-            ast::ForeignItemKind::Ty => {
+            ast::ForeignItemKind::TyAlias(..) => {
                 gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
             }
-            ast::ForeignItemKind::Macro(..) => {}
+            ast::ForeignItemKind::Macro(..) | ast::ForeignItemKind::Const(..) => {}
         }
 
         visit::walk_foreign_item(self, i)
@@ -548,12 +548,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         }
 
         match i.kind {
-            ast::AssocItemKind::Fn(ref sig, _) => {
+            ast::AssocItemKind::Fn(ref sig, _, _) => {
                 if let (ast::Const::Yes(_), AssocCtxt::Trait) = (sig.header.constness, ctxt) {
                     gate_feature_post!(&self, const_fn, i.span, "const fn is unstable");
                 }
             }
-            ast::AssocItemKind::TyAlias(_, ref ty) => {
+            ast::AssocItemKind::TyAlias(ref generics, _, ref ty) => {
                 if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
                     gate_feature_post!(
                         &self,
@@ -565,7 +565,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 if let Some(ty) = ty {
                     self.check_impl_trait(ty);
                 }
-                self.check_gat(&i.generics, i.span);
+                self.check_gat(generics, i.span);
             }
             _ => {}
         }
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 20b1ff06034..6e1567ce34e 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -912,7 +912,7 @@ impl<'a> State<'a> {
         }
     }
 
-    crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
+    crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[Attribute]) {
         self.print_inner_attributes(attrs);
         for item in &nmod.items {
             self.print_foreign_item(item);
@@ -1016,59 +1016,73 @@ impl<'a> State<'a> {
     }
 
     crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+        let ast::ForeignItem { id, span, ident, attrs, kind, vis, tokens: _ } = item;
+        self.print_nested_item_kind(*id, *span, *ident, attrs, ast::Defaultness::Final, kind, vis);
+    }
+
+    fn print_nested_item_kind(
+        &mut self,
+        id: ast::NodeId,
+        span: Span,
+        ident: ast::Ident,
+        attrs: &[Attribute],
+        defaultness: ast::Defaultness,
+        kind: &ast::AssocItemKind,
+        vis: &ast::Visibility,
+    ) {
+        self.ann.pre(self, AnnNode::SubItem(id));
         self.hardbreak_if_not_bol();
-        self.maybe_print_comment(item.span.lo());
-        self.print_outer_attributes(&item.attrs);
-        match item.kind {
-            ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => {
-                self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
+        self.maybe_print_comment(span.lo());
+        self.print_outer_attributes(attrs);
+        self.print_defaultness(defaultness);
+        match kind {
+            ast::ForeignItemKind::Fn(sig, gen, body) => {
+                self.print_fn_full(sig, ident, gen, vis, body.as_deref(), attrs);
             }
-            ast::ForeignItemKind::Static(ref t, m) => {
-                self.head(visibility_qualified(&item.vis, "static"));
-                if m == ast::Mutability::Mut {
-                    self.word_space("mut");
-                }
-                self.print_ident(item.ident);
-                self.word_space(":");
-                self.print_type(t);
-                self.s.word(";");
-                self.end(); // end the head-ibox
-                self.end(); // end the outer cbox
+            ast::ForeignItemKind::Const(ty, body) => {
+                self.print_item_const(ident, None, ty, body.as_deref(), vis);
             }
-            ast::ForeignItemKind::Ty => {
-                self.head(visibility_qualified(&item.vis, "type"));
-                self.print_ident(item.ident);
-                self.s.word(";");
-                self.end(); // end the head-ibox
-                self.end(); // end the outer cbox
+            ast::ForeignItemKind::Static(ty, mutbl, body) => {
+                self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis);
+            }
+            ast::ForeignItemKind::TyAlias(generics, bounds, ty) => {
+                self.print_associated_type(ident, generics, bounds, ty.as_deref());
             }
-            ast::ForeignItemKind::Macro(ref m) => {
+            ast::ForeignItemKind::Macro(m) => {
                 self.print_mac(m);
                 if m.args.need_semicolon() {
                     self.s.word(";");
                 }
             }
         }
+        self.ann.post(self, AnnNode::SubItem(id))
     }
 
-    fn print_associated_const(
+    fn print_item_const(
         &mut self,
         ident: ast::Ident,
+        mutbl: Option<ast::Mutability>,
         ty: &ast::Ty,
-        default: Option<&ast::Expr>,
+        body: Option<&ast::Expr>,
         vis: &ast::Visibility,
     ) {
-        self.s.word(visibility_qualified(vis, ""));
-        self.word_space("const");
+        let leading = match mutbl {
+            None => "const",
+            Some(ast::Mutability::Not) => "static",
+            Some(ast::Mutability::Mut) => "static mut",
+        };
+        self.head(visibility_qualified(vis, leading));
         self.print_ident(ident);
         self.word_space(":");
         self.print_type(ty);
-        if let Some(expr) = default {
-            self.s.space();
+        self.s.space();
+        self.end(); // end the head-ibox
+        if let Some(body) = body {
             self.word_space("=");
-            self.print_expr(expr);
+            self.print_expr(body);
         }
-        self.s.word(";")
+        self.s.word(";");
+        self.end(); // end the outer cbox
     }
 
     fn print_associated_type(
@@ -1118,34 +1132,11 @@ impl<'a> State<'a> {
                 self.end(); // end inner head-block
                 self.end(); // end outer head-block
             }
-            ast::ItemKind::Static(ref ty, m, ref expr) => {
-                self.head(visibility_qualified(&item.vis, "static"));
-                if m == ast::Mutability::Mut {
-                    self.word_space("mut");
-                }
-                self.print_ident(item.ident);
-                self.word_space(":");
-                self.print_type(ty);
-                self.s.space();
-                self.end(); // end the head-ibox
-
-                self.word_space("=");
-                self.print_expr(expr);
-                self.s.word(";");
-                self.end(); // end the outer cbox
+            ast::ItemKind::Static(ref ty, mutbl, ref body) => {
+                self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis);
             }
-            ast::ItemKind::Const(ref ty, ref expr) => {
-                self.head(visibility_qualified(&item.vis, "const"));
-                self.print_ident(item.ident);
-                self.word_space(":");
-                self.print_type(ty);
-                self.s.space();
-                self.end(); // end the head-ibox
-
-                self.word_space("=");
-                self.print_expr(expr);
-                self.s.word(";");
-                self.end(); // end the outer cbox
+            ast::ItemKind::Const(ref ty, ref body) => {
+                self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis);
             }
             ast::ItemKind::Fn(ref sig, ref gen, ref body) => {
                 self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
@@ -1464,30 +1455,8 @@ impl<'a> State<'a> {
     }
 
     crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
-        self.ann.pre(self, AnnNode::SubItem(item.id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(item.span.lo());
-        self.print_outer_attributes(&item.attrs);
-        self.print_defaultness(item.defaultness);
-        match &item.kind {
-            ast::AssocItemKind::Const(ty, expr) => {
-                self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis);
-            }
-            ast::AssocItemKind::Fn(sig, body) => {
-                let body = body.as_deref();
-                self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs);
-            }
-            ast::AssocItemKind::TyAlias(bounds, ty) => {
-                self.print_associated_type(item.ident, &item.generics, bounds, ty.as_deref());
-            }
-            ast::AssocItemKind::Macro(mac) => {
-                self.print_mac(mac);
-                if mac.args.need_semicolon() {
-                    self.s.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(item.id))
+        let ast::AssocItem { id, span, ident, attrs, defaultness, kind, vis, tokens: _ } = item;
+        self.print_nested_item_kind(*id, *span, *ident, attrs, *defaultness, kind, vis);
     }
 
     crate fn print_stmt(&mut self, st: &ast::Stmt) {
diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs
index c2bd2ac90e3..294b7463916 100644
--- a/src/librustc_builtin_macros/deriving/generic/mod.rs
+++ b/src/librustc_builtin_macros/deriving/generic/mod.rs
@@ -544,8 +544,8 @@ impl<'a> TraitDef<'a> {
                 vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited),
                 defaultness: ast::Defaultness::Final,
                 attrs: Vec::new(),
-                generics: Generics::default(),
                 kind: ast::AssocItemKind::TyAlias(
+                    Generics::default(),
                     Vec::new(),
                     Some(type_def.to_ty(cx, self.span, type_ident, generics)),
                 ),
@@ -973,12 +973,11 @@ impl<'a> MethodDef<'a> {
         P(ast::AssocItem {
             id: ast::DUMMY_NODE_ID,
             attrs: self.attributes.clone(),
-            generics: fn_generics,
             span: trait_.span,
             vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited),
             defaultness: ast::Defaultness::Final,
             ident: method_ident,
-            kind: ast::AssocItemKind::Fn(sig, Some(body_block)),
+            kind: ast::AssocItemKind::Fn(sig, fn_generics, Some(body_block)),
             tokens: None,
         })
     }
diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs
index 2e38a7880c6..e15405e1f0d 100644
--- a/src/librustc_builtin_macros/test.rs
+++ b/src/librustc_builtin_macros/test.rs
@@ -186,81 +186,85 @@ pub fn expand_test_or_bench(
         ast::ItemKind::Const(
             cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
             // test::TestDescAndFn {
-            cx.expr_struct(
-                sp,
-                test_path("TestDescAndFn"),
-                vec![
-                    // desc: test::TestDesc {
-                    field(
-                        "desc",
-                        cx.expr_struct(
-                            sp,
-                            test_path("TestDesc"),
-                            vec![
-                                // name: "path::to::test"
-                                field(
-                                    "name",
-                                    cx.expr_call(
-                                        sp,
-                                        cx.expr_path(test_path("StaticTestName")),
-                                        vec![cx.expr_str(
-                                            sp,
-                                            Symbol::intern(&item_path(
-                                                // skip the name of the root module
-                                                &cx.current_expansion.module.mod_path[1..],
-                                                &item.ident,
-                                            )),
-                                        )],
-                                    ),
-                                ),
-                                // ignore: true | false
-                                field("ignore", cx.expr_bool(sp, should_ignore(&item))),
-                                // allow_fail: true | false
-                                field("allow_fail", cx.expr_bool(sp, should_fail(&item))),
-                                // should_panic: ...
-                                field(
-                                    "should_panic",
-                                    match should_panic(cx, &item) {
-                                        // test::ShouldPanic::No
-                                        ShouldPanic::No => cx.expr_path(should_panic_path("No")),
-                                        // test::ShouldPanic::Yes
-                                        ShouldPanic::Yes(None) => {
-                                            cx.expr_path(should_panic_path("Yes"))
-                                        }
-                                        // test::ShouldPanic::YesWithMessage("...")
-                                        ShouldPanic::Yes(Some(sym)) => cx.expr_call(
+            Some(
+                cx.expr_struct(
+                    sp,
+                    test_path("TestDescAndFn"),
+                    vec![
+                        // desc: test::TestDesc {
+                        field(
+                            "desc",
+                            cx.expr_struct(
+                                sp,
+                                test_path("TestDesc"),
+                                vec![
+                                    // name: "path::to::test"
+                                    field(
+                                        "name",
+                                        cx.expr_call(
                                             sp,
-                                            cx.expr_path(should_panic_path("YesWithMessage")),
-                                            vec![cx.expr_str(sp, sym)],
+                                            cx.expr_path(test_path("StaticTestName")),
+                                            vec![cx.expr_str(
+                                                sp,
+                                                Symbol::intern(&item_path(
+                                                    // skip the name of the root module
+                                                    &cx.current_expansion.module.mod_path[1..],
+                                                    &item.ident,
+                                                )),
+                                            )],
                                         ),
-                                    },
-                                ),
-                                // test_type: ...
-                                field(
-                                    "test_type",
-                                    match test_type(cx) {
-                                        // test::TestType::UnitTest
-                                        TestType::UnitTest => {
-                                            cx.expr_path(test_type_path("UnitTest"))
-                                        }
-                                        // test::TestType::IntegrationTest
-                                        TestType::IntegrationTest => {
-                                            cx.expr_path(test_type_path("IntegrationTest"))
-                                        }
-                                        // test::TestPath::Unknown
-                                        TestType::Unknown => {
-                                            cx.expr_path(test_type_path("Unknown"))
-                                        }
-                                    },
-                                ),
-                                // },
-                            ],
+                                    ),
+                                    // ignore: true | false
+                                    field("ignore", cx.expr_bool(sp, should_ignore(&item))),
+                                    // allow_fail: true | false
+                                    field("allow_fail", cx.expr_bool(sp, should_fail(&item))),
+                                    // should_panic: ...
+                                    field(
+                                        "should_panic",
+                                        match should_panic(cx, &item) {
+                                            // test::ShouldPanic::No
+                                            ShouldPanic::No => {
+                                                cx.expr_path(should_panic_path("No"))
+                                            }
+                                            // test::ShouldPanic::Yes
+                                            ShouldPanic::Yes(None) => {
+                                                cx.expr_path(should_panic_path("Yes"))
+                                            }
+                                            // test::ShouldPanic::YesWithMessage("...")
+                                            ShouldPanic::Yes(Some(sym)) => cx.expr_call(
+                                                sp,
+                                                cx.expr_path(should_panic_path("YesWithMessage")),
+                                                vec![cx.expr_str(sp, sym)],
+                                            ),
+                                        },
+                                    ),
+                                    // test_type: ...
+                                    field(
+                                        "test_type",
+                                        match test_type(cx) {
+                                            // test::TestType::UnitTest
+                                            TestType::UnitTest => {
+                                                cx.expr_path(test_type_path("UnitTest"))
+                                            }
+                                            // test::TestType::IntegrationTest
+                                            TestType::IntegrationTest => {
+                                                cx.expr_path(test_type_path("IntegrationTest"))
+                                            }
+                                            // test::TestPath::Unknown
+                                            TestType::Unknown => {
+                                                cx.expr_path(test_type_path("Unknown"))
+                                            }
+                                        },
+                                    ),
+                                    // },
+                                ],
+                            ),
                         ),
-                    ),
-                    // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...)
-                    field("testfn", test_fn), // }
-                ],
-            ), // }
+                        // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...)
+                        field("testfn", test_fn), // }
+                    ],
+                ), // }
+            ),
         ),
     );
     test_const = test_const.map(|mut tc| {
diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs
index 9030001542d..8a53e1d1861 100644
--- a/src/librustc_expand/build.rs
+++ b/src/librustc_expand/build.rs
@@ -634,7 +634,7 @@ impl<'a> ExtCtxt<'a> {
         mutbl: ast::Mutability,
         expr: P<ast::Expr>,
     ) -> P<ast::Item> {
-        self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, expr))
+        self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr)))
     }
 
     pub fn item_const(
@@ -644,7 +644,7 @@ impl<'a> ExtCtxt<'a> {
         ty: P<ast::Ty>,
         expr: P<ast::Expr>,
     ) -> P<ast::Item> {
-        self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, expr))
+        self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, Some(expr)))
     }
 
     pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute {
diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs
index 5bf7602ea6e..6599e92222c 100644
--- a/src/librustc_expand/mbe/macro_parser.rs
+++ b/src/librustc_expand/mbe/macro_parser.rs
@@ -856,8 +856,6 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal {
     if name == sym::tt {
         return token::NtTT(p.parse_token_tree());
     }
-    // check at the beginning and the parser checks after each bump
-    p.process_potential_macro_variable();
     match parse_nt_inner(p, sp, name) {
         Ok(nt) => nt,
         Err(mut err) => {
diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs
index f3c827b1816..52e581e30f5 100644
--- a/src/librustc_expand/mbe/macro_rules.rs
+++ b/src/librustc_expand/mbe/macro_rules.rs
@@ -267,7 +267,6 @@ fn generic_extension<'cx>(
                     cx.current_expansion.module.mod_path.last().map(|id| id.to_string());
                 p.last_type_ascription = cx.current_expansion.prior_type_ascription;
 
-                p.process_potential_macro_variable();
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
                 return Box::new(ParserAnyMacro {
diff --git a/src/librustc_expand/placeholders.rs b/src/librustc_expand/placeholders.rs
index 6bcb8f45f00..c96b394c7b5 100644
--- a/src/librustc_expand/placeholders.rs
+++ b/src/librustc_expand/placeholders.rs
@@ -25,7 +25,6 @@ pub fn placeholder(
 
     let ident = ast::Ident::invalid();
     let attrs = Vec::new();
-    let generics = ast::Generics::default();
     let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited));
     let span = DUMMY_SP;
     let expr_placeholder = || {
@@ -57,7 +56,6 @@ pub fn placeholder(
             ident,
             vis,
             attrs,
-            generics,
             kind: ast::AssocItemKind::Macro(mac_placeholder()),
             defaultness: ast::Defaultness::Final,
             tokens: None,
@@ -68,7 +66,6 @@ pub fn placeholder(
             ident,
             vis,
             attrs,
-            generics,
             kind: ast::AssocItemKind::Macro(mac_placeholder()),
             defaultness: ast::Defaultness::Final,
             tokens: None,
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 72abfa15a1f..99e9878bfd8 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -686,7 +686,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
     fn flat_map_trait_item(&mut self, i: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
         let is_const = match i.kind {
             ast::AssocItemKind::Const(..) => true,
-            ast::AssocItemKind::Fn(ref sig, _) => Self::is_sig_const(sig),
+            ast::AssocItemKind::Fn(ref sig, _, _) => Self::is_sig_const(sig),
             _ => false,
         };
         self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 6039fef33e6..73c5f386e65 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -640,7 +640,7 @@ declare_lint_pass!(
 impl EarlyLintPass for AnonymousParameters {
     fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
         match it.kind {
-            ast::AssocItemKind::Fn(ref sig, _) => {
+            ast::AssocItemKind::Fn(ref sig, _, _) => {
                 for arg in sig.decl.inputs.iter() {
                     match arg.pat.kind {
                         ast::PatKind::Ident(_, ident, None) => {
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 480df99a01e..7870b9da4cb 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -603,7 +603,7 @@ impl EarlyLintPass for UnusedParens {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
         use ast::ItemKind::*;
 
-        if let Const(.., ref expr) | Static(.., ref expr) = item.kind {
+        if let Const(.., Some(expr)) | Static(.., Some(expr)) = &item.kind {
             self.check_unused_parens_expr(cx, expr, "assigned value", false, None, None);
         }
     }
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index e509e8267cc..215496e4d03 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -94,32 +94,23 @@ pub trait Qualif {
             }
 
             Operand::Constant(ref constant) => {
-                if constant.check_static_ptr(cx.tcx).is_some() {
-                    // `mir_const_qualif` does return the qualifs in the final value of a `static`,
-                    // so we could use value-based qualification here, but we shouldn't do this
-                    // without a good reason.
-                    //
-                    // Note: this uses `constant.literal.ty` which is a reference or pointer to the
-                    // type of the actual `static` item.
-                    Self::in_any_value_of_ty(cx, constant.literal.ty)
-                } else if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val
-                {
+                // Check the qualifs of the value of `const` items.
+                if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val {
                     assert!(promoted.is_none());
                     // Don't peek inside trait associated constants.
-                    if cx.tcx.trait_of_item(def_id).is_some() {
-                        Self::in_any_value_of_ty(cx, constant.literal.ty)
-                    } else {
+                    if cx.tcx.trait_of_item(def_id).is_none() {
                         let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def_id);
-                        let qualif = Self::in_qualifs(&qualifs);
+                        if !Self::in_qualifs(&qualifs) {
+                            return false;
+                        }
 
                         // Just in case the type is more specific than
                         // the definition, e.g., impl associated const
                         // with type parameters, take it into account.
-                        qualif && Self::in_any_value_of_ty(cx, constant.literal.ty)
                     }
-                } else {
-                    false
                 }
+                // Otherwise use the qualifs of the type.
+                Self::in_any_value_of_ty(cx, constant.literal.ty)
             }
         }
     }
diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs
index 4aad2c0f68a..a0b8415b3e1 100644
--- a/src/librustc_parse/lib.rs
+++ b/src/librustc_parse/lib.rs
@@ -9,7 +9,7 @@ use rustc_errors::{Diagnostic, FatalError, Level, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::{FileName, SourceFile, Span};
 use syntax::ast;
-use syntax::token::{self, Nonterminal};
+use syntax::token::{self, Nonterminal, Token};
 use syntax::tokenstream::{self, TokenStream, TokenTree};
 
 use std::path::{Path, PathBuf};
@@ -170,8 +170,9 @@ fn maybe_source_file_to_parser(
     let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?;
     let mut parser = stream_to_parser(sess, stream, None);
     parser.unclosed_delims = unclosed_delims;
-    if parser.token == token::Eof && parser.token.span.is_dummy() {
-        parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt());
+    if parser.token == token::Eof {
+        let span = Span::new(end_pos, end_pos, parser.token.span.ctxt());
+        parser.set_token(Token::new(token::Eof, span));
     }
 
     Ok(parser)
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 51822ab2ea5..97daa91eed1 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -166,7 +166,7 @@ impl<'a> Parser<'a> {
         while let Some(op) = self.check_assoc_op() {
             // Adjust the span for interpolated LHS to point to the `$lhs` token
             // and not to what it refers to.
-            let lhs_span = match self.unnormalized_prev_token().kind {
+            let lhs_span = match self.unnormalized_prev_token.kind {
                 TokenKind::Interpolated(..) => self.prev_span,
                 _ => lhs.span,
             };
@@ -527,7 +527,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, (Span, P<Expr>)> {
         expr.map(|e| {
             (
-                match self.unnormalized_prev_token().kind {
+                match self.unnormalized_prev_token.kind {
                     TokenKind::Interpolated(..) => self.prev_span,
                     _ => e.span,
                 },
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index d7b8d9778f0..4dcde2f92db 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -13,7 +13,7 @@ use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind
 use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, Unsafe};
 use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind};
 use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
-use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind};
+use syntax::ast::{FnHeader, ForeignItem, Mutability, Visibility, VisibilityKind};
 use syntax::ptr::P;
 use syntax::token;
 use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
@@ -333,29 +333,19 @@ impl<'a> Parser<'a> {
         self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn])
     }
 
-    fn missing_assoc_item_kind_err(
-        &self,
-        item_type: &str,
-        prev_span: Span,
-    ) -> DiagnosticBuilder<'a> {
-        let expected_kinds = if item_type == "extern" {
-            "missing `fn`, `type`, or `static`"
-        } else {
-            "missing `fn`, `type`, or `const`"
-        };
-
-        // Given this code `path(`, it seems like this is not
-        // setting the visibility of a macro invocation, but rather
-        // a mistyped method declaration.
-        // Create a diagnostic pointing out that `fn` is missing.
-        //
-        // x |     pub path(&self) {
-        //   |        ^ missing `fn`, `type`, or `const`
-        //     pub  path(
-        //        ^^ `sp` below will point to this
+    /// Given this code `path(`, it seems like this is not
+    /// setting the visibility of a macro invocation,
+    /// but rather a mistyped method declaration.
+    /// Create a diagnostic pointing out that `fn` is missing.
+    ///
+    /// ```
+    /// x |     pub   path(&self) {
+    ///   |         ^ missing `fn`, `type`, `const`, or `static`
+    /// ```
+    fn missing_nested_item_kind_err(&self, prev_span: Span) -> DiagnosticBuilder<'a> {
         let sp = prev_span.between(self.token.span);
-        let mut err = self
-            .struct_span_err(sp, &format!("{} for {}-item declaration", expected_kinds, item_type));
+        let expected_kinds = "missing `fn`, `type`, `const`, or `static`";
+        let mut err = self.struct_span_err(sp, &format!("{} for item declaration", expected_kinds));
         err.span_label(sp, expected_kinds);
         err
     }
@@ -546,6 +536,7 @@ impl<'a> Parser<'a> {
                 1,
                 &[
                     kw::Impl,
+                    kw::Static,
                     kw::Const,
                     kw::Async,
                     kw::Fn,
@@ -638,7 +629,7 @@ impl<'a> Parser<'a> {
     fn parse_assoc_item(
         &mut self,
         at_end: &mut bool,
-        req_name: fn(&token::Token) -> bool,
+        req_name: ReqName,
     ) -> PResult<'a, P<AssocItem>> {
         let attrs = self.parse_outer_attributes()?;
         let mut unclosed_delims = vec![];
@@ -652,59 +643,67 @@ impl<'a> Parser<'a> {
         if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) {
             item.tokens = Some(tokens);
         }
+        self.error_on_assoc_static(&item);
         Ok(P(item))
     }
 
+    fn error_on_assoc_static(&self, item: &AssocItem) {
+        if let AssocItemKind::Static(..) = item.kind {
+            self.struct_span_err(item.span, "associated `static` items are not allowed").emit();
+        }
+    }
+
     fn parse_assoc_item_(
         &mut self,
         at_end: &mut bool,
         mut attrs: Vec<Attribute>,
-        req_name: fn(&token::Token) -> bool,
+        req_name: ReqName,
     ) -> PResult<'a, AssocItem> {
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
         let defaultness = self.parse_defaultness();
+        let (ident, kind) = self.parse_assoc_item_kind(at_end, &mut attrs, req_name, &vis)?;
+        let span = lo.to(self.prev_span);
+        let id = DUMMY_NODE_ID;
+        Ok(AssocItem { id, span, ident, attrs, vis, defaultness, kind, tokens: None })
+    }
 
-        let (ident, kind, generics) = if self.eat_keyword(kw::Type) {
-            self.parse_assoc_ty()?
+    fn parse_assoc_item_kind(
+        &mut self,
+        at_end: &mut bool,
+        attrs: &mut Vec<Attribute>,
+        req_name: ReqName,
+        vis: &Visibility,
+    ) -> PResult<'a, (Ident, AssocItemKind)> {
+        if self.eat_keyword(kw::Type) {
+            self.parse_assoc_ty()
         } else if self.check_fn_front_matter() {
-            let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?;
-            (ident, AssocItemKind::Fn(sig, body), generics)
-        } else if self.check_keyword(kw::Const) {
-            self.parse_assoc_const()?
+            let (ident, sig, generics, body) = self.parse_fn(at_end, attrs, req_name)?;
+            Ok((ident, AssocItemKind::Fn(sig, generics, body)))
+        } else if self.is_static_global() {
+            self.bump(); // `static`
+            let mutbl = self.parse_mutability();
+            let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?;
+            Ok((ident, AssocItemKind::Static(ty, mutbl, expr)))
+        } else if self.eat_keyword(kw::Const) {
+            let (ident, ty, expr) = self.parse_item_const_common(None)?;
+            Ok((ident, AssocItemKind::Const(ty, expr)))
         } else if self.isnt_macro_invocation() {
-            return Err(self.missing_assoc_item_kind_err("associated", self.prev_span));
+            Err(self.missing_nested_item_kind_err(self.prev_span))
         } else if self.token.is_path_start() {
             let mac = self.parse_item_macro(&vis)?;
             *at_end = true;
-            (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default())
+            Ok((Ident::invalid(), AssocItemKind::Macro(mac)))
         } else {
-            self.recover_attrs_no_item(&attrs)?;
-            self.unexpected()?
-        };
-
-        let span = lo.to(self.prev_span);
-        let id = DUMMY_NODE_ID;
-        Ok(AssocItem { id, span, ident, attrs, vis, defaultness, generics, kind, tokens: None })
-    }
-
-    /// This parses the grammar:
-    ///
-    ///     AssocConst = "const" Ident ":" Ty "=" Expr ";"
-    fn parse_assoc_const(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
-        self.expect_keyword(kw::Const)?;
-        let ident = self.parse_ident()?;
-        self.expect(&token::Colon)?;
-        let ty = self.parse_ty()?;
-        let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
-        self.expect_semi()?;
-        Ok((ident, AssocItemKind::Const(ty, expr), Generics::default()))
+            self.recover_attrs_no_item(attrs)?;
+            self.unexpected()
+        }
     }
 
     /// Parses the following grammar:
     ///
     ///     AssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty]
-    fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
+    fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind)> {
         let ident = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
 
@@ -716,7 +715,7 @@ impl<'a> Parser<'a> {
         let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
         self.expect_semi()?;
 
-        Ok((ident, AssocItemKind::TyAlias(bounds, default), generics))
+        Ok((ident, AssocItemKind::TyAlias(generics, bounds, default)))
     }
 
     /// Parses a `UseTree`.
@@ -875,60 +874,26 @@ impl<'a> Parser<'a> {
         let mut attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
+        let (ident, kind) = self.parse_assoc_item_kind(at_end, &mut attrs, |_| true, &vis)?;
+        let item = self.mk_item(lo, ident, kind, vis, attrs);
+        self.error_on_foreign_const(&item);
+        Ok(P(item))
+    }
 
-        let (ident, kind) = if self.check_keyword(kw::Type) {
-            // FOREIGN TYPE ITEM
-            self.parse_item_foreign_type()?
-        } else if self.check_fn_front_matter() {
-            // FOREIGN FUNCTION ITEM
-            let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, |_| true)?;
-            (ident, ForeignItemKind::Fn(sig, generics, body))
-        } else if self.is_static_global() {
-            // FOREIGN STATIC ITEM
-            self.bump(); // `static`
-            self.parse_item_foreign_static()?
-        } else if self.token.is_keyword(kw::Const) {
-            // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
-            self.bump(); // `const`
-            self.struct_span_err(self.prev_span, "extern items cannot be `const`")
+    fn error_on_foreign_const(&self, item: &ForeignItem) {
+        if let AssocItemKind::Const(..) = item.kind {
+            self.struct_span_err(item.ident.span, "extern items cannot be `const`")
                 .span_suggestion(
-                    self.prev_span,
+                    item.span.with_hi(item.ident.span.lo()),
                     "try using a static value",
-                    "static".to_owned(),
+                    "static ".to_string(),
                     Applicability::MachineApplicable,
                 )
+                .note(
+                    "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html",
+                )
                 .emit();
-            self.parse_item_foreign_static()?
-        } else if self.isnt_macro_invocation() {
-            return Err(self.missing_assoc_item_kind_err("extern", self.prev_span));
-        } else if self.token.is_path_start() {
-            let mac = self.parse_item_macro(&vis)?;
-            *at_end = true;
-            (Ident::invalid(), ForeignItemKind::Macro(mac))
-        } else {
-            self.recover_attrs_no_item(&attrs)?;
-            self.unexpected()?
-        };
-        Ok(P(self.mk_item(lo, ident, kind, vis, attrs)))
-    }
-
-    /// Parses a static item from a foreign module.
-    /// Assumes that the `static` keyword is already parsed.
-    fn parse_item_foreign_static(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
-        let mutbl = self.parse_mutability();
-        let ident = self.parse_ident()?;
-        self.expect(&token::Colon)?;
-        let ty = self.parse_ty()?;
-        self.expect_semi()?;
-        Ok((ident, ForeignItemKind::Static(ty, mutbl)))
-    }
-
-    /// Parses a type from a foreign module.
-    fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
-        self.expect_keyword(kw::Type)?;
-        let ident = self.parse_ident()?;
-        self.expect_semi()?;
-        Ok((ident, ForeignItemKind::Ty))
+        }
     }
 
     fn is_static_global(&mut self) -> bool {
@@ -964,34 +929,43 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with
+    /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with
     /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
     ///
     /// When `m` is `"const"`, `$ident` may also be `"_"`.
     fn parse_item_const(&mut self, m: Option<Mutability>) -> PResult<'a, ItemInfo> {
+        let (id, ty, expr) = self.parse_item_const_common(m)?;
+        let item = match m {
+            Some(m) => ItemKind::Static(ty, m, expr),
+            None => ItemKind::Const(ty, expr),
+        };
+        Ok((id, item))
+    }
+
+    /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with
+    /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
+    ///
+    /// When `m` is `"const"`, `$ident` may also be `"_"`.
+    fn parse_item_const_common(
+        &mut self,
+        m: Option<Mutability>,
+    ) -> PResult<'a, (Ident, P<Ty>, Option<P<ast::Expr>>)> {
         let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?;
 
         // Parse the type of a `const` or `static mut?` item.
         // That is, the `":" $ty` fragment.
-        let ty = if self.token == token::Eq {
-            self.recover_missing_const_type(id, m)
-        } else {
-            // Not `=` so expect `":"" $ty` as usual.
-            self.expect(&token::Colon)?;
+        let ty = if self.eat(&token::Colon) {
             self.parse_ty()?
+        } else {
+            self.recover_missing_const_type(id, m)
         };
 
-        self.expect(&token::Eq)?;
-        let e = self.parse_expr()?;
+        let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
         self.expect_semi()?;
-        let item = match m {
-            Some(m) => ItemKind::Static(ty, m, e),
-            None => ItemKind::Const(ty, e),
-        };
-        Ok((id, item))
+        Ok((id, ty, expr))
     }
 
-    /// We were supposed to parse `:` but instead, we're already at `=`.
+    /// We were supposed to parse `:` but the `:` was missing.
     /// This means that the type is missing.
     fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
         // Construct the error and stash it away with the hope
@@ -1400,8 +1374,9 @@ impl<'a> Parser<'a> {
     }
 
     fn report_invalid_macro_expansion_item(&self, args: &MacArgs) {
+        let span = args.span().expect("undelimited macro call");
         let mut err = self.struct_span_err(
-            self.prev_span,
+            span,
             "macros that expand to items must be delimited with braces or followed by a semicolon",
         );
         if self.unclosed_delims.is_empty() {
@@ -1416,14 +1391,14 @@ impl<'a> Parser<'a> {
             );
         } else {
             err.span_suggestion(
-                self.prev_span,
+                span,
                 "change the delimiters to curly braces",
                 " { /* items */ }".to_string(),
                 Applicability::HasPlaceholders,
             );
         }
         err.span_suggestion(
-            self.prev_span.shrink_to_hi(),
+            span.shrink_to_hi(),
             "add a semicolon",
             ';'.to_string(),
             Applicability::MaybeIncorrect,
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index 79944dc35e5..937e5e3cd69 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -93,18 +93,16 @@ pub struct Parser<'a> {
     /// Use span from this token if you need an isolated span.
     pub token: Token,
     /// The current non-normalized token if it's different from `token`.
-    /// Preferable use is through the `unnormalized_token()` getter.
     /// Use span from this token if you need to concatenate it with some neighbouring spans.
-    unnormalized_token: Option<Token>,
+    unnormalized_token: Token,
     /// The previous normalized token.
     /// Use span from this token if you need an isolated span.
     prev_token: Token,
     /// The previous non-normalized token if it's different from `prev_token`.
-    /// Preferable use is through the `unnormalized_prev_token()` getter.
     /// Use span from this token if you need to concatenate it with some neighbouring spans.
-    unnormalized_prev_token: Option<Token>,
-    /// Equivalent to `unnormalized_prev_token().span`.
-    /// FIXME: Remove in favor of `(unnormalized_)prev_token().span`.
+    unnormalized_prev_token: Token,
+    /// Equivalent to `unnormalized_prev_token.span`.
+    /// FIXME: Remove in favor of `(unnormalized_)prev_token.span`.
     pub prev_span: Span,
     restrictions: Restrictions,
     /// Used to determine the path to externally loaded source files.
@@ -378,9 +376,9 @@ impl<'a> Parser<'a> {
         let mut parser = Parser {
             sess,
             token: Token::dummy(),
-            unnormalized_token: None,
+            unnormalized_token: Token::dummy(),
             prev_token: Token::dummy(),
-            unnormalized_prev_token: None,
+            unnormalized_prev_token: Token::dummy(),
             prev_span: DUMMY_SP,
             restrictions: Restrictions::empty(),
             recurse_into_file_modules,
@@ -404,7 +402,8 @@ impl<'a> Parser<'a> {
             subparser_name,
         };
 
-        parser.token = parser.next_tok();
+        // Make parser point to the first token.
+        parser.bump();
 
         if let Some(directory) = directory {
             parser.directory = directory;
@@ -418,19 +417,10 @@ impl<'a> Parser<'a> {
             }
         }
 
-        parser.process_potential_macro_variable();
         parser
     }
 
-    fn unnormalized_token(&self) -> &Token {
-        self.unnormalized_token.as_ref().unwrap_or(&self.token)
-    }
-
-    fn unnormalized_prev_token(&self) -> &Token {
-        self.unnormalized_prev_token.as_ref().unwrap_or(&self.prev_token)
-    }
-
-    fn next_tok(&mut self) -> Token {
+    fn next_tok(&mut self, fallback_span: Span) -> Token {
         let mut next = if self.desugar_doc_comments {
             self.token_cursor.next_desugared()
         } else {
@@ -438,7 +428,7 @@ impl<'a> Parser<'a> {
         };
         if next.span.is_dummy() {
             // Tweak the location for better diagnostics, but keep syntactic context intact.
-            next.span = self.unnormalized_token().span.with_ctxt(next.span.ctxt());
+            next.span = fallback_span.with_ctxt(next.span.ctxt());
         }
         next
     }
@@ -896,6 +886,23 @@ impl<'a> Parser<'a> {
         self.parse_delim_comma_seq(token::Paren, f)
     }
 
+    // Interpolated identifier (`$i: ident`) and lifetime (`$l: lifetime`)
+    // tokens are replaced with usual identifier and lifetime tokens,
+    // so the former are never encountered during normal parsing.
+    crate fn set_token(&mut self, token: Token) {
+        self.unnormalized_token = token;
+        self.token = match &self.unnormalized_token.kind {
+            token::Interpolated(nt) => match **nt {
+                token::NtIdent(ident, is_raw) => {
+                    Token::new(token::Ident(ident.name, is_raw), ident.span)
+                }
+                token::NtLifetime(ident) => Token::new(token::Lifetime(ident.name), ident.span),
+                _ => self.unnormalized_token.clone(),
+            },
+            _ => self.unnormalized_token.clone(),
+        }
+    }
+
     /// Advance the parser by one token.
     pub fn bump(&mut self) {
         if self.prev_token.kind == TokenKind::Eof {
@@ -905,16 +912,15 @@ impl<'a> Parser<'a> {
         }
 
         // Update the current and previous tokens.
-        let next_token = self.next_tok();
-        self.prev_token = mem::replace(&mut self.token, next_token);
+        self.prev_token = self.token.take();
         self.unnormalized_prev_token = self.unnormalized_token.take();
+        let next_token = self.next_tok(self.unnormalized_prev_token.span);
+        self.set_token(next_token);
 
         // Update fields derived from the previous token.
-        self.prev_span = self.unnormalized_prev_token().span;
+        self.prev_span = self.unnormalized_prev_token.span;
 
         self.expected_tokens.clear();
-        // Check after each token.
-        self.process_potential_macro_variable();
     }
 
     /// Advances the parser using provided token as a next one. Use this when
@@ -924,12 +930,12 @@ impl<'a> Parser<'a> {
     /// Correct token kinds and spans need to be calculated instead.
     fn bump_with(&mut self, next: TokenKind, span: Span) {
         // Update the current and previous tokens.
-        let next_token = Token::new(next, span);
-        self.prev_token = mem::replace(&mut self.token, next_token);
+        self.prev_token = self.token.take();
         self.unnormalized_prev_token = self.unnormalized_token.take();
+        self.set_token(Token::new(next, span));
 
         // Update fields derived from the previous token.
-        self.prev_span = self.unnormalized_prev_token().span.with_hi(span.lo());
+        self.prev_span = self.unnormalized_prev_token.span.with_hi(span.lo());
 
         self.expected_tokens.clear();
     }
@@ -1066,39 +1072,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub fn process_potential_macro_variable(&mut self) {
-        let normalized_token = match self.token.kind {
-            token::Dollar
-                if self.token.span.from_expansion() && self.look_ahead(1, |t| t.is_ident()) =>
-            {
-                self.bump();
-                let name = match self.token.kind {
-                    token::Ident(name, _) => name,
-                    _ => unreachable!(),
-                };
-                let span = self.prev_span.to(self.token.span);
-                self.struct_span_err(span, &format!("unknown macro variable `{}`", name))
-                    .span_label(span, "unknown macro variable")
-                    .emit();
-                self.bump();
-                return;
-            }
-            token::Interpolated(ref nt) => {
-                // Interpolated identifier and lifetime tokens are replaced with usual identifier
-                // and lifetime tokens, so the former are never encountered during normal parsing.
-                match **nt {
-                    token::NtIdent(ident, is_raw) => {
-                        Token::new(token::Ident(ident.name, is_raw), ident.span)
-                    }
-                    token::NtLifetime(ident) => Token::new(token::Lifetime(ident.name), ident.span),
-                    _ => return,
-                }
-            }
-            _ => return,
-        };
-        self.unnormalized_token = Some(mem::replace(&mut self.token, normalized_token));
-    }
-
     /// Parses a single token tree from the input.
     pub fn parse_token_tree(&mut self) -> TokenTree {
         match self.token.kind {
@@ -1107,15 +1080,14 @@ impl<'a> Parser<'a> {
                     &mut self.token_cursor.frame,
                     self.token_cursor.stack.pop().unwrap(),
                 );
-                self.token.span = frame.span.entire();
+                self.set_token(Token::new(TokenKind::CloseDelim(frame.delim), frame.span.close));
                 self.bump();
                 TokenTree::Delimited(frame.span, frame.delim, frame.tree_cursor.stream.into())
             }
             token::CloseDelim(_) | token::Eof => unreachable!(),
             _ => {
-                let token = self.token.clone();
                 self.bump();
-                TokenTree::Token(token)
+                TokenTree::Token(self.prev_token.clone())
             }
         }
     }
diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs
index ec6d4db6102..520d325f16b 100644
--- a/src/librustc_parse/parser/pat.rs
+++ b/src/librustc_parse/parser/pat.rs
@@ -503,17 +503,18 @@ impl<'a> Parser<'a> {
         // 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.kind {
-            PatKind::Ident(..) => {}
-            _ => self.ban_mut_general_pat(mut_span, &pat, changed_any_binding),
+        // If we don't have `mut $ident (@ pat)?`, error.
+        if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind {
+            // Don't recurse into the subpattern.
+            // `mut` on the outer binding doesn't affect the inner bindings.
+            *m = Mutability::Mut;
+        } else {
+            // Add `mut` to any binding in the parsed pattern.
+            let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat);
+            self.ban_mut_general_pat(mut_span, &pat, changed_any_binding);
         }
 
-        Ok(pat.kind)
+        Ok(pat.into_inner().kind)
     }
 
     /// Recover on `mut ref? ident @ pat` and suggest
@@ -542,14 +543,10 @@ impl<'a> Parser<'a> {
             }
 
             fn visit_pat(&mut self, pat: &mut P<Pat>) {
-                if let PatKind::Ident(ref mut bm, ..) = pat.kind {
-                    if let BindingMode::ByValue(ref mut m @ Mutability::Not) = bm {
-                        *m = Mutability::Mut;
-                    }
+                if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind
+                {
                     self.0 = true;
-                    // Don't recurse into the subpattern, mut on the outer
-                    // binding doesn't affect the inner bindings.
-                    return;
+                    *m = Mutability::Mut;
                 }
                 noop_visit_pat(pat, self);
             }
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index 761c06b70ee..18e57c6a5d4 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -134,7 +134,7 @@ impl<'a> Parser<'a> {
             path
         });
 
-        let lo = self.unnormalized_token().span;
+        let lo = self.unnormalized_token.span;
         let mut segments = Vec::new();
         let mod_sep_ctxt = self.token.span.ctxt();
         if self.eat(&token::ModSep) {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index d6ea737385c..1f622b80e8e 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -826,10 +826,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             ForeignItemKind::Fn(..) => {
                 (Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)), ValueNS)
             }
-            ForeignItemKind::Static(..) => {
+            ForeignItemKind::Static(..) | ForeignItemKind::Const(..) => {
                 (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS)
             }
-            ForeignItemKind::Ty => {
+            ForeignItemKind::TyAlias(..) => {
                 (Res::Def(DefKind::ForeignTy, self.r.definitions.local_def_id(item.id)), TypeNS)
             }
             ForeignItemKind::Macro(_) => unreachable!(),
@@ -1251,8 +1251,9 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         // Add the item to the trait info.
         let item_def_id = self.r.definitions.local_def_id(item.id);
         let (res, ns) = match item.kind {
-            AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
-            AssocItemKind::Fn(ref sig, _) => {
+            AssocItemKind::Static(..) // Let's pretend it's a `const` for recovery.
+            | AssocItemKind::Const(..) => (Res::Def(DefKind::AssocConst, item_def_id), ValueNS),
+            AssocItemKind::Fn(ref sig, _, _) => {
                 if sig.decl.has_self() {
                     self.r.has_self.insert(item_def_id);
                 }
diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs
index fe80dec513c..60cba555121 100644
--- a/src/librustc_resolve/def_collector.rs
+++ b/src/librustc_resolve/def_collector.rs
@@ -215,18 +215,22 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
 
     fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
         let def_data = match &i.kind {
-            AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.is_async() => {
+            AssocItemKind::Fn(FnSig { header, decl }, generics, body)
+                if header.asyncness.is_async() =>
+            {
                 return self.visit_async_fn(
                     i.id,
                     i.ident.name,
                     i.span,
                     header,
-                    &i.generics,
+                    generics,
                     decl,
                     body.as_deref(),
                 );
             }
-            AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name),
+            AssocItemKind::Fn(..) | AssocItemKind::Const(..) | AssocItemKind::Static(..) => {
+                DefPathData::ValueNs(i.ident.name)
+            }
             AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
             AssocItemKind::Macro(..) => return self.visit_macro_invoc(i.id),
         };
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 997b1a4da8c..73601cd2ee7 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -437,17 +437,18 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
     }
     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
         match foreign_item.kind {
-            ForeignItemKind::Fn(_, ref generics, _) => {
+            ForeignItemKind::Fn(_, ref generics, _)
+            | ForeignItemKind::TyAlias(ref generics, ..) => {
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
             }
-            ForeignItemKind::Static(..) => {
+            ForeignItemKind::Const(..) | ForeignItemKind::Static(..) => {
                 self.with_item_rib(HasGenericParams::No, |this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
             }
-            ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {
+            ForeignItemKind::Macro(..) => {
                 visit::walk_foreign_item(self, foreign_item);
             }
         }
@@ -826,41 +827,34 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         this.visit_generics(generics);
                         walk_list!(this, visit_param_bound, bounds);
 
-                        for trait_item in trait_items {
+                        let walk_assoc_item = |this: &mut Self, generics, item| {
+                            this.with_generic_param_rib(generics, AssocItemRibKind, |this| {
+                                visit::walk_assoc_item(this, item, AssocCtxt::Trait)
+                            });
+                        };
+
+                        for item in trait_items {
                             this.with_trait_items(trait_items, |this| {
-                                this.with_generic_param_rib(
-                                    &trait_item.generics,
-                                    AssocItemRibKind,
-                                    |this| {
-                                        match trait_item.kind {
-                                            AssocItemKind::Const(ref ty, ref default) => {
-                                                this.visit_ty(ty);
-
-                                                // Only impose the restrictions of
-                                                // ConstRibKind for an actual constant
-                                                // expression in a provided default.
-                                                if let Some(ref expr) = *default {
-                                                    this.with_constant_rib(|this| {
-                                                        this.visit_expr(expr);
-                                                    });
-                                                }
-                                            }
-                                            AssocItemKind::Fn(_, _) => visit::walk_assoc_item(
-                                                this,
-                                                trait_item,
-                                                AssocCtxt::Trait,
-                                            ),
-                                            AssocItemKind::TyAlias(..) => visit::walk_assoc_item(
-                                                this,
-                                                trait_item,
-                                                AssocCtxt::Trait,
-                                            ),
-                                            AssocItemKind::Macro(_) => {
-                                                panic!("unexpanded macro in resolve!")
-                                            }
-                                        };
-                                    },
-                                );
+                                match &item.kind {
+                                    AssocItemKind::Static(ty, _, default)
+                                    | AssocItemKind::Const(ty, default) => {
+                                        this.visit_ty(ty);
+                                        // Only impose the restrictions of `ConstRibKind` for an
+                                        // actual constant expression in a provided default.
+                                        if let Some(expr) = default {
+                                            this.with_constant_rib(|this| this.visit_expr(expr));
+                                        }
+                                    }
+                                    AssocItemKind::Fn(_, generics, _) => {
+                                        walk_assoc_item(this, generics, item);
+                                    }
+                                    AssocItemKind::TyAlias(generics, _, _) => {
+                                        walk_assoc_item(this, generics, item);
+                                    }
+                                    AssocItemKind::Macro(_) => {
+                                        panic!("unexpanded macro in resolve!")
+                                    }
+                                };
                             });
                         }
                     });
@@ -888,9 +882,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 debug!("resolve_item ItemKind::Const");
                 self.with_item_rib(HasGenericParams::No, |this| {
                     this.visit_ty(ty);
-                    this.with_constant_rib(|this| {
-                        this.visit_expr(expr);
-                    });
+                    if let Some(expr) = expr {
+                        this.with_constant_rib(|this| this.visit_expr(expr));
+                    }
                 });
             }
 
@@ -1021,7 +1015,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             trait_items
                 .iter()
                 .filter_map(|item| match &item.kind {
-                    AssocItemKind::TyAlias(bounds, _) if bounds.len() == 0 => Some(item.ident),
+                    AssocItemKind::TyAlias(_, bounds, _) if bounds.len() == 0 => Some(item.ident),
                     _ => None,
                 })
                 .collect(),
@@ -1113,66 +1107,74 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         this.with_current_self_type(self_type, |this| {
                             this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
                                 debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
-                                for impl_item in impl_items {
-                                    // We also need a new scope for the impl item type parameters.
-                                    this.with_generic_param_rib(&impl_item.generics,
-                                                                AssocItemRibKind,
-                                                                |this| {
-                                        use crate::ResolutionError::*;
-                                        match impl_item.kind {
-                                            AssocItemKind::Const(..) => {
-                                                debug!(
-                                                    "resolve_implementation AssocItemKind::Const",
-                                                );
-                                                // If this is a trait impl, ensure the const
-                                                // exists in trait
-                                                this.check_trait_item(
-                                                    impl_item.ident,
-                                                    ValueNS,
-                                                    impl_item.span,
-                                                    |n, s| ConstNotMemberOfTrait(n, s),
-                                                );
-
-                                                this.with_constant_rib(|this| {
+                                for item in impl_items {
+                                    use crate::ResolutionError::*;
+                                    match &item.kind {
+                                        AssocItemKind::Static(..) | AssocItemKind::Const(..) => {
+                                            debug!("resolve_implementation AssocItemKind::Const",);
+                                            // If this is a trait impl, ensure the const
+                                            // exists in trait
+                                            this.check_trait_item(
+                                                item.ident,
+                                                ValueNS,
+                                                item.span,
+                                                |n, s| ConstNotMemberOfTrait(n, s),
+                                            );
+
+                                            this.with_constant_rib(|this| {
+                                                visit::walk_assoc_item(this, item, AssocCtxt::Impl)
+                                            });
+                                        }
+                                        AssocItemKind::Fn(_, generics, _) => {
+                                            // We also need a new scope for the impl item type parameters.
+                                            this.with_generic_param_rib(
+                                                generics,
+                                                AssocItemRibKind,
+                                                |this| {
+                                                    // If this is a trait impl, ensure the method
+                                                    // exists in trait
+                                                    this.check_trait_item(
+                                                        item.ident,
+                                                        ValueNS,
+                                                        item.span,
+                                                        |n, s| MethodNotMemberOfTrait(n, s),
+                                                    );
+
+                                                    visit::walk_assoc_item(
+                                                        this,
+                                                        item,
+                                                        AssocCtxt::Impl,
+                                                    )
+                                                },
+                                            );
+                                        }
+                                        AssocItemKind::TyAlias(generics, _, _) => {
+                                            // We also need a new scope for the impl item type parameters.
+                                            this.with_generic_param_rib(
+                                                generics,
+                                                AssocItemRibKind,
+                                                |this| {
+                                                    // If this is a trait impl, ensure the type
+                                                    // exists in trait
+                                                    this.check_trait_item(
+                                                        item.ident,
+                                                        TypeNS,
+                                                        item.span,
+                                                        |n, s| TypeNotMemberOfTrait(n, s),
+                                                    );
+
                                                     visit::walk_assoc_item(
                                                         this,
-                                                        impl_item,
+                                                        item,
                                                         AssocCtxt::Impl,
                                                     )
-                                                });
-                                            }
-                                            AssocItemKind::Fn(..) => {
-                                                // If this is a trait impl, ensure the method
-                                                // exists in trait
-                                                this.check_trait_item(impl_item.ident,
-                                                                      ValueNS,
-                                                                      impl_item.span,
-                                                    |n, s| MethodNotMemberOfTrait(n, s));
-
-                                                visit::walk_assoc_item(
-                                                    this,
-                                                    impl_item,
-                                                    AssocCtxt::Impl,
-                                                )
-                                            }
-                                            AssocItemKind::TyAlias(_, _) => {
-                                                // If this is a trait impl, ensure the type
-                                                // exists in trait
-                                                this.check_trait_item(impl_item.ident,
-                                                                      TypeNS,
-                                                                      impl_item.span,
-                                                    |n, s| TypeNotMemberOfTrait(n, s));
-
-                                                visit::walk_assoc_item(
-                                                    this,
-                                                    impl_item,
-                                                    AssocCtxt::Impl,
-                                                )
-                                            }
-                                            AssocItemKind::Macro(_) =>
-                                                panic!("unexpanded macro in resolve!"),
+                                                },
+                                            );
+                                        }
+                                        AssocItemKind::Macro(_) => {
+                                            panic!("unexpanded macro in resolve!")
                                         }
-                                    });
+                                    }
                                 }
                             });
                         });
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index a445b0ea1b8..db7733e7241 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -400,7 +400,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         &mut self,
         item: &'l ast::Item,
         typ: &'l ast::Ty,
-        expr: &'l ast::Expr,
+        expr: Option<&'l ast::Expr>,
     ) {
         let hir_id = self.tcx.hir().node_to_hir_id(item.id);
         self.nest_tables(item.id, |v| {
@@ -409,7 +409,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 v.dumper.dump_def(&access_from!(v.save_ctxt, item, hir_id), var_data);
             }
             v.visit_ty(&typ);
-            v.visit_expr(expr);
+            walk_list!(v, visit_expr, expr);
         });
     }
 
@@ -1004,7 +1004,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         self.process_macro_use(trait_item.span);
         let vis_span = trait_item.span.shrink_to_lo();
         match trait_item.kind {
-            ast::AssocItemKind::Const(ref ty, ref expr) => {
+            ast::AssocItemKind::Static(ref ty, _, ref expr)
+            | ast::AssocItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(
                     trait_item.id,
                     trait_item.ident,
@@ -1015,18 +1016,18 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     &trait_item.attrs,
                 );
             }
-            ast::AssocItemKind::Fn(ref sig, ref body) => {
+            ast::AssocItemKind::Fn(ref sig, ref generics, ref body) => {
                 self.process_method(
                     sig,
                     body.as_ref().map(|x| &**x),
                     trait_item.id,
                     trait_item.ident,
-                    &trait_item.generics,
+                    generics,
                     respan(vis_span, ast::VisibilityKind::Public),
                     trait_item.span,
                 );
             }
-            ast::AssocItemKind::TyAlias(ref bounds, ref default_ty) => {
+            ast::AssocItemKind::TyAlias(_, ref bounds, ref default_ty) => {
                 // FIXME do something with _bounds (for type refs)
                 let name = trait_item.ident.name.to_string();
                 let qualname = format!(
@@ -1074,7 +1075,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
     fn process_impl_item(&mut self, impl_item: &'l ast::AssocItem, impl_id: DefId) {
         self.process_macro_use(impl_item.span);
         match impl_item.kind {
-            ast::AssocItemKind::Const(ref ty, ref expr) => {
+            ast::AssocItemKind::Static(ref ty, _, ref expr)
+            | ast::AssocItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(
                     impl_item.id,
                     impl_item.ident,
@@ -1085,19 +1087,19 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     &impl_item.attrs,
                 );
             }
-            ast::AssocItemKind::Fn(ref sig, ref body) => {
+            ast::AssocItemKind::Fn(ref sig, ref generics, ref body) => {
                 self.process_method(
                     sig,
                     body.as_deref(),
                     impl_item.id,
                     impl_item.ident,
-                    &impl_item.generics,
+                    generics,
                     impl_item.vis.clone(),
                     impl_item.span,
                 );
             }
-            ast::AssocItemKind::TyAlias(_, None) => {}
-            ast::AssocItemKind::TyAlias(_, Some(ref ty)) => {
+            ast::AssocItemKind::TyAlias(_, _, None) => {}
+            ast::AssocItemKind::TyAlias(_, _, Some(ref ty)) => {
                 // FIXME: uses of the assoc type should ideally point to this
                 // 'def' and the name here should be a ref to the def in the
                 // trait.
@@ -1293,8 +1295,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
             Fn(ref sig, ref ty_params, ref body) => {
                 self.process_fn(item, &sig.decl, &sig.header, ty_params, body.as_deref())
             }
-            Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr),
-            Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr),
+            Static(ref typ, _, ref e) => self.process_static_or_const_item(item, typ, e.as_deref()),
+            Const(ref typ, ref e) => self.process_static_or_const_item(item, typ, e.as_deref()),
             Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => {
                 self.process_struct(item, def, ty_params)
             }
@@ -1532,7 +1534,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                     self.visit_ty(&ret_ty);
                 }
             }
-            ast::ForeignItemKind::Static(ref ty, _) => {
+            ast::ForeignItemKind::Const(ref ty, _) | ast::ForeignItemKind::Static(ref ty, _, _) => {
                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(var_data, DefData, item.span);
                     self.dumper.dump_def(&access, var_data);
@@ -1540,7 +1542,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
 
                 self.visit_ty(ty);
             }
-            ast::ForeignItemKind::Ty => {
+            ast::ForeignItemKind::TyAlias(..) => {
                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(var_data, DefData, item.span);
                     self.dumper.dump_def(&access, var_data);
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index eea7376590e..6a34e47130f 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -151,7 +151,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
-            ast::ForeignItemKind::Static(ref ty, _) => {
+            ast::ForeignItemKind::Const(ref ty, _) | ast::ForeignItemKind::Static(ref ty, _, _) => {
                 filter!(self.span_utils, item.ident.span);
 
                 let id = id_from_node_id(item.id, self);
@@ -173,7 +173,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                 }))
             }
             // FIXME(plietar): needs a new DefKind in rls-data
-            ast::ForeignItemKind::Ty => None,
+            ast::ForeignItemKind::TyAlias(..) => None,
             ast::ForeignItemKind::Macro(..) => None,
         }
     }
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 4f5c388f2a9..a2c61db4b7c 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -334,10 +334,13 @@ impl Sig for ast::Item {
 
                 let ty = ty.make(offset + text.len(), id, scx)?;
                 text.push_str(&ty.text);
-                text.push_str(" = ");
 
-                let expr = pprust::expr_to_string(expr).replace('\n', " ");
-                text.push_str(&expr);
+                if let Some(expr) = expr {
+                    text.push_str(" = ");
+                    let expr = pprust::expr_to_string(expr).replace('\n', " ");
+                    text.push_str(&expr);
+                }
+
                 text.push(';');
 
                 Ok(extend_sig(ty, text, defs, vec![]))
@@ -355,10 +358,13 @@ impl Sig for ast::Item {
 
                 let ty = ty.make(offset + text.len(), id, scx)?;
                 text.push_str(&ty.text);
-                text.push_str(" = ");
 
-                let expr = pprust::expr_to_string(expr).replace('\n', " ");
-                text.push_str(&expr);
+                if let Some(expr) = expr {
+                    text.push_str(" = ");
+                    let expr = pprust::expr_to_string(expr).replace('\n', " ");
+                    text.push_str(&expr);
+                }
+
                 text.push(';');
 
                 Ok(extend_sig(ty, text, defs, vec![]))
@@ -754,7 +760,7 @@ impl Sig for ast::ForeignItem {
 
                 Ok(sig)
             }
-            ast::ForeignItemKind::Static(ref ty, m) => {
+            ast::ForeignItemKind::Static(ref ty, m, _) => {
                 let mut text = "static ".to_owned();
                 if m == ast::Mutability::Mut {
                     text.push_str("mut ");
@@ -773,7 +779,7 @@ impl Sig for ast::ForeignItem {
 
                 Ok(extend_sig(ty_sig, text, defs, vec![]))
             }
-            ast::ForeignItemKind::Ty => {
+            ast::ForeignItemKind::TyAlias(..) => {
                 let mut text = "type ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
@@ -786,6 +792,7 @@ impl Sig for ast::ForeignItem {
 
                 Ok(Signature { text: text, defs: defs, refs: vec![] })
             }
+            ast::ForeignItemKind::Const(..) => Err("foreign const"),
             ast::ForeignItemKind::Macro(..) => Err("macro"),
         }
     }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 86b00c2f0d3..bb31e979b73 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -5,7 +5,7 @@ use super::{FnCtxt, Needs};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint};
 use rustc::ty::{self, Ty, TypeFoldable};
-use rustc_errors::{self, struct_span_err, Applicability};
+use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_span::Span;
@@ -321,11 +321,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         lhs_ty, missing_trait
                                     ));
                                 } else if !suggested_deref {
-                                    err.note(&format!(
-                                        "an implementation of `{}` might \
-                                         be missing for `{}`",
-                                        missing_trait, lhs_ty
-                                    ));
+                                    suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
                                 }
                             }
                             err.emit();
@@ -467,11 +463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                         lhs_ty, missing_trait
                                     ));
                                 } else if !suggested_deref && !involves_fn {
-                                    err.note(&format!(
-                                        "an implementation of `{}` might \
-                                         be missing for `{}`",
-                                        missing_trait, lhs_ty
-                                    ));
+                                    suggest_impl_missing(&mut err, lhs_ty, &missing_trait);
                                 }
                             }
                             err.emit();
@@ -707,11 +699,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 hir::UnOp::UnNot => "std::ops::Not",
                                 hir::UnOp::UnDeref => "std::ops::UnDerf",
                             };
-                            err.note(&format!(
-                                "an implementation of `{}` might \
-                                                be missing for `{}`",
-                                missing_trait, operand_ty
-                            ));
+                            suggest_impl_missing(&mut err, operand_ty, &missing_trait);
                         }
                     }
                     err.emit();
@@ -929,3 +917,16 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
         }
     }
 }
+
+/// If applicable, note that an implementation of `trait` for `ty` may fix the error.
+fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) {
+    if let Adt(def, _) = ty.peel_refs().kind {
+        if def.did.is_local() {
+            err.note(&format!(
+                "an implementation of `{}` might \
+                be missing for `{}`",
+                missing_trait, ty
+            ));
+        }
+    }
+}
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index e8913b6927a..70586be0d04 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -33,7 +33,7 @@ use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
 use rustc::ty::{ReprOptions, ToPredicate, WithConstness};
 use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr};
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -369,10 +369,12 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
                         hir::ItemKind::Enum(_, generics)
                         | hir::ItemKind::Struct(_, generics)
                         | hir::ItemKind::Union(_, generics) => {
-                            // FIXME: look for an appropriate lt name if `'a` is already used
+                            let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics);
                             let (lt_sp, sugg) = match &generics.params[..] {
-                                [] => (generics.span, "<'a>".to_string()),
-                                [bound, ..] => (bound.span.shrink_to_lo(), "'a, ".to_string()),
+                                [] => (generics.span, format!("<{}>", lt_name)),
+                                [bound, ..] => {
+                                    (bound.span.shrink_to_lo(), format!("{}, ", lt_name))
+                                }
                             };
                             let suggestions = vec![
                                 (lt_sp, sugg),
@@ -387,7 +389,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
                                                     ty::EarlyBoundRegion {
                                                         def_id: item_def_id,
                                                         index: 0,
-                                                        name: Symbol::intern("'a"),
+                                                        name: Symbol::intern(&lt_name),
                                                     },
                                                 ))
                                             })
@@ -445,6 +447,43 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
     }
 }
 
+/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
+fn get_new_lifetime_name<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    poly_trait_ref: ty::PolyTraitRef<'tcx>,
+    generics: &hir::Generics<'tcx>,
+) -> String {
+    let existing_lifetimes = tcx
+        .collect_referenced_late_bound_regions(&poly_trait_ref)
+        .into_iter()
+        .filter_map(|lt| {
+            if let ty::BoundRegion::BrNamed(_, name) = lt {
+                Some(name.as_str().to_string())
+            } else {
+                None
+            }
+        })
+        .chain(generics.params.iter().filter_map(|param| {
+            if let hir::GenericParamKind::Lifetime { .. } = &param.kind {
+                Some(param.name.ident().as_str().to_string())
+            } else {
+                None
+            }
+        }))
+        .collect::<FxHashSet<String>>();
+
+    let a_to_z_repeat_n = |n| {
+        (b'a'..=b'z').map(move |c| {
+            let mut s = format!("'");
+            s.extend(std::iter::repeat(char::from(c)).take(n));
+            s
+        })
+    };
+
+    // If all single char lifetime names are present, we wrap around and double the chars.
+    (1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap()
+}
+
 /// Returns the predicates defined on `item_def_id` of the form
 /// `X: Foo` where `X` is the type parameter `def_id`.
 fn type_param_predicates(
@@ -1588,7 +1627,6 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
 /// Returns a list of user-specified type predicates for the definition with ID `def_id`.
 /// N.B., this does not include any implied/inferred constraints.
 fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
-    use rustc_data_structures::fx::FxHashSet;
     use rustc_hir::*;
 
     debug!("explicit_predicates_of(def_id={:?})", def_id);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a9c6fcddc77..9ae3010a0f6 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1612,46 +1612,6 @@ pub struct FnSig {
     pub decl: P<FnDecl>,
 }
 
-/// Represents associated items.
-/// These include items in `impl` and `trait` definitions.
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct AssocItem {
-    pub attrs: Vec<Attribute>,
-    pub id: NodeId,
-    pub span: Span,
-    pub vis: Visibility,
-    pub ident: Ident,
-
-    pub defaultness: Defaultness,
-    pub generics: Generics,
-    pub kind: AssocItemKind,
-    /// See `Item::tokens` for what this is.
-    pub tokens: Option<TokenStream>,
-}
-
-/// Represents various kinds of content within an `impl`.
-///
-/// The term "provided" in the variants below refers to the item having a default
-/// definition / body. Meanwhile, a "required" item lacks a definition / body.
-/// In an implementation, all items must be provided.
-/// The `Option`s below denote the bodies, where `Some(_)`
-/// means "provided" and conversely `None` means "required".
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum AssocItemKind {
-    /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
-    /// If `def` is parsed, then the associated constant is provided, and otherwise required.
-    Const(P<Ty>, Option<P<Expr>>),
-
-    /// An associated function.
-    Fn(FnSig, Option<P<Block>>),
-
-    /// An associated type.
-    TyAlias(GenericBounds, Option<P<Ty>>),
-
-    /// A macro expanding to an associated item.
-    Macro(Mac),
-}
-
 #[derive(
     Clone,
     Copy,
@@ -2542,11 +2502,11 @@ pub enum ItemKind {
     /// A static item (`static`).
     ///
     /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`.
-    Static(P<Ty>, Mutability, P<Expr>),
+    Static(P<Ty>, Mutability, Option<P<Expr>>),
     /// A constant item (`const`).
     ///
     /// E.g., `const FOO: i32 = 42;`.
-    Const(P<Ty>, P<Expr>),
+    Const(P<Ty>, Option<P<Expr>>),
     /// A function declaration (`fn`).
     ///
     /// E.g., `fn foo(bar: usize) -> usize { .. }`.
@@ -2646,28 +2606,45 @@ impl ItemKind {
     }
 }
 
-pub type ForeignItem = Item<ForeignItemKind>;
+// FIXME(Centril): These definitions should be unmerged;
+// see https://github.com/rust-lang/rust/pull/69194#discussion_r379899975
+pub type ForeignItem = Item<AssocItemKind>;
+pub type ForeignItemKind = AssocItemKind;
 
-/// An item within an `extern` block.
+/// Represents associated items.
+/// These include items in `impl` and `trait` definitions.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum ForeignItemKind {
-    /// A foreign function.
-    Fn(FnSig, Generics, Option<P<Block>>),
-    /// A foreign static item (`static ext: u8`).
-    Static(P<Ty>, Mutability),
-    /// A foreign type.
-    Ty,
-    /// A macro invocation.
-    Macro(Mac),
+pub struct AssocItem {
+    pub attrs: Vec<Attribute>,
+    pub id: NodeId,
+    pub span: Span,
+    pub vis: Visibility,
+    pub ident: Ident,
+
+    pub defaultness: Defaultness,
+    pub kind: AssocItemKind,
+    /// See `Item::tokens` for what this is.
+    pub tokens: Option<TokenStream>,
 }
 
-impl ForeignItemKind {
-    pub fn descriptive_variant(&self) -> &str {
-        match *self {
-            ForeignItemKind::Fn(..) => "foreign function",
-            ForeignItemKind::Static(..) => "foreign static item",
-            ForeignItemKind::Ty => "foreign type",
-            ForeignItemKind::Macro(..) => "macro in foreign module",
-        }
-    }
+/// Represents non-free item kinds.
+///
+/// The term "provided" in the variants below refers to the item having a default
+/// definition / body. Meanwhile, a "required" item lacks a definition / body.
+/// In an implementation, all items must be provided.
+/// The `Option`s below denote the bodies, where `Some(_)`
+/// means "provided" and conversely `None` means "required".
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub enum AssocItemKind {
+    /// A constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
+    /// If `def` is parsed, then the constant is provided, and otherwise required.
+    Const(P<Ty>, Option<P<Expr>>),
+    /// A static item (`static FOO: u8`).
+    Static(P<Ty>, Mutability, Option<P<Expr>>),
+    /// A function.
+    Fn(FnSig, Generics, Option<P<Block>>),
+    /// A type.
+    TyAlias(Generics, GenericBounds, Option<P<Ty>>),
+    /// A macro expanding to items.
+    Macro(Mac),
 }
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 2afe4159e93..92f20b719f8 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -890,13 +890,9 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
     match kind {
         ItemKind::ExternCrate(_orig_name) => {}
         ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
-        ItemKind::Static(ty, _mut, expr) => {
+        ItemKind::Static(ty, _, expr) | ItemKind::Const(ty, expr) => {
             vis.visit_ty(ty);
-            vis.visit_expr(expr);
-        }
-        ItemKind::Const(ty, expr) => {
-            vis.visit_ty(ty);
-            vis.visit_expr(expr);
+            visit_opt(expr, |expr| vis.visit_expr(expr));
         }
         ItemKind::Fn(sig, generics, body) => {
             visit_fn_sig(sig, vis);
@@ -951,31 +947,43 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
     mut item: P<AssocItem>,
     visitor: &mut T,
 ) -> SmallVec<[P<AssocItem>; 1]> {
-    let AssocItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } =
+    let AssocItem { id, ident, vis, defaultness: _, attrs, kind, span, tokens: _ } =
         item.deref_mut();
+    walk_nested_item(visitor, id, span, ident, vis, attrs, kind);
+    smallvec![item]
+}
+
+pub fn walk_nested_item(
+    visitor: &mut impl MutVisitor,
+    id: &mut NodeId,
+    span: &mut Span,
+    ident: &mut Ident,
+    vis: &mut Visibility,
+    attrs: &mut Vec<Attribute>,
+    kind: &mut AssocItemKind,
+) {
     visitor.visit_id(id);
     visitor.visit_ident(ident);
     visitor.visit_vis(vis);
     visit_attrs(attrs, visitor);
-    visitor.visit_generics(generics);
     match kind {
-        AssocItemKind::Const(ty, expr) => {
+        AssocItemKind::Const(ty, expr) | AssocItemKind::Static(ty, _, expr) => {
             visitor.visit_ty(ty);
             visit_opt(expr, |expr| visitor.visit_expr(expr));
         }
-        AssocItemKind::Fn(sig, body) => {
+        AssocItemKind::Fn(sig, generics, body) => {
+            visitor.visit_generics(generics);
             visit_fn_sig(sig, visitor);
             visit_opt(body, |body| visitor.visit_block(body));
         }
-        AssocItemKind::TyAlias(bounds, ty) => {
+        AssocItemKind::TyAlias(generics, bounds, ty) => {
+            visitor.visit_generics(generics);
             visit_bounds(bounds, visitor);
             visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
         AssocItemKind::Macro(mac) => visitor.visit_mac(mac),
     }
     visitor.visit_span(span);
-
-    smallvec![item]
 }
 
 pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
@@ -1041,22 +1049,7 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
     visitor: &mut T,
 ) -> SmallVec<[P<ForeignItem>; 1]> {
     let ForeignItem { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut();
-    visitor.visit_ident(ident);
-    visit_attrs(attrs, visitor);
-    match kind {
-        ForeignItemKind::Fn(sig, generics, body) => {
-            visit_fn_sig(sig, visitor);
-            visitor.visit_generics(generics);
-            visit_opt(body, |body| visitor.visit_block(body));
-        }
-        ForeignItemKind::Static(t, _m) => visitor.visit_ty(t),
-        ForeignItemKind::Ty => {}
-        ForeignItemKind::Macro(mac) => visitor.visit_mac(mac),
-    }
-    visitor.visit_id(id);
-    visitor.visit_span(span);
-    visitor.visit_vis(vis);
-
+    walk_nested_item(visitor, id, span, ident, vis, attrs, kind);
     smallvec![item]
 }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 26f3773bea8..dedd42fe0f6 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -300,7 +300,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         ItemKind::Use(ref use_tree) => visitor.visit_use_tree(use_tree, item.id, false),
         ItemKind::Static(ref typ, _, ref expr) | ItemKind::Const(ref typ, ref expr) => {
             visitor.visit_ty(typ);
-            visitor.visit_expr(expr);
+            walk_list!(visitor, visit_expr, expr);
         }
         ItemKind::Fn(ref sig, ref generics, ref body) => {
             visitor.visit_generics(generics);
@@ -525,21 +525,8 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
 }
 
 pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) {
-    visitor.visit_vis(&item.vis);
-    visitor.visit_ident(item.ident);
-
-    match item.kind {
-        ForeignItemKind::Fn(ref sig, ref generics, ref body) => {
-            visitor.visit_generics(generics);
-            let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref());
-            visitor.visit_fn(kind, item.span, item.id);
-        }
-        ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
-        ForeignItemKind::Ty => (),
-        ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac),
-    }
-
-    walk_list!(visitor, visit_attribute, &item.attrs);
+    let ForeignItem { id, span, ident, vis, attrs, kind, tokens: _ } = item;
+    walk_nested_item(visitor, *id, *span, *ident, vis, attrs, kind, FnCtxt::Foreign);
 }
 
 pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) {
@@ -622,24 +609,39 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Spa
 }
 
 pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, ctxt: AssocCtxt) {
-    visitor.visit_vis(&item.vis);
-    visitor.visit_ident(item.ident);
-    walk_list!(visitor, visit_attribute, &item.attrs);
-    visitor.visit_generics(&item.generics);
-    match item.kind {
-        AssocItemKind::Const(ref ty, ref expr) => {
+    let AssocItem { id, span, ident, vis, attrs, kind, tokens: _, defaultness: _ } = item;
+    walk_nested_item(visitor, *id, *span, *ident, vis, attrs, kind, FnCtxt::Assoc(ctxt));
+}
+
+fn walk_nested_item<'a, V: Visitor<'a>>(
+    visitor: &mut V,
+    id: NodeId,
+    span: Span,
+    ident: Ident,
+    vis: &'a Visibility,
+    attrs: &'a [Attribute],
+    kind: &'a AssocItemKind,
+    ctxt: FnCtxt,
+) {
+    visitor.visit_vis(vis);
+    visitor.visit_ident(ident);
+    walk_list!(visitor, visit_attribute, attrs);
+    match kind {
+        AssocItemKind::Const(ty, expr) | AssocItemKind::Static(ty, _, expr) => {
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_expr, expr);
         }
-        AssocItemKind::Fn(ref sig, ref body) => {
-            let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
-            visitor.visit_fn(kind, item.span, item.id);
+        AssocItemKind::Fn(sig, generics, body) => {
+            visitor.visit_generics(generics);
+            let kind = FnKind::Fn(ctxt, ident, sig, vis, body.as_deref());
+            visitor.visit_fn(kind, span, id);
         }
-        AssocItemKind::TyAlias(ref bounds, ref ty) => {
+        AssocItemKind::TyAlias(generics, bounds, ty) => {
+            visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, ty);
         }
-        AssocItemKind::Macro(ref mac) => {
+        AssocItemKind::Macro(mac) => {
             visitor.visit_mac(mac);
         }
     }
diff --git a/src/test/run-make-fulldeps/min-global-align/min_global_align.rs b/src/test/run-make-fulldeps/min-global-align/min_global_align.rs
index ce86d202c62..d9851a2f794 100644
--- a/src/test/run-make-fulldeps/min-global-align/min_global_align.rs
+++ b/src/test/run-make-fulldeps/min-global-align/min_global_align.rs
@@ -1,5 +1,5 @@
 #![feature(no_core, lang_items)]
-#![crate_type="rlib"]
+#![crate_type = "rlib"]
 #![no_core]
 
 pub static STATIC_BOOL: bool = true;
@@ -9,7 +9,6 @@ pub static mut STATIC_MUT_BOOL: bool = true;
 const CONST_BOOL: bool = true;
 pub static CONST_BOOL_REF: &'static bool = &CONST_BOOL;
 
-
 #[lang = "sized"]
 trait Sized {}
 
@@ -19,10 +18,13 @@ trait Copy {}
 #[lang = "freeze"]
 trait Freeze {}
 
+// No `UnsafeCell`, so everything is `Freeze`.
+impl<T: ?Sized> Freeze for T {}
+
 #[lang = "sync"]
 trait Sync {}
 impl Sync for bool {}
 impl Sync for &'static bool {}
 
-#[lang="drop_in_place"]
-pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) { }
+#[lang = "drop_in_place"]
+pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs
index 8a5777d4d7c..58f186d7775 100644
--- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs
@@ -12,11 +12,12 @@ struct SomeStruct<I: for<'x> Foo<&'x isize>> {
     //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
 }
 
-enum SomeEnum<I: for<'x> Foo<&'x isize>> {
+enum SomeEnum<'b, I: for<'a> Foo<&'a isize>> {
     TupleVariant(I::A),
     //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
     StructVariant { field: I::A },
     //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
+    OkVariant(&'b usize),
 }
 
 // FIXME(eddyb) This one doesn't even compile because of the unsupported syntax.
@@ -26,7 +27,13 @@ enum SomeEnum<I: for<'x> Foo<&'x isize>> {
 // }
 
 struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> {
-    field: <I as Foo<&'a isize>>::A
+    field: <I as Foo<&'a isize>>::A,
+}
+
+struct Why<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x,
+    'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> {
+    field: I::A,
+    //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context
 }
 
 pub fn main() {}
diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr
index c71bc70ea6c..e3fd2860ebc 100644
--- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr
+++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr
@@ -18,8 +18,8 @@ LL |     TupleVariant(I::A),
    |
 help: use a fully qualified path with explicit lifetimes
    |
-LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> {
-LL |     TupleVariant(<I as Foo<&'a isize>>::A),
+LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> {
+LL |     TupleVariant(<I as Foo<&'c isize>>::A),
    |
 
 error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context
@@ -30,11 +30,24 @@ LL |     StructVariant { field: I::A },
    |
 help: use a fully qualified path with explicit lifetimes
    |
-LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> {
+LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> {
 LL |     TupleVariant(I::A),
 LL |
-LL |     StructVariant { field: <I as Foo<&'a isize>>::A },
+LL |     StructVariant { field: <I as Foo<&'c isize>>::A },
    |
 
-error: aborting due to 3 previous errors
+error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context
+  --> $DIR/associated-types-project-from-hrtb-in-struct.rs:35:12
+   |
+LL |     field: I::A,
+   |            ^^^^
+   |
+help: use a fully qualified path with explicit lifetimes
+   |
+LL | struct Why<'bb, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x,
+LL |     'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> {
+LL |     field: <I as Foo<&'bb &'bb isize>>::A,
+   |
+
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/autoderef-full-lval.stderr b/src/test/ui/autoderef-full-lval.stderr
index e2870ef8062..f094388794e 100644
--- a/src/test/ui/autoderef-full-lval.stderr
+++ b/src/test/ui/autoderef-full-lval.stderr
@@ -5,8 +5,6 @@ LL |     let z: isize = a.x + b.y;
    |                    --- ^ --- std::boxed::Box<isize>
    |                    |
    |                    std::boxed::Box<isize>
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box<isize>`
 
 error[E0369]: cannot add `std::boxed::Box<isize>` to `std::boxed::Box<isize>`
   --> $DIR/autoderef-full-lval.rs:21:33
@@ -15,8 +13,6 @@ LL |     let answer: isize = forty.a + two.a;
    |                         ------- ^ ----- std::boxed::Box<isize>
    |                         |
    |                         std::boxed::Box<isize>
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box<isize>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/binop/binop-bitxor-str.stderr b/src/test/ui/binop/binop-bitxor-str.stderr
index 9a0d301d863..18c1ce0ff02 100644
--- a/src/test/ui/binop/binop-bitxor-str.stderr
+++ b/src/test/ui/binop/binop-bitxor-str.stderr
@@ -5,8 +5,6 @@ LL | fn main() { let x = "a".to_string() ^ "b".to_string(); }
    |                     --------------- ^ --------------- std::string::String
    |                     |
    |                     std::string::String
-   |
-   = note: an implementation of `std::ops::BitXor` might be missing for `std::string::String`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/binop/binop-mul-bool.stderr b/src/test/ui/binop/binop-mul-bool.stderr
index ade22025589..859c44a859e 100644
--- a/src/test/ui/binop/binop-mul-bool.stderr
+++ b/src/test/ui/binop/binop-mul-bool.stderr
@@ -5,8 +5,6 @@ LL | fn main() { let x = true * false; }
    |                     ---- ^ ----- bool
    |                     |
    |                     bool
-   |
-   = note: an implementation of `std::ops::Mul` might be missing for `bool`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/binop/binop-typeck.stderr b/src/test/ui/binop/binop-typeck.stderr
index ebf82079ef2..42d91081999 100644
--- a/src/test/ui/binop/binop-typeck.stderr
+++ b/src/test/ui/binop/binop-typeck.stderr
@@ -5,8 +5,6 @@ LL |     let z = x + y;
    |             - ^ - {integer}
    |             |
    |             bool
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `bool`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
index 781a179624e..c03377d74e9 100644
--- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
+++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr
@@ -23,8 +23,6 @@ LL |     [0_usize; 33] == [1_usize; 33]
    |     ------------- ^^ ------------- [usize; 33]
    |     |
    |     [usize; 33]
-   |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `[usize; 33]`
 
 error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]`
   --> $DIR/core-traits-no-impls-length-33.rs:19:19
@@ -33,8 +31,6 @@ LL |     [0_usize; 33] < [1_usize; 33]
    |     ------------- ^ ------------- [usize; 33]
    |     |
    |     [usize; 33]
-   |
-   = note: an implementation of `std::cmp::PartialOrd` might be missing for `[usize; 33]`
 
 error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied
   --> $DIR/core-traits-no-impls-length-33.rs:24:14
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr
index a6805c32a6e..d4e25930d22 100644
--- a/src/test/ui/destructuring-assignment/note-unsupported.stderr
+++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr
@@ -16,8 +16,6 @@ LL |     (a, b) += (3, 4);
    |     ------^^^^^^^^^^
    |     |
    |     cannot use `+=` on type `({integer}, {integer})`
-   |
-   = note: an implementation of `std::ops::AddAssign` might be missing for `({integer}, {integer})`
 
 error[E0067]: invalid left-hand side of assignment
   --> $DIR/note-unsupported.rs:7:12
@@ -48,8 +46,6 @@ LL |     [a, b] += [3, 4];
    |     ------^^^^^^^^^^
    |     |
    |     cannot use `+=` on type `[{integer}; 2]`
-   |
-   = note: an implementation of `std::ops::AddAssign` might be missing for `[{integer}; 2]`
 
 error[E0067]: invalid left-hand side of assignment
   --> $DIR/note-unsupported.rs:11:12
diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs
index 60633c6930c..2ed682cea95 100644
--- a/src/test/ui/did_you_mean/issue-40006.rs
+++ b/src/test/ui/did_you_mean/issue-40006.rs
@@ -18,10 +18,10 @@ trait A { //~ ERROR missing
 trait B {
     fn xxx() { ### } //~ ERROR expected
 }
-trait C { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration
+trait C { //~ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
     L = M;
 }
-trait D { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration
+trait D { //~ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
     Z = { 2 + 3 };
 }
 trait E {
diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr
index 072e61f6a3c..119e30a3e0f 100644
--- a/src/test/ui/did_you_mean/issue-40006.stderr
+++ b/src/test/ui/did_you_mean/issue-40006.stderr
@@ -1,26 +1,26 @@
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-40006.rs:1:13
    |
 LL |   impl dyn A {
    |  _____________^
 LL | |     Y
-   | |____^ missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, `const`, or `static`
 
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-40006.rs:7:10
    |
 LL |   trait X {
    |  __________^
 LL | |     X() {}
-   | |____^ missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, `const`, or `static`
 
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-40006.rs:15:10
    |
 LL |   trait A {
    |  __________^
 LL | |     X() {}
-   | |____^ missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, `const`, or `static`
 
 error: expected `[`, found `#`
   --> $DIR/issue-40006.rs:19:17
@@ -28,21 +28,21 @@ error: expected `[`, found `#`
 LL |     fn xxx() { ### }
    |                 ^ expected `[`
 
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-40006.rs:21:10
    |
 LL |   trait C {
    |  __________^
 LL | |     L = M;
-   | |____^ missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, `const`, or `static`
 
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-40006.rs:24:10
    |
 LL |   trait D {
    |  __________^
 LL | |     Z = { 2 + 3 };
-   | |____^ missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, `const`, or `static`
 
 error: expected one of `!` or `::`, found `(`
   --> $DIR/issue-40006.rs:28:9
@@ -50,11 +50,11 @@ error: expected one of `!` or `::`, found `(`
 LL |     ::Y ();
    |         ^ expected one of `!` or `::`
 
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-40006.rs:32:8
    |
 LL |     pub hello_method(&self) {
-   |        ^ missing `fn`, `type`, or `const`
+   |        ^ missing `fn`, `type`, `const`, or `static`
 
 error[E0599]: no method named `hello_method` found for struct `S` in the current scope
   --> $DIR/issue-40006.rs:38:7
diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr
index 526503798b3..fad8270fd5a 100644
--- a/src/test/ui/error-codes/E0067.stderr
+++ b/src/test/ui/error-codes/E0067.stderr
@@ -5,8 +5,6 @@ LL |     LinkedList::new() += 1;
    |     -----------------^^^^^
    |     |
    |     cannot use `+=` on type `std::collections::LinkedList<_>`
-   |
-   = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>`
 
 error[E0067]: invalid left-hand side of assignment
   --> $DIR/E0067.rs:4:23
diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr
index 9b69b373364..fb5290bf64e 100644
--- a/src/test/ui/error-festival.stderr
+++ b/src/test/ui/error-festival.stderr
@@ -23,8 +23,6 @@ LL |     x += 2;
    |     -^^^^^
    |     |
    |     cannot use `+=` on type `&str`
-   |
-   = note: an implementation of `std::ops::AddAssign` might be missing for `&str`
 
 error[E0599]: no method named `z` found for reference `&str` in the current scope
   --> $DIR/error-festival.rs:16:7
diff --git a/src/test/ui/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr
index 258202b6903..7f67adbdb19 100644
--- a/src/test/ui/extern/extern-const.stderr
+++ b/src/test/ui/extern/extern-const.stderr
@@ -1,8 +1,12 @@
 error: extern items cannot be `const`
-  --> $DIR/extern-const.rs:16:5
+  --> $DIR/extern-const.rs:16:11
    |
 LL |     const rust_dbg_static_mut: libc::c_int;
-   |     ^^^^^ help: try using a static value: `static`
+   |     ------^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     help: try using a static value: `static`
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/for/for-loop-type-error.stderr b/src/test/ui/for/for-loop-type-error.stderr
index 0ed26384f40..c93a3b9b25c 100644
--- a/src/test/ui/for/for-loop-type-error.stderr
+++ b/src/test/ui/for/for-loop-type-error.stderr
@@ -5,8 +5,6 @@ LL |     let x = () + ();
    |             -- ^ -- ()
    |             |
    |             ()
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `()`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-14915.stderr b/src/test/ui/issues/issue-14915.stderr
index 00b9909af59..3c34a8a3467 100644
--- a/src/test/ui/issues/issue-14915.stderr
+++ b/src/test/ui/issues/issue-14915.stderr
@@ -5,8 +5,6 @@ LL |     println!("{}", x + 1);
    |                    - ^ - {integer}
    |                    |
    |                    std::boxed::Box<isize>
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box<isize>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-24363.stderr b/src/test/ui/issues/issue-24363.stderr
index a60fb24ec12..16537e21ae0 100644
--- a/src/test/ui/issues/issue-24363.stderr
+++ b/src/test/ui/issues/issue-24363.stderr
@@ -11,8 +11,6 @@ LL |         ()+()
    |         --^-- ()
    |         |
    |         ()
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `()`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr
index 5d65734cd23..4c0e1cf7ebb 100644
--- a/src/test/ui/issues/issue-31076.stderr
+++ b/src/test/ui/issues/issue-31076.stderr
@@ -5,8 +5,6 @@ LL |     let x = 5 + 6;
    |             - ^ - {integer}
    |             |
    |             {integer}
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `{integer}`
 
 error[E0369]: cannot add `i32` to `i32`
   --> $DIR/issue-31076.rs:15:18
@@ -15,8 +13,6 @@ LL |     let y = 5i32 + 6i32;
    |             ---- ^ ---- i32
    |             |
    |             i32
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `i32`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-35668.stderr b/src/test/ui/issues/issue-35668.stderr
index 9d5796a5eef..98e8e6366b9 100644
--- a/src/test/ui/issues/issue-35668.stderr
+++ b/src/test/ui/issues/issue-35668.stderr
@@ -5,8 +5,6 @@ LL |     a.iter().map(|a| a*a)
    |                      -^- &T
    |                      |
    |                      &T
-   |
-   = note: an implementation of `std::ops::Mul` might be missing for `&T`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-40610.stderr b/src/test/ui/issues/issue-40610.stderr
index 95f45c168e1..b4e302dfffc 100644
--- a/src/test/ui/issues/issue-40610.stderr
+++ b/src/test/ui/issues/issue-40610.stderr
@@ -5,8 +5,6 @@ LL |     () + f(&[1.0]);
    |     -- ^ --------- ()
    |     |
    |     ()
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `()`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-41394.stderr b/src/test/ui/issues/issue-41394.stderr
index 3f60ea4bbf7..47a24547d45 100644
--- a/src/test/ui/issues/issue-41394.stderr
+++ b/src/test/ui/issues/issue-41394.stderr
@@ -5,8 +5,6 @@ LL |     A = "" + 1
    |         -- ^ - {integer}
    |         |
    |         &str
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `&str`
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/issue-41394.rs:7:9
diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr
index 6221b90b31d..f4ca3c46ea2 100644
--- a/src/test/ui/issues/issue-58856-2.stderr
+++ b/src/test/ui/issues/issue-58856-2.stderr
@@ -7,11 +7,11 @@ LL |     fn how_are_you(&self -> Empty {
    |                   |     help: `)` may belong here
    |                   unclosed delimiter
 
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `)`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `static`, `type`, `unsafe`, `}`, or identifier, found `)`
   --> $DIR/issue-58856-2.rs:11:1
    |
 LL |     }
-   |      - expected one of 11 possible tokens
+   |      - expected one of 12 possible tokens
 LL | }
    | ^ unexpected token
 
diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr
index 2ac5577e0a0..58f1376b19d 100644
--- a/src/test/ui/issues/issue-59488.stderr
+++ b/src/test/ui/issues/issue-59488.stderr
@@ -58,8 +58,6 @@ LL |     foo > bar;
    |     --- ^ --- fn(i64) -> i64 {bar}
    |     |
    |     fn() -> i32 {foo}
-   |
-   = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() -> i32 {foo}`
 
 error[E0308]: mismatched types
   --> $DIR/issue-59488.rs:25:11
@@ -79,7 +77,6 @@ LL |     assert_eq!(Foo::Bar, i);
    |     fn(usize) -> Foo {Foo::Bar}
    |     fn(usize) -> Foo {Foo::Bar}
    |
-   = note: an implementation of `std::cmp::PartialEq` might be missing for `fn(usize) -> Foo {Foo::Bar}`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug`
diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr
index b2beb73503b..bab50a53b1a 100644
--- a/src/test/ui/issues/issue-60075.stderr
+++ b/src/test/ui/issues/issue-60075.stderr
@@ -4,7 +4,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
 LL |         });
    |          ^ expected one of `.`, `;`, `?`, `else`, or an operator
 
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `;`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `static`, `type`, `unsafe`, `}`, or identifier, found `;`
   --> $DIR/issue-60075.rs:6:11
    |
 LL |     fn qux() -> Option<usize> {
diff --git a/src/test/ui/issues/issue-6596-1.rs b/src/test/ui/issues/issue-6596-1.rs
index 5da54451346..25f1d650072 100644
--- a/src/test/ui/issues/issue-6596-1.rs
+++ b/src/test/ui/issues/issue-6596-1.rs
@@ -1,7 +1,7 @@
 macro_rules! e {
     ($inp:ident) => (
         $nonexistent
-        //~^ ERROR unknown macro variable `nonexistent`
+        //~^ ERROR expected expression, found `$`
     );
 }
 
diff --git a/src/test/ui/issues/issue-6596-1.stderr b/src/test/ui/issues/issue-6596-1.stderr
index 4f29d8a9274..216fe6472a5 100644
--- a/src/test/ui/issues/issue-6596-1.stderr
+++ b/src/test/ui/issues/issue-6596-1.stderr
@@ -1,8 +1,8 @@
-error: unknown macro variable `nonexistent`
+error: expected expression, found `$`
   --> $DIR/issue-6596-1.rs:3:9
    |
 LL |         $nonexistent
-   |         ^^^^^^^^^^^^ unknown macro variable
+   |         ^^^^^^^^^^^^ expected expression
 ...
 LL |     e!(foo);
    |     -------- in this macro invocation
diff --git a/src/test/ui/issues/issue-6596-2.rs b/src/test/ui/issues/issue-6596-2.rs
index b19700efe5a..8f7c98d9a67 100644
--- a/src/test/ui/issues/issue-6596-2.rs
+++ b/src/test/ui/issues/issue-6596-2.rs
@@ -3,7 +3,7 @@
 macro_rules! g {
     ($inp:ident) => (
         { $inp $nonexistent }
-        //~^ ERROR unknown macro variable `nonexistent`
+        //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$`
     );
 }
 
diff --git a/src/test/ui/issues/issue-6596-2.stderr b/src/test/ui/issues/issue-6596-2.stderr
index 4fcb0176faa..3d13c64f762 100644
--- a/src/test/ui/issues/issue-6596-2.stderr
+++ b/src/test/ui/issues/issue-6596-2.stderr
@@ -1,8 +1,8 @@
-error: unknown macro variable `nonexistent`
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$`
   --> $DIR/issue-6596-2.rs:5:16
    |
 LL |         { $inp $nonexistent }
-   |                ^^^^^^^^^^^^ unknown macro variable
+   |                ^^^^^^^^^^^^ expected one of 8 possible tokens
 ...
 LL |     g!(foo);
    |     -------- in this macro invocation
diff --git a/src/test/ui/macros/issue-54441.rs b/src/test/ui/macros/issue-54441.rs
index a70163df1cb..5570f081b15 100644
--- a/src/test/ui/macros/issue-54441.rs
+++ b/src/test/ui/macros/issue-54441.rs
@@ -1,5 +1,5 @@
 macro_rules! m {
-    //~^ ERROR missing `fn`, `type`, or `static` for extern-item declaration
+    //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
     () => {
         let
     };
diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr
index 761e7aec723..5857aacb431 100644
--- a/src/test/ui/macros/issue-54441.stderr
+++ b/src/test/ui/macros/issue-54441.stderr
@@ -1,11 +1,11 @@
-error: missing `fn`, `type`, or `static` for extern-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-54441.rs:1:1
    |
 LL | / macro_rules! m {
 LL | |
 LL | |     () => {
 LL | |         let
-   | |________^ missing `fn`, `type`, or `static`
+   | |________^ missing `fn`, `type`, `const`, or `static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/minus-string.stderr b/src/test/ui/minus-string.stderr
index 9177082cf0b..3fbec7c89c9 100644
--- a/src/test/ui/minus-string.stderr
+++ b/src/test/ui/minus-string.stderr
@@ -3,8 +3,6 @@ error[E0600]: cannot apply unary operator `-` to type `std::string::String`
    |
 LL | fn main() { -"foo".to_string(); }
    |             ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-`
-   |
-   = note: an implementation of `std::ops::Neg` might be missing for `std::string::String`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs b/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs
new file mode 100644
index 00000000000..d37ce06c555
--- /dev/null
+++ b/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs
@@ -0,0 +1,17 @@
+// Semantically, an associated constant cannot use `_` as a name.
+
+fn main() {}
+
+const _: () = {
+    pub trait A {
+        const _: () = (); //~ ERROR `const` items in this context need a name
+    }
+    impl A for () {
+        const _: () = (); //~ ERROR `const` items in this context need a name
+        //~^ ERROR const `_` is not a member of trait `A`
+    }
+    struct B;
+    impl B {
+        const _: () = (); //~ ERROR `const` items in this context need a name
+    }
+};
diff --git a/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr b/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr
new file mode 100644
index 00000000000..538bf0ec100
--- /dev/null
+++ b/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr
@@ -0,0 +1,27 @@
+error: `const` items in this context need a name
+  --> $DIR/assoc-const-underscore-semantic-fail.rs:7:15
+   |
+LL |         const _: () = ();
+   |               ^ `_` is not a valid name for this `const` item
+
+error: `const` items in this context need a name
+  --> $DIR/assoc-const-underscore-semantic-fail.rs:10:15
+   |
+LL |         const _: () = ();
+   |               ^ `_` is not a valid name for this `const` item
+
+error: `const` items in this context need a name
+  --> $DIR/assoc-const-underscore-semantic-fail.rs:15:15
+   |
+LL |         const _: () = ();
+   |               ^ `_` is not a valid name for this `const` item
+
+error[E0438]: const `_` is not a member of trait `A`
+  --> $DIR/assoc-const-underscore-semantic-fail.rs:10:9
+   |
+LL |         const _: () = ();
+   |         ^^^^^^^^^^^^^^^^^ not a member of trait `A`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0438`.
diff --git a/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs b/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs
new file mode 100644
index 00000000000..60da408c811
--- /dev/null
+++ b/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs
@@ -0,0 +1,18 @@
+// All constant items (associated or otherwise) may syntactically use `_` as a name.
+
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+const _: () = {
+    pub trait A {
+        const _: () = ();
+    }
+    impl A for () {
+        const _: () = ();
+    }
+    impl dyn A {
+        const _: () = ();
+    }
+};
diff --git a/src/test/ui/parser/assoc-static-semantic-fail.rs b/src/test/ui/parser/assoc-static-semantic-fail.rs
new file mode 100644
index 00000000000..cf3debd77cb
--- /dev/null
+++ b/src/test/ui/parser/assoc-static-semantic-fail.rs
@@ -0,0 +1,43 @@
+// Semantically, we do not allow e.g., `static X: u8 = 0;` as an associated item.
+
+#![feature(specialization)]
+
+fn main() {}
+
+struct S;
+impl S {
+    static IA: u8 = 0;
+    //~^ ERROR associated `static` items are not allowed
+    static IB: u8;
+    //~^ ERROR associated `static` items are not allowed
+    default static IC: u8 = 0;
+    //~^ ERROR associated `static` items are not allowed
+    pub(crate) default static ID: u8;
+    //~^ ERROR associated `static` items are not allowed
+}
+
+trait T {
+    static TA: u8 = 0;
+    //~^ ERROR associated `static` items are not allowed
+    static TB: u8;
+    //~^ ERROR associated `static` items are not allowed
+    default static TC: u8 = 0;
+    //~^ ERROR associated `static` items are not allowed
+    //~| ERROR `default` is only allowed on items in
+    pub(crate) default static TD: u8;
+    //~^ ERROR associated `static` items are not allowed
+    //~| ERROR `default` is only allowed on items in
+    //~| ERROR unnecessary visibility qualifier
+}
+
+impl T for S {
+    static TA: u8 = 0;
+    //~^ ERROR associated `static` items are not allowed
+    static TB: u8;
+    //~^ ERROR associated `static` items are not allowed
+    default static TC: u8 = 0;
+    //~^ ERROR associated `static` items are not allowed
+    pub default static TD: u8;
+    //~^ ERROR associated `static` items are not allowed
+    //~| ERROR unnecessary visibility qualifier
+}
diff --git a/src/test/ui/parser/assoc-static-semantic-fail.stderr b/src/test/ui/parser/assoc-static-semantic-fail.stderr
new file mode 100644
index 00000000000..d02e2855c7e
--- /dev/null
+++ b/src/test/ui/parser/assoc-static-semantic-fail.stderr
@@ -0,0 +1,99 @@
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:9:5
+   |
+LL |     static IA: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:11:5
+   |
+LL |     static IB: u8;
+   |     ^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:13:5
+   |
+LL |     default static IC: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:15:5
+   |
+LL |     pub(crate) default static ID: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:20:5
+   |
+LL |     static TA: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:22:5
+   |
+LL |     static TB: u8;
+   |     ^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:24:5
+   |
+LL |     default static TC: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:27:5
+   |
+LL |     pub(crate) default static TD: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:34:5
+   |
+LL |     static TA: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:36:5
+   |
+LL |     static TB: u8;
+   |     ^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:38:5
+   |
+LL |     default static TC: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-semantic-fail.rs:40:5
+   |
+LL |     pub default static TD: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/assoc-static-semantic-fail.rs:24:5
+   |
+LL |     default static TC: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `default` is only allowed on items in `impl` definitions
+  --> $DIR/assoc-static-semantic-fail.rs:27:5
+   |
+LL |     pub(crate) default static TD: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0449]: unnecessary visibility qualifier
+  --> $DIR/assoc-static-semantic-fail.rs:27:5
+   |
+LL |     pub(crate) default static TD: u8;
+   |     ^^^^^^^^^^
+
+error[E0449]: unnecessary visibility qualifier
+  --> $DIR/assoc-static-semantic-fail.rs:40:5
+   |
+LL |     pub default static TD: u8;
+   |     ^^^ `pub` not permitted here because it's implied
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0449`.
diff --git a/src/test/ui/parser/assoc-static-syntactic-fail.rs b/src/test/ui/parser/assoc-static-syntactic-fail.rs
new file mode 100644
index 00000000000..8f042767e55
--- /dev/null
+++ b/src/test/ui/parser/assoc-static-syntactic-fail.rs
@@ -0,0 +1,27 @@
+// Syntactically, we do allow e.g., `static X: u8 = 0;` as an associated item.
+
+fn main() {}
+
+#[cfg(FALSE)]
+impl S {
+    static IA: u8 = 0; //~ ERROR associated `static` items are not allowed
+    static IB: u8; //~ ERROR associated `static` items are not allowed
+    default static IC: u8 = 0; //~ ERROR associated `static` items are not allowed
+    pub(crate) default static ID: u8; //~ ERROR associated `static` items are not allowed
+}
+
+#[cfg(FALSE)]
+trait T {
+    static TA: u8 = 0; //~ ERROR associated `static` items are not allowed
+    static TB: u8; //~ ERROR associated `static` items are not allowed
+    default static TC: u8 = 0; //~ ERROR associated `static` items are not allowed
+    pub(crate) default static TD: u8; //~ ERROR associated `static` items are not allowed
+}
+
+#[cfg(FALSE)]
+impl T for S {
+    static TA: u8 = 0; //~ ERROR associated `static` items are not allowed
+    static TB: u8; //~ ERROR associated `static` items are not allowed
+    default static TC: u8 = 0; //~ ERROR associated `static` items are not allowed
+    pub default static TD: u8; //~ ERROR associated `static` items are not allowed
+}
diff --git a/src/test/ui/parser/assoc-static-syntactic-fail.stderr b/src/test/ui/parser/assoc-static-syntactic-fail.stderr
new file mode 100644
index 00000000000..bb1e5c4be2e
--- /dev/null
+++ b/src/test/ui/parser/assoc-static-syntactic-fail.stderr
@@ -0,0 +1,74 @@
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:7:5
+   |
+LL |     static IA: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:8:5
+   |
+LL |     static IB: u8;
+   |     ^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:9:5
+   |
+LL |     default static IC: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:10:5
+   |
+LL |     pub(crate) default static ID: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:15:5
+   |
+LL |     static TA: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:16:5
+   |
+LL |     static TB: u8;
+   |     ^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:17:5
+   |
+LL |     default static TC: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:18:5
+   |
+LL |     pub(crate) default static TD: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:23:5
+   |
+LL |     static TA: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:24:5
+   |
+LL |     static TB: u8;
+   |     ^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:25:5
+   |
+LL |     default static TC: u8 = 0;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: associated `static` items are not allowed
+  --> $DIR/assoc-static-syntactic-fail.rs:26:5
+   |
+LL |     pub default static TD: u8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/ui/parser/default.rs b/src/test/ui/parser/default.rs
index 65ecb1ebbe9..50952eef22f 100644
--- a/src/test/ui/parser/default.rs
+++ b/src/test/ui/parser/default.rs
@@ -20,7 +20,7 @@ impl Foo for u16 {
 
 impl Foo for u32 { //~ ERROR not all trait items implemented, missing: `foo`
     default pub fn foo<T: Default>() -> T { T::default() }
-    //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration
+    //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr
index ede9e471518..07b051ece2b 100644
--- a/src/test/ui/parser/default.stderr
+++ b/src/test/ui/parser/default.stderr
@@ -1,8 +1,8 @@
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/default.rs:22:12
    |
 LL |     default pub fn foo<T: Default>() -> T { T::default() }
-   |            ^ missing `fn`, `type`, or `const`
+   |            ^ missing `fn`, `type`, `const`, or `static`
 
 error[E0449]: unnecessary visibility qualifier
   --> $DIR/default.rs:16:5
diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs
index 1d271fa64b0..f6e7f7e6abe 100644
--- a/src/test/ui/parser/duplicate-visibility.rs
+++ b/src/test/ui/parser/duplicate-visibility.rs
@@ -2,5 +2,5 @@ fn main() {}
 
 extern {
     pub pub fn foo();
-    //~^ ERROR missing `fn`, `type`, or `static` for extern-item declaration
+    //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
 }
diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr
index 36a3a1ed5a0..398ba65c9e1 100644
--- a/src/test/ui/parser/duplicate-visibility.stderr
+++ b/src/test/ui/parser/duplicate-visibility.stderr
@@ -1,8 +1,8 @@
-error: missing `fn`, `type`, or `static` for extern-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/duplicate-visibility.rs:4:8
    |
 LL |     pub pub fn foo();
-   |        ^ missing `fn`, `type`, or `static`
+   |        ^ missing `fn`, `type`, `const`, or `static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/extern-no-fn.rs b/src/test/ui/parser/extern-no-fn.rs
index c37ddd69ce5..dc47f741073 100644
--- a/src/test/ui/parser/extern-no-fn.rs
+++ b/src/test/ui/parser/extern-no-fn.rs
@@ -1,4 +1,5 @@
-extern { //~ ERROR missing `fn`, `type`, or `static` for extern-item declaration
+extern {
+//~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
     f();
 }
 
diff --git a/src/test/ui/parser/extern-no-fn.stderr b/src/test/ui/parser/extern-no-fn.stderr
index d2d5e3c4687..8d55eefc8d0 100644
--- a/src/test/ui/parser/extern-no-fn.stderr
+++ b/src/test/ui/parser/extern-no-fn.stderr
@@ -1,10 +1,11 @@
-error: missing `fn`, `type`, or `static` for extern-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/extern-no-fn.rs:1:9
    |
 LL |   extern {
    |  _________^
+LL | |
 LL | |     f();
-   | |____^ missing `fn`, `type`, or `static`
+   | |____^ missing `fn`, `type`, `const`, or `static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/foreign-const-semantic-fail.rs b/src/test/ui/parser/foreign-const-semantic-fail.rs
new file mode 100644
index 00000000000..d28b6414282
--- /dev/null
+++ b/src/test/ui/parser/foreign-const-semantic-fail.rs
@@ -0,0 +1,8 @@
+fn main() {}
+
+extern {
+    const A: isize;
+    //~^ ERROR extern items cannot be `const`
+    const B: isize = 42;
+    //~^ ERROR extern items cannot be `const`
+}
diff --git a/src/test/ui/parser/foreign-const-semantic-fail.stderr b/src/test/ui/parser/foreign-const-semantic-fail.stderr
new file mode 100644
index 00000000000..f364f11bb03
--- /dev/null
+++ b/src/test/ui/parser/foreign-const-semantic-fail.stderr
@@ -0,0 +1,22 @@
+error: extern items cannot be `const`
+  --> $DIR/foreign-const-semantic-fail.rs:4:11
+   |
+LL |     const A: isize;
+   |     ------^
+   |     |
+   |     help: try using a static value: `static`
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: extern items cannot be `const`
+  --> $DIR/foreign-const-semantic-fail.rs:6:11
+   |
+LL |     const B: isize = 42;
+   |     ------^
+   |     |
+   |     help: try using a static value: `static`
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/foreign-const-syntactic-fail.rs b/src/test/ui/parser/foreign-const-syntactic-fail.rs
new file mode 100644
index 00000000000..a78f8b1623a
--- /dev/null
+++ b/src/test/ui/parser/foreign-const-syntactic-fail.rs
@@ -0,0 +1,9 @@
+// Syntactically, a `const` item inside an `extern { ... }` block is not allowed.
+
+fn main() {}
+
+#[cfg(FALSE)]
+extern {
+    const A: isize; //~ ERROR extern items cannot be `const`
+    const B: isize = 42; //~ ERROR extern items cannot be `const`
+}
diff --git a/src/test/ui/parser/foreign-const-syntactic-fail.stderr b/src/test/ui/parser/foreign-const-syntactic-fail.stderr
new file mode 100644
index 00000000000..9cf58fa95fb
--- /dev/null
+++ b/src/test/ui/parser/foreign-const-syntactic-fail.stderr
@@ -0,0 +1,22 @@
+error: extern items cannot be `const`
+  --> $DIR/foreign-const-syntactic-fail.rs:7:11
+   |
+LL |     const A: isize;
+   |     ------^
+   |     |
+   |     help: try using a static value: `static`
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: extern items cannot be `const`
+  --> $DIR/foreign-const-syntactic-fail.rs:8:11
+   |
+LL |     const B: isize = 42;
+   |     ------^
+   |     |
+   |     help: try using a static value: `static`
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/foreign-static-semantic-fail.rs b/src/test/ui/parser/foreign-static-semantic-fail.rs
new file mode 100644
index 00000000000..9abdf33df9c
--- /dev/null
+++ b/src/test/ui/parser/foreign-static-semantic-fail.rs
@@ -0,0 +1,8 @@
+// Syntactically, a foreign static may not have a body.
+
+fn main() {}
+
+extern {
+    static X: u8 = 0; //~ ERROR incorrect `static` inside `extern` block
+    static mut Y: u8 = 0; //~ ERROR incorrect `static` inside `extern` block
+}
diff --git a/src/test/ui/parser/foreign-static-semantic-fail.stderr b/src/test/ui/parser/foreign-static-semantic-fail.stderr
new file mode 100644
index 00000000000..5942e3a9449
--- /dev/null
+++ b/src/test/ui/parser/foreign-static-semantic-fail.stderr
@@ -0,0 +1,27 @@
+error: incorrect `static` inside `extern` block
+  --> $DIR/foreign-static-semantic-fail.rs:6:12
+   |
+LL | extern {
+   | ------ `extern` blocks define existing foreign statics and statics inside of them cannot have a body
+LL |     static X: u8 = 0;
+   |            ^       - the invalid body
+   |            |
+   |            cannot have a body
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: incorrect `static` inside `extern` block
+  --> $DIR/foreign-static-semantic-fail.rs:7:16
+   |
+LL | extern {
+   | ------ `extern` blocks define existing foreign statics and statics inside of them cannot have a body
+LL |     static X: u8 = 0;
+LL |     static mut Y: u8 = 0;
+   |                ^       - the invalid body
+   |                |
+   |                cannot have a body
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/foreign-static-syntactic-pass.rs b/src/test/ui/parser/foreign-static-syntactic-pass.rs
new file mode 100644
index 00000000000..2c805e8a0b7
--- /dev/null
+++ b/src/test/ui/parser/foreign-static-syntactic-pass.rs
@@ -0,0 +1,11 @@
+// Syntactically, a foreign static may have a body.
+
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+extern {
+    static X: u8 = 0;
+    static mut Y: u8 = 0;
+}
diff --git a/src/test/ui/parser/foreign-ty-semantic-fail.rs b/src/test/ui/parser/foreign-ty-semantic-fail.rs
new file mode 100644
index 00000000000..96b15232b10
--- /dev/null
+++ b/src/test/ui/parser/foreign-ty-semantic-fail.rs
@@ -0,0 +1,18 @@
+#![feature(extern_types)]
+
+fn main() {}
+
+extern "C" {
+    type A: Ord;
+    //~^ ERROR bounds on `type`s in `extern` blocks have no effect
+    type B<'a> where 'a: 'static;
+    //~^ ERROR `type`s inside `extern` blocks cannot have generic parameters
+    //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses
+    type C<T: Ord> where T: 'static;
+    //~^ ERROR `type`s inside `extern` blocks cannot have generic parameters
+    //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses
+    type D = u8;
+    //~^ ERROR incorrect `type` inside `extern` block
+
+    type E: where;
+}
diff --git a/src/test/ui/parser/foreign-ty-semantic-fail.stderr b/src/test/ui/parser/foreign-ty-semantic-fail.stderr
new file mode 100644
index 00000000000..588e4966aae
--- /dev/null
+++ b/src/test/ui/parser/foreign-ty-semantic-fail.stderr
@@ -0,0 +1,65 @@
+error: bounds on `type`s in `extern` blocks have no effect
+  --> $DIR/foreign-ty-semantic-fail.rs:6:13
+   |
+LL |     type A: Ord;
+   |             ^^^
+
+error: `type`s inside `extern` blocks cannot have generic parameters
+  --> $DIR/foreign-ty-semantic-fail.rs:8:11
+   |
+LL | extern "C" {
+   | ---------- `extern` block begins here
+...
+LL |     type B<'a> where 'a: 'static;
+   |           ^^^^ help: remove the generic parameters
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: `type`s inside `extern` blocks cannot have `where` clauses
+  --> $DIR/foreign-ty-semantic-fail.rs:8:16
+   |
+LL | extern "C" {
+   | ---------- `extern` block begins here
+...
+LL |     type B<'a> where 'a: 'static;
+   |                ^^^^^^^^^^^^^^^^^ help: remove the `where` clause
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: `type`s inside `extern` blocks cannot have generic parameters
+  --> $DIR/foreign-ty-semantic-fail.rs:11:11
+   |
+LL | extern "C" {
+   | ---------- `extern` block begins here
+...
+LL |     type C<T: Ord> where T: 'static;
+   |           ^^^^^^^^ help: remove the generic parameters
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: `type`s inside `extern` blocks cannot have `where` clauses
+  --> $DIR/foreign-ty-semantic-fail.rs:11:20
+   |
+LL | extern "C" {
+   | ---------- `extern` block begins here
+...
+LL |     type C<T: Ord> where T: 'static;
+   |                    ^^^^^^^^^^^^^^^^ help: remove the `where` clause
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: incorrect `type` inside `extern` block
+  --> $DIR/foreign-ty-semantic-fail.rs:14:10
+   |
+LL | extern "C" {
+   | ---------- `extern` blocks define existing foreign types and types inside of them cannot have a body
+...
+LL |     type D = u8;
+   |          ^   -- the invalid body
+   |          |
+   |          cannot have a body
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/parser/foreign-ty-syntactic-pass.rs b/src/test/ui/parser/foreign-ty-syntactic-pass.rs
new file mode 100644
index 00000000000..a746de1f14f
--- /dev/null
+++ b/src/test/ui/parser/foreign-ty-syntactic-pass.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+extern "C" {
+    type A: Ord;
+    type A<'a> where 'a: 'static;
+    type A<T: Ord> where T: 'static;
+    type A = u8;
+    type A<'a: 'static, T: Ord + 'static>: Eq + PartialEq where T: 'static + Copy = Vec<u8>;
+}
diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs
index 9c321c4bd0d..fa9c7ababcf 100644
--- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs
+++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs
@@ -11,11 +11,11 @@ impl X {
     //~| ERROR associated types are not yet supported in inherent impls
     type Z: Ord;
     //~^ ERROR associated type in `impl` without body
-    //~| ERROR bounds on associated `type`s in `impl`s have no effect
+    //~| ERROR bounds on `type`s in `impl`s have no effect
     //~| ERROR associated types are not yet supported in inherent impls
     type W: Ord where Self: Eq;
     //~^ ERROR associated type in `impl` without body
-    //~| ERROR bounds on associated `type`s in `impl`s have no effect
+    //~| ERROR bounds on `type`s in `impl`s have no effect
     //~| ERROR associated types are not yet supported in inherent impls
     type W where Self: Eq;
     //~^ ERROR associated type in `impl` without body
diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
index 65e1981e3ac..541d9317c79 100644
--- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
+++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr
@@ -14,7 +14,7 @@ LL |     type Z: Ord;
    |                |
    |                help: provide a definition for the type: `= <type>;`
 
-error: bounds on associated `type`s in `impl`s have no effect
+error: bounds on `type`s in `impl`s have no effect
   --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:13
    |
 LL |     type Z: Ord;
@@ -28,7 +28,7 @@ LL |     type W: Ord where Self: Eq;
    |                               |
    |                               help: provide a definition for the type: `= <type>;`
 
-error: bounds on associated `type`s in `impl`s have no effect
+error: bounds on `type`s in `impl`s have no effect
   --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:13
    |
 LL |     type W: Ord where Self: Eq;
diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs
index 982a6be23ac..014c930ef82 100644
--- a/src/test/ui/parser/issue-19398.rs
+++ b/src/test/ui/parser/issue-19398.rs
@@ -1,5 +1,5 @@
 trait T {
-    //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration
+    //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
     extern "Rust" unsafe fn foo();
 }
 
diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr
index 2bd6ac3a4b3..b38b39f9bd9 100644
--- a/src/test/ui/parser/issue-19398.stderr
+++ b/src/test/ui/parser/issue-19398.stderr
@@ -1,11 +1,11 @@
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-19398.rs:1:10
    |
 LL |   trait T {
    |  __________^
 LL | |
 LL | |     extern "Rust" unsafe fn foo();
-   | |____^ missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, `const`, or `static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-21153.rs b/src/test/ui/parser/issue-21153.rs
index 46cd45f28b4..4fe05e6f041 100644
--- a/src/test/ui/parser/issue-21153.rs
+++ b/src/test/ui/parser/issue-21153.rs
@@ -1,4 +1,5 @@
-trait MyTrait<T>: Iterator { //~ ERROR missing `fn`, `type`, or `const`
+trait MyTrait<T>: Iterator {
+    //~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
     Item = T;
 }
 
diff --git a/src/test/ui/parser/issue-21153.stderr b/src/test/ui/parser/issue-21153.stderr
index 6e20a9ce3c4..e9824bd7290 100644
--- a/src/test/ui/parser/issue-21153.stderr
+++ b/src/test/ui/parser/issue-21153.stderr
@@ -1,10 +1,11 @@
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/issue-21153.rs:1:29
    |
 LL |   trait MyTrait<T>: Iterator {
    |  _____________________________^
+LL | |
 LL | |     Item = T;
-   | |____^ missing `fn`, `type`, or `const`
+   | |____^ missing `fn`, `type`, `const`, or `static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr
index 25c1efe35ae..d25828da0b9 100644
--- a/src/test/ui/parser/issue-32446.stderr
+++ b/src/test/ui/parser/issue-32446.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `...`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `static`, `type`, `unsafe`, `}`, or identifier, found `...`
   --> $DIR/issue-32446.rs:4:11
    |
 LL | trait T { ... }
-   |           ^^^ expected one of 11 possible tokens
+   |           ^^^ expected one of 12 possible tokens
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-41155.stderr b/src/test/ui/parser/issue-41155.stderr
index 327bc65818f..a91ef6c67e8 100644
--- a/src/test/ui/parser/issue-41155.stderr
+++ b/src/test/ui/parser/issue-41155.stderr
@@ -1,8 +1,8 @@
-error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, `unsafe`, or identifier, found `}`
+error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `static`, `type`, `unsafe`, or identifier, found `}`
   --> $DIR/issue-41155.rs:5:1
    |
 LL |     pub
-   |        - expected one of 9 possible tokens
+   |        - expected one of 10 possible tokens
 LL | }
    | ^ unexpected token
 
diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs
new file mode 100644
index 00000000000..613b3c98561
--- /dev/null
+++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs
@@ -0,0 +1,7 @@
+// Semantically, a free `const` item cannot omit its body.
+
+fn main() {}
+
+const A: u8; //~ ERROR free constant item without body
+const B; //~ ERROR free constant item without body
+//~^ ERROR missing type for `const` item
diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr
new file mode 100644
index 00000000000..4e97229fa1a
--- /dev/null
+++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr
@@ -0,0 +1,24 @@
+error: free constant item without body
+  --> $DIR/item-free-const-no-body-semantic-fail.rs:5:1
+   |
+LL | const A: u8;
+   | ^^^^^^^^^^^-
+   |            |
+   |            help: provide a definition for the constant: `= <expr>;`
+
+error: free constant item without body
+  --> $DIR/item-free-const-no-body-semantic-fail.rs:6:1
+   |
+LL | const B;
+   | ^^^^^^^-
+   |        |
+   |        help: provide a definition for the constant: `= <expr>;`
+
+error: missing type for `const` item
+  --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7
+   |
+LL | const B;
+   |       ^ help: provide a type for the item: `B: [type error]`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs b/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs
new file mode 100644
index 00000000000..acfdd3c363f
--- /dev/null
+++ b/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs
@@ -0,0 +1,8 @@
+// Syntactically, a free `const` item can omit its body.
+
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+const X: u8;
diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs
new file mode 100644
index 00000000000..780479e3d26
--- /dev/null
+++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs
@@ -0,0 +1,11 @@
+// Semantically, a free `static` item cannot omit its body.
+
+fn main() {}
+
+static A: u8; //~ ERROR free static item without body
+static B; //~ ERROR free static item without body
+//~^ ERROR missing type for `static` item
+
+static mut C: u8; //~ ERROR free static item without body
+static mut D; //~ ERROR free static item without body
+//~^ ERROR missing type for `static mut` item
diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr
new file mode 100644
index 00000000000..60b7bb34c69
--- /dev/null
+++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr
@@ -0,0 +1,46 @@
+error: free static item without body
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:5:1
+   |
+LL | static A: u8;
+   | ^^^^^^^^^^^^-
+   |             |
+   |             help: provide a definition for the static: `= <expr>;`
+
+error: free static item without body
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:6:1
+   |
+LL | static B;
+   | ^^^^^^^^-
+   |         |
+   |         help: provide a definition for the static: `= <expr>;`
+
+error: free static item without body
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:9:1
+   |
+LL | static mut C: u8;
+   | ^^^^^^^^^^^^^^^^-
+   |                 |
+   |                 help: provide a definition for the static: `= <expr>;`
+
+error: free static item without body
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:10:1
+   |
+LL | static mut D;
+   | ^^^^^^^^^^^^-
+   |             |
+   |             help: provide a definition for the static: `= <expr>;`
+
+error: missing type for `static` item
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8
+   |
+LL | static B;
+   |        ^ help: provide a type for the item: `B: [type error]`
+
+error: missing type for `static mut` item
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12
+   |
+LL | static mut D;
+   |            ^ help: provide a type for the item: `D: [type error]`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs b/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs
new file mode 100644
index 00000000000..db0039204d8
--- /dev/null
+++ b/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs
@@ -0,0 +1,8 @@
+// Syntactically, a free `const` item can omit its body.
+
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+static X: u8;
diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr
index 9d05e85bcc0..c76b096a1eb 100644
--- a/src/test/ui/parser/macro/trait-non-item-macros.stderr
+++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or identifier, found `2`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `static`, `type`, `unsafe`, or identifier, found `2`
   --> $DIR/trait-non-item-macros.rs:2:19
    |
 LL |     ($a:expr) => ($a)
-   |                   ^^ expected one of 10 possible tokens
+   |                   ^^ expected one of 11 possible tokens
 ...
 LL |     bah!(2);
    |     -------- in this macro invocation
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs
index 592215030f5..748db8983b5 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs
@@ -3,7 +3,7 @@ fn main() {}
 impl T for () { //~ ERROR cannot find trait `T` in this scope
 
 fn foo(&self) {}
-//~^ ERROR missing `fn`, `type`, or `const`
+//~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
 
 trait T {
     fn foo(&self);
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr
index 1ec54525105..240be39eace 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr
@@ -7,7 +7,7 @@ LL | impl T for () {
 LL |
    |                                                    ^
 
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/missing-close-brace-in-impl-trait.rs:5:17
    |
 LL |   fn foo(&self) {}
@@ -15,7 +15,7 @@ LL |   fn foo(&self) {}
 LL | |
 LL | |
 LL | | trait T {
-   | |_ missing `fn`, `type`, or `const`
+   | |_ missing `fn`, `type`, `const`, or `static`
 
 error[E0405]: cannot find trait `T` in this scope
   --> $DIR/missing-close-brace-in-impl-trait.rs:3:6
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs
index 077e3347194..4e8cc6489bc 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs
@@ -3,7 +3,7 @@ trait T {
     fn foo(&self);
 
 pub(crate) struct Bar<T>();
-//~^ ERROR missing `fn`, `type`, or `const`
+//~^ ERROR missing `fn`, `type`, `const`, or `static` for item declaration
 
 impl T for Bar<usize> {
 fn foo(&self) {}
diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
index 1bb153c461d..54afad5755b 100644
--- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
+++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr
@@ -7,11 +7,11 @@ LL | trait T {
 LL | fn main() {}
    |                                                                 ^
 
-error: missing `fn`, `type`, or `const` for associated-item declaration
+error: missing `fn`, `type`, `const`, or `static` for item declaration
   --> $DIR/missing-close-brace-in-trait.rs:5:11
    |
 LL | pub(crate) struct Bar<T>();
-   |           ^ missing `fn`, `type`, or `const`
+   |           ^ missing `fn`, `type`, `const`, or `static`
 
 error[E0601]: `main` function not found in crate `missing_close_brace_in_trait`
   --> $DIR/missing-close-brace-in-trait.rs:1:1
diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs
index 66fd5893af5..8b83d6ab2f8 100644
--- a/src/test/ui/parser/mut-patterns.rs
+++ b/src/test/ui/parser/mut-patterns.rs
@@ -9,6 +9,8 @@ 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 (x @ y) = 0; //~ ERROR `mut` must be attached to each individual binding
+
     let mut mut x = 0;
     //~^ ERROR `mut` on a binding may not be repeated
     //~| remove the additional `mut`s
diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr
index 5f4c349d7d6..9a6af7394bf 100644
--- a/src/test/ui/parser/mut-patterns.stderr
+++ b/src/test/ui/parser/mut-patterns.stderr
@@ -14,14 +14,22 @@ LL |     let mut (_, _) = (0, 0);
    |
    = note: `mut` may be followed by `variable` and `variable @ pattern`
 
+error: `mut` must be attached to each individual binding
+  --> $DIR/mut-patterns.rs:12:9
+   |
+LL |     let mut (x @ y) = 0;
+   |         ^^^^^^^^^^^ help: add `mut` to each binding: `(mut x @ mut y)`
+   |
+   = 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
+  --> $DIR/mut-patterns.rs:14: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
+  --> $DIR/mut-patterns.rs:19:9
    |
 LL |     let mut Foo { x: x } = Foo { x: 3 };
    |         ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }`
@@ -29,7 +37,7 @@ LL |     let mut Foo { x: x } = Foo { x: 3 };
    = 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
+  --> $DIR/mut-patterns.rs:23:9
    |
 LL |     let mut Foo { x } = Foo { x: 3 };
    |         ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }`
@@ -37,13 +45,13 @@ LL |     let mut Foo { x } = Foo { x: 3 };
    = 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
+  --> $DIR/mut-patterns.rs:28: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
+  --> $DIR/mut-patterns.rs:28:17
    |
 LL |     let mut mut yield(become, await) = r#yield(0, 0);
    |                 ^^^^^ expected identifier, found reserved keyword
@@ -54,7 +62,7 @@ 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
+  --> $DIR/mut-patterns.rs:28:23
    |
 LL |     let mut mut yield(become, await) = r#yield(0, 0);
    |                       ^^^^^^ expected identifier, found reserved keyword
@@ -65,7 +73,7 @@ LL |     let mut mut yield(r#become, await) = r#yield(0, 0);
    |                       ^^^^^^^^
 
 error: expected identifier, found keyword `await`
-  --> $DIR/mut-patterns.rs:26:31
+  --> $DIR/mut-patterns.rs:28:31
    |
 LL |     let mut mut yield(become, await) = r#yield(0, 0);
    |                               ^^^^^ expected identifier, found keyword
@@ -76,7 +84,7 @@ 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
+  --> $DIR/mut-patterns.rs:28: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)`
@@ -84,7 +92,7 @@ LL |     let mut mut yield(become, await) = r#yield(0, 0);
    = 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
+  --> $DIR/mut-patterns.rs:37: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 }))))`
@@ -92,7 +100,7 @@ LL |     let mut W(mut a, W(b, W(ref c, W(d, B { box f }))))
    = note: `mut` may be followed by `variable` and `variable @ pattern`
 
 error: expected identifier, found `x`
-  --> $DIR/mut-patterns.rs:42:21
+  --> $DIR/mut-patterns.rs:44:21
    |
 LL |             let mut $p = 0;
    |                     ^^ expected identifier
@@ -102,5 +110,5 @@ LL |     foo!(x);
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/test/ui/parser/removed-syntax-extern-const.rs b/src/test/ui/parser/removed-syntax-extern-const.rs
deleted file mode 100644
index 71c22e62f8e..00000000000
--- a/src/test/ui/parser/removed-syntax-extern-const.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-extern {
-    const i: isize;
-    //~^ ERROR extern items cannot be `const`
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/removed-syntax-extern-const.stderr b/src/test/ui/parser/removed-syntax-extern-const.stderr
deleted file mode 100644
index 2bccbd91452..00000000000
--- a/src/test/ui/parser/removed-syntax-extern-const.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: extern items cannot be `const`
-  --> $DIR/removed-syntax-extern-const.rs:2:5
-   |
-LL |     const i: isize;
-   |     ^^^^^ help: try using a static value: `static`
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/parser/removed-syntax-static-fn.rs b/src/test/ui/parser/removed-syntax-static-fn.rs
index 9e12222f3fd..cd643b874db 100644
--- a/src/test/ui/parser/removed-syntax-static-fn.rs
+++ b/src/test/ui/parser/removed-syntax-static-fn.rs
@@ -1,8 +1,10 @@
 struct S;
 
 impl S {
-    //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration
     static fn f() {}
+    //~^ ERROR expected identifier, found keyword `fn`
+    //~| ERROR expected one of `:`, `;`, or `=`
+    //~| ERROR missing type for `static` item
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/removed-syntax-static-fn.stderr b/src/test/ui/parser/removed-syntax-static-fn.stderr
index 5edf88026fb..dc5625bdade 100644
--- a/src/test/ui/parser/removed-syntax-static-fn.stderr
+++ b/src/test/ui/parser/removed-syntax-static-fn.stderr
@@ -1,11 +1,20 @@
-error: missing `fn`, `type`, or `const` for associated-item declaration
-  --> $DIR/removed-syntax-static-fn.rs:3:9
+error: expected identifier, found keyword `fn`
+  --> $DIR/removed-syntax-static-fn.rs:4:12
    |
-LL |   impl S {
-   |  _________^
-LL | |
-LL | |     static fn f() {}
-   | |____^ missing `fn`, `type`, or `const`
+LL |     static fn f() {}
+   |            ^^ expected identifier, found keyword
 
-error: aborting due to previous error
+error: expected one of `:`, `;`, or `=`, found `f`
+  --> $DIR/removed-syntax-static-fn.rs:4:15
+   |
+LL |     static fn f() {}
+   |               ^ expected one of `:`, `;`, or `=`
+
+error: missing type for `static` item
+  --> $DIR/removed-syntax-static-fn.rs:4:12
+   |
+LL |     static fn f() {}
+   |            ^^ help: provide a type for the item: `r#fn: <type>`
+
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/underscore_item_not_const.rs b/src/test/ui/parser/underscore_item_not_const.rs
index 7b0d128f06f..c01ac4752e0 100644
--- a/src/test/ui/parser/underscore_item_not_const.rs
+++ b/src/test/ui/parser/underscore_item_not_const.rs
@@ -1,18 +1,4 @@
-// Test that various non-const items and associated consts do not permit `_` as a name.
-
-// Associated `const`s:
-
-pub trait A {
-    const _: () = (); //~ ERROR expected identifier, found reserved identifier `_`
-}
-impl A for () {
-    const _: () = (); //~ ERROR expected identifier, found reserved identifier `_`
-}
-impl dyn A {
-    const _: () = (); //~ ERROR expected identifier, found reserved identifier `_`
-}
-
-// Other kinds of items:
+// Test that various non-const items do not syntactically permit `_` as a name.
 
 static _: () = (); //~ ERROR expected identifier, found reserved identifier `_`
 struct _(); //~ ERROR expected identifier, found reserved identifier `_`
diff --git a/src/test/ui/parser/underscore_item_not_const.stderr b/src/test/ui/parser/underscore_item_not_const.stderr
index ebf1ff9ff1e..0bc7642dd19 100644
--- a/src/test/ui/parser/underscore_item_not_const.stderr
+++ b/src/test/ui/parser/underscore_item_not_const.stderr
@@ -1,92 +1,74 @@
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:6:11
-   |
-LL |     const _: () = ();
-   |           ^ expected identifier, found reserved identifier
-
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:9:11
-   |
-LL |     const _: () = ();
-   |           ^ expected identifier, found reserved identifier
-
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:12:11
-   |
-LL |     const _: () = ();
-   |           ^ expected identifier, found reserved identifier
-
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:17:8
+  --> $DIR/underscore_item_not_const.rs:3:8
    |
 LL | static _: () = ();
    |        ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:18:8
+  --> $DIR/underscore_item_not_const.rs:4:8
    |
 LL | struct _();
    |        ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:19:6
+  --> $DIR/underscore_item_not_const.rs:5:6
    |
 LL | enum _ {}
    |      ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:20:4
+  --> $DIR/underscore_item_not_const.rs:6:4
    |
 LL | fn _() {}
    |    ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:21:5
+  --> $DIR/underscore_item_not_const.rs:7:5
    |
 LL | mod _ {}
    |     ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:22:6
+  --> $DIR/underscore_item_not_const.rs:8:6
    |
 LL | type _ = ();
    |      ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:23:5
+  --> $DIR/underscore_item_not_const.rs:9:5
    |
 LL | use _;
    |     ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:24:5
+  --> $DIR/underscore_item_not_const.rs:10:5
    |
 LL | use _ as g;
    |     ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:25:7
+  --> $DIR/underscore_item_not_const.rs:11:7
    |
 LL | trait _ {}
    |       ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:26:7
+  --> $DIR/underscore_item_not_const.rs:12:7
    |
 LL | trait _ = Copy;
    |       ^ expected identifier, found reserved identifier
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:27:14
+  --> $DIR/underscore_item_not_const.rs:13:14
    |
 LL | macro_rules! _ { () => {} }
    |              ^ expected identifier, found reserved identifier
 
 error: expected one of `!` or `::`, found reserved identifier `_`
-  --> $DIR/underscore_item_not_const.rs:28:7
+  --> $DIR/underscore_item_not_const.rs:14:7
    |
 LL | union _ { f: u8 }
    |       ^ expected one of `!` or `::`
 
-error: aborting due to 15 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr
index bb3e61017d4..95662444640 100644
--- a/src/test/ui/pattern/pattern-tyvar-2.stderr
+++ b/src/test/ui/pattern/pattern-tyvar-2.stderr
@@ -5,8 +5,6 @@ LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3;
    |                                                                     - ^ - {integer}
    |                                                                     |
    |                                                                     std::vec::Vec<isize>
-   |
-   = note: an implementation of `std::ops::Mul` might be missing for `std::vec::Vec<isize>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs b/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs
new file mode 100644
index 00000000000..c9f0664c3a3
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs
@@ -0,0 +1,17 @@
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro_hygiene)]
+#![feature(proc_macro_quote)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn dollar_ident(input: TokenStream) -> TokenStream {
+    let black_hole = input.into_iter().next().unwrap();
+    quote! {
+        $black_hole!($$var);
+    }
+}
diff --git a/src/test/ui/proc-macro/generate-dollar-ident.rs b/src/test/ui/proc-macro/generate-dollar-ident.rs
new file mode 100644
index 00000000000..b838be9fb9f
--- /dev/null
+++ b/src/test/ui/proc-macro/generate-dollar-ident.rs
@@ -0,0 +1,18 @@
+// Proc macros can generate token sequence `$ IDENT`
+// without it being recognized as an unknown macro variable.
+
+// check-pass
+// aux-build:generate-dollar-ident.rs
+
+extern crate generate_dollar_ident;
+use generate_dollar_ident::*;
+
+macro_rules! black_hole {
+    ($($tt:tt)*) => {};
+}
+
+black_hole!($var);
+
+dollar_ident!(black_hole);
+
+fn main() {}
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 084f070989b..39874a6c680 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -560,8 +560,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool`
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
-   |
-   = note: an implementation of `std::ops::Neg` might be missing for `bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
   --> $DIR/disallowed-positions.rs:46:8
@@ -748,8 +746,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool`
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
-   |
-   = note: an implementation of `std::ops::Neg` might be missing for `bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
   --> $DIR/disallowed-positions.rs:110:11
@@ -927,8 +923,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool`
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
-   |
-   = note: an implementation of `std::ops::Neg` might be missing for `bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
   --> $DIR/disallowed-positions.rs:183:5
diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr
index 8a32561bd01..8caa5bea4ac 100644
--- a/src/test/ui/span/issue-39018.stderr
+++ b/src/test/ui/span/issue-39018.stderr
@@ -136,8 +136,6 @@ LL |     let _ = &c + &d;
    |             -- ^ -- &&str
    |             |
    |             &&str
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `&&str`
 
 error[E0369]: cannot add `&str` to `&&str`
   --> $DIR/issue-39018.rs:35:16
@@ -146,8 +144,6 @@ LL |     let _ = &c + d;
    |             -- ^ - &str
    |             |
    |             &&str
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `&&str`
 
 error[E0369]: cannot add `&&str` to `&str`
   --> $DIR/issue-39018.rs:36:15
diff --git a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
index 8d7ba36c665..29216f36f5f 100644
--- a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
+++ b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr
@@ -5,8 +5,6 @@ LL |     a * b
    |     - ^ - f64
    |     |
    |     &T
-   |
-   = note: an implementation of `std::ops::Mul` might be missing for `&T`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unop-neg-bool.stderr b/src/test/ui/unop-neg-bool.stderr
index 18273013749..9913747b88e 100644
--- a/src/test/ui/unop-neg-bool.stderr
+++ b/src/test/ui/unop-neg-bool.stderr
@@ -3,8 +3,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool`
    |
 LL |     -true;
    |     ^^^^^ cannot apply unary operator `-`
-   |
-   = note: an implementation of `std::ops::Neg` might be missing for `bool`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/vec/vec-res-add.stderr b/src/test/ui/vec/vec-res-add.stderr
index 1cc12a222e5..2d41583268c 100644
--- a/src/test/ui/vec/vec-res-add.stderr
+++ b/src/test/ui/vec/vec-res-add.stderr
@@ -5,8 +5,6 @@ LL |     let k = i + j;
    |             - ^ - std::vec::Vec<R>
    |             |
    |             std::vec::Vec<R>
-   |
-   = note: an implementation of `std::ops::Add` might be missing for `std::vec::Vec<R>`
 
 error: aborting due to previous error