diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index 426659fd92452..e0db8606bc203 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 99de4b88fd3c4..56d789b7a6a8b 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 2f0495b8b5a48..d3fcb589fd0ff 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 0b21de4d78b41..d4de2c937583d 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 75938470b6fca..2f712964a84cb 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 5cf233e222e7c..2e4cbd708a9f6 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 02a0bc00c1169..b6837c0703aed 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 af22e46eb6afa..0882151063098 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/placeholders.rs b/src/librustc_expand/placeholders.rs
index 6bcb8f45f001e..c96b394c7b5e2 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 659323d1c2555..df50fc5d3ed24 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 93fca43d67c1f..207defa96a3e6 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 480df99a01eed..7870b9da4cb70 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_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 500aaaf43b92a..da72da043650c 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
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index d6ea737385cdd..1f622b80e8e2e 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 fe80dec513cfe..60cba55512193 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 bcf558d1563ed..68559c0446aed 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 01e3e3f368529..6a3abf4fbf5f3 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 401e172275113..d244370ae2c11 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 d3c4d6d5723b9..3c68124ad40f7 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/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 72430fa9c17e4..a73142406153a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1605,46 +1605,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,
@@ -2536,11 +2496,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 { .. }`.
@@ -2640,28 +2600,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 e0180d451936f..1fa6cce2c6284 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 73e731397c329..448ed0ba3de57 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/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs
index 60633c6930cdf..2ed682cea9503 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 072e61f6a3cd1..119e30a3e0f57 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/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr
index 258202b6903d3..7f67adbdb19c7 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/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr
index 6221b90b31dd7..f4ca3c46ea28a 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-60075.stderr b/src/test/ui/issues/issue-60075.stderr
index b2beb73503bb0..bab50a53b1ae4 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/macros/issue-54441.rs b/src/test/ui/macros/issue-54441.rs
index a70163df1cb93..5570f081b157d 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 761e7aec7235a..5857aacb43176 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/parser/assoc-const-underscore-semantic-fail.rs b/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs
new file mode 100644
index 0000000000000..d37ce06c555bf
--- /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 0000000000000..538bf0ec100dc
--- /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 0000000000000..60da408c81153
--- /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 0000000000000..cf3debd77cbfd
--- /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 0000000000000..d02e2855c7e62
--- /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 0000000000000..8f042767e5503
--- /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 0000000000000..bb1e5c4be2e9c
--- /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 65ecb1ebbe919..50952eef22f5c 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 ede9e47151863..07b051ece2b5d 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 1d271fa64b0ec..f6e7f7e6abe8f 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 36a3a1ed5a0cc..398ba65c9e1d8 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 c37ddd69ce53c..dc47f7410730c 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 d2d5e3c46874a..8d55eefc8d0ec 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 0000000000000..d28b64142826c
--- /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 0000000000000..f364f11bb038d
--- /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 0000000000000..a78f8b1623a80
--- /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 0000000000000..9cf58fa95fb2d
--- /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 0000000000000..9abdf33df9c46
--- /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 0000000000000..5942e3a94497b
--- /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 0000000000000..2c805e8a0b700
--- /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 0000000000000..96b15232b10d0
--- /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 0000000000000..588e4966aaeb5
--- /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 0000000000000..a746de1f14f4d
--- /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 9c321c4bd0d74..fa9c7ababcf9e 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 65e1981e3ac78..541d9317c79d0 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 982a6be23ac5f..014c930ef8205 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 2bd6ac3a4b3a4..b38b39f9bd99f 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 46cd45f28b43d..4fe05e6f04155 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 6e20a9ce3c432..e9824bd729081 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 25c1efe35ae11..d25828da0b979 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 327bc65818fa9..a91ef6c67e89e 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 0000000000000..613b3c9856171
--- /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 0000000000000..4e97229fa1a41
--- /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 0000000000000..acfdd3c363f25
--- /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 0000000000000..780479e3d26ac
--- /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 0000000000000..60b7bb34c698b
--- /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 0000000000000..db0039204d870
--- /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 9d05e85bcc00e..c76b096a1ebf4 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 592215030f552..748db8983b595 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 1ec54525105f6..240be39eacef4 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 077e334719427..4e8cc6489bc64 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 1bb153c461d90..54afad5755b15 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/removed-syntax-extern-const.rs b/src/test/ui/parser/removed-syntax-extern-const.rs
deleted file mode 100644
index 71c22e62f8e4b..0000000000000
--- 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 2bccbd91452f6..0000000000000
--- 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 9e12222f3fd8b..cd643b874dbda 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 5edf88026fbec..dc5625bdadea3 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 7b0d128f06f8a..c01ac4752e075 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 ebf1ff9ff1ea3..0bc7642dd1964 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