]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_parse/parser/item.rs
parse extern consts
[rust.git] / src / librustc_parse / parser / item.rs
index 8ba957c6b3b52a149233bd4d0fd2df9f22b1a17e..5fcd72090ec87f88a37459aeff2414b0dcda160d 100644 (file)
@@ -8,10 +8,9 @@
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey};
 use rustc_span::source_map::{self, Span};
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::BytePos;
-use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
+use syntax::ast::{self, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
 use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind};
-use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, StrLit, Unsafe};
+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};
@@ -22,7 +21,7 @@
 use log::debug;
 use std::mem;
 
-pub(super) type ItemInfo = (Ident, ItemKind, Option<Vec<Attribute>>);
+pub(super) type ItemInfo = (Ident, ItemKind);
 
 impl<'a> Parser<'a> {
     pub fn parse_item(&mut self) -> PResult<'a, Option<P<Item>>> {
@@ -83,72 +82,67 @@ fn parse_item_implementation(
         });
 
         let lo = self.token.span;
-
         let vis = self.parse_visibility(FollowedByType::No)?;
 
-        if self.eat_keyword(kw::Use) {
-            // USE ITEM
-            let item_ = ItemKind::Use(P(self.parse_use_tree()?));
-            self.expect_semi()?;
+        if let Some((ident, kind)) = self.parse_item_kind(&mut attrs, macros_allowed, lo, &vis)? {
+            return Ok(Some(P(self.mk_item(lo, ident, kind, vis, attrs))));
+        }
 
-            let span = lo.to(self.prev_span);
-            let item = self.mk_item(span, Ident::invalid(), item_, vis, attrs);
-            return Ok(Some(item));
+        // FAILURE TO PARSE ITEM
+        if let VisibilityKind::Inherited = vis.node {
+        } else {
+            let vs = pprust::vis_to_string(&vis);
+            let vs = vs.trim_end();
+            self.struct_span_err(vis.span, &format!("unmatched visibility `{}`", vs))
+                .span_label(vis.span, "the unmatched visibility")
+                .help(&format!("you likely meant to define an item, e.g., `{} fn foo() {{}}`", vs))
+                .emit();
         }
 
-        if self.is_fn_front_matter() {
-            // FUNCTION ITEM
-            let (ident, sig, generics, body) =
-                self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
-            let kind = ItemKind::Fn(sig, generics, body);
-            return self.mk_item_with_info(attrs, lo, vis, (ident, kind, None));
+        if !attributes_allowed {
+            self.recover_attrs_no_item(&attrs)?;
         }
+        Ok(None)
+    }
 
-        if self.eat_keyword(kw::Extern) {
+    /// Parses one of the items allowed by the flags.
+    fn parse_item_kind(
+        &mut self,
+        attrs: &mut Vec<Attribute>,
+        macros_allowed: bool,
+        lo: Span,
+        vis: &Visibility,
+    ) -> PResult<'a, Option<ItemInfo>> {
+        let info = if self.eat_keyword(kw::Use) {
+            // USE ITEM
+            let tree = self.parse_use_tree()?;
+            self.expect_semi()?;
+            (Ident::invalid(), ItemKind::Use(P(tree)))
+        } else if self.check_fn_front_matter() {
+            // FUNCTION ITEM
+            let (ident, sig, generics, body) = self.parse_fn(&mut false, attrs, |_| true)?;
+            (ident, ItemKind::Fn(sig, generics, body))
+        } else if self.eat_keyword(kw::Extern) {
             if self.eat_keyword(kw::Crate) {
                 // EXTERN CRATE
-                return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
+                self.parse_item_extern_crate()?
+            } else {
+                // EXTERN BLOCK
+                self.parse_item_foreign_mod(attrs)?
             }
-            // EXTERN BLOCK
-            let abi = self.parse_abi();
-            return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?));
-        }
-
-        if self.is_static_global() {
+        } else if self.is_static_global() {
             // STATIC ITEM
-            self.bump();
+            self.bump(); // `static`
             let m = self.parse_mutability();
-            let info = self.parse_item_const(Some(m))?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
-
-        if let Const::Yes(const_span) = self.parse_constness() {
+            self.parse_item_const(Some(m))?
+        } else if let Const::Yes(const_span) = self.parse_constness() {
             // CONST ITEM
-            if self.eat_keyword(kw::Mut) {
-                let prev_span = self.prev_span;
-                self.struct_span_err(prev_span, "const globals cannot be mutable")
-                    .span_label(prev_span, "cannot be mutable")
-                    .span_suggestion(
-                        const_span,
-                        "you might want to declare a static instead",
-                        "static".to_owned(),
-                        Applicability::MaybeIncorrect,
-                    )
-                    .emit();
-            }
-
-            let info = self.parse_item_const(None)?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
-
-        if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) {
-            // UNSAFE TRAIT ITEM
-            let unsafety = self.parse_unsafety();
-            let info = self.parse_item_trait(lo, unsafety)?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
-
-        if self.check_keyword(kw::Impl)
+            self.recover_const_mut(const_span);
+            self.parse_item_const(None)?
+        } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() {
+            // TRAIT ITEM
+            self.parse_item_trait(attrs, lo)?
+        } else if self.check_keyword(kw::Impl)
             || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Impl])
             || self.check_keyword(kw::Default) && self.is_keyword_ahead(1, &[kw::Impl, kw::Unsafe])
         {
@@ -156,273 +150,189 @@ fn parse_item_implementation(
             let defaultness = self.parse_defaultness();
             let unsafety = self.parse_unsafety();
             self.expect_keyword(kw::Impl)?;
-            let info = self.parse_item_impl(unsafety, defaultness)?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
-
-        if self.eat_keyword(kw::Mod) {
+            self.parse_item_impl(attrs, unsafety, defaultness)?
+        } else if self.eat_keyword(kw::Mod) {
             // MODULE ITEM
-            let info = self.parse_item_mod(&attrs[..])?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
-
-        if self.eat_keyword(kw::Type) {
+            self.parse_item_mod(attrs)?
+        } else if self.eat_keyword(kw::Type) {
             // TYPE ITEM
             let (ident, ty, generics) = self.parse_type_alias()?;
-            let kind = ItemKind::TyAlias(ty, generics);
-            return self.mk_item_with_info(attrs, lo, vis, (ident, kind, None));
-        }
-
-        if self.eat_keyword(kw::Enum) {
+            (ident, ItemKind::TyAlias(ty, generics))
+        } else if self.eat_keyword(kw::Enum) {
             // ENUM ITEM
-            let info = self.parse_item_enum()?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
-
-        if self.check_keyword(kw::Trait)
-            || (self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait]))
-        {
-            // TRAIT ITEM
-            let info = self.parse_item_trait(lo, Unsafe::No)?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
-
-        if self.eat_keyword(kw::Struct) {
+            self.parse_item_enum()?
+        } else if self.eat_keyword(kw::Struct) {
             // STRUCT ITEM
-            let info = self.parse_item_struct()?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
-
-        if self.is_union_item() {
+            self.parse_item_struct()?
+        } else if self.is_kw_followed_by_ident(kw::Union) {
             // UNION ITEM
-            self.bump();
-            let info = self.parse_item_union()?;
-            return self.mk_item_with_info(attrs, lo, vis, info);
-        }
+            self.bump(); // `union`
+            self.parse_item_union()?
+        } else if self.eat_keyword(kw::Macro) {
+            // MACROS 2.0 ITEM
+            self.parse_item_decl_macro(lo)?
+        } else if self.is_macro_rules_item() {
+            // MACRO_RULES ITEM
+            self.parse_item_macro_rules(vis)?
+        } else if vis.node.is_pub() && self.isnt_macro_invocation() {
+            self.recover_missing_kw_before_item()?;
+            return Ok(None);
+        } else if macros_allowed && self.token.is_path_start() {
+            // MACRO INVOCATION ITEM
+            (Ident::invalid(), ItemKind::Mac(self.parse_item_macro(vis)?))
+        } else {
+            return Ok(None);
+        };
+        Ok(Some(info))
+    }
 
-        if let Some(macro_def) = self.eat_macro_def(&attrs, &vis, lo)? {
-            return Ok(Some(macro_def));
-        }
+    /// When parsing a statement, would the start of a path be an item?
+    pub(super) fn is_path_start_item(&mut self) -> bool {
+        self.is_crate_vis() // no: `crate::b`, yes: `crate $item`
+        || self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
+        || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
+        || self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
+        || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac`
+    }
+
+    /// Are we sure this could not possibly be a macro invocation?
+    fn isnt_macro_invocation(&mut self) -> bool {
+        self.check_ident() && self.look_ahead(1, |t| *t != token::Not && *t != token::ModSep)
+    }
 
-        // Verify whether we have encountered a struct or method definition where the user forgot to
-        // add the `struct` or `fn` keyword after writing `pub`: `pub S {}`
-        if vis.node.is_pub() && self.check_ident() && self.look_ahead(1, |t| *t != token::Not) {
-            // Space between `pub` keyword and the identifier
-            //
-            //     pub   S {}
-            //        ^^^ `sp` points here
-            let sp = self.prev_span.between(self.token.span);
-            let full_sp = self.prev_span.to(self.token.span);
-            let ident_sp = self.token.span;
-            if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
-                // possible public struct definition where `struct` was forgotten
-                let ident = self.parse_ident().unwrap();
-                let msg = format!("add `struct` here to parse `{}` as a public struct", ident);
-                let mut err = self.struct_span_err(sp, "missing `struct` for struct definition");
+    /// Recover on encountering a struct or method definition where the user
+    /// forgot to add the `struct` or `fn` keyword after writing `pub`: `pub S {}`.
+    fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
+        // Space between `pub` keyword and the identifier
+        //
+        //     pub   S {}
+        //        ^^^ `sp` points here
+        let sp = self.prev_span.between(self.token.span);
+        let full_sp = self.prev_span.to(self.token.span);
+        let ident_sp = self.token.span;
+        if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
+            // possible public struct definition where `struct` was forgotten
+            let ident = self.parse_ident().unwrap();
+            let msg = format!("add `struct` here to parse `{}` as a public struct", ident);
+            let mut err = self.struct_span_err(sp, "missing `struct` for struct definition");
+            err.span_suggestion_short(
+                sp,
+                &msg,
+                " struct ".into(),
+                Applicability::MaybeIncorrect, // speculative
+            );
+            return Err(err);
+        } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
+            let ident = self.parse_ident().unwrap();
+            self.bump(); // `(`
+            let kw_name = self.recover_first_param();
+            self.consume_block(token::Paren, ConsumeClosingDelim::Yes);
+            let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
+                self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
+                self.bump(); // `{`
+                ("fn", kw_name, false)
+            } else if self.check(&token::OpenDelim(token::Brace)) {
+                self.bump(); // `{`
+                ("fn", kw_name, false)
+            } else if self.check(&token::Colon) {
+                let kw = "struct";
+                (kw, kw, false)
+            } else {
+                ("fn` or `struct", "function or struct", true)
+            };
+
+            let msg = format!("missing `{}` for {} definition", kw, kw_name);
+            let mut err = self.struct_span_err(sp, &msg);
+            if !ambiguous {
+                self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                let suggestion =
+                    format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name);
                 err.span_suggestion_short(
                     sp,
-                    &msg,
-                    " struct ".into(),
-                    Applicability::MaybeIncorrect, // speculative
+                    &suggestion,
+                    format!(" {} ", kw),
+                    Applicability::MachineApplicable,
                 );
-                return Err(err);
-            } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
-                let ident = self.parse_ident().unwrap();
-                self.bump(); // `(`
-                let kw_name = self.recover_first_param();
-                self.consume_block(token::Paren, ConsumeClosingDelim::Yes);
-                let (kw, kw_name, ambiguous) = if self.check(&token::RArrow) {
-                    self.eat_to_tokens(&[&token::OpenDelim(token::Brace)]);
-                    self.bump(); // `{`
-                    ("fn", kw_name, false)
-                } else if self.check(&token::OpenDelim(token::Brace)) {
-                    self.bump(); // `{`
-                    ("fn", kw_name, false)
-                } else if self.check(&token::Colon) {
-                    let kw = "struct";
-                    (kw, kw, false)
-                } else {
-                    ("fn` or `struct", "function or struct", true)
-                };
-
-                let msg = format!("missing `{}` for {} definition", kw, kw_name);
-                let mut err = self.struct_span_err(sp, &msg);
-                if !ambiguous {
-                    self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
-                    let suggestion =
-                        format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name);
-                    err.span_suggestion_short(
-                        sp,
-                        &suggestion,
-                        format!(" {} ", kw),
-                        Applicability::MachineApplicable,
+            } else {
+                if let Ok(snippet) = self.span_to_snippet(ident_sp) {
+                    err.span_suggestion(
+                        full_sp,
+                        "if you meant to call a macro, try",
+                        format!("{}!", snippet),
+                        // this is the `ambiguous` conditional branch
+                        Applicability::MaybeIncorrect,
                     );
                 } else {
-                    if let Ok(snippet) = self.span_to_snippet(ident_sp) {
-                        err.span_suggestion(
-                            full_sp,
-                            "if you meant to call a macro, try",
-                            format!("{}!", snippet),
-                            // this is the `ambiguous` conditional branch
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        err.help(
-                            "if you meant to call a macro, remove the `pub` \
+                    err.help(
+                        "if you meant to call a macro, remove the `pub` \
                                   and add a trailing `!` after the identifier",
-                        );
-                    }
-                }
-                return Err(err);
-            } else if self.look_ahead(1, |t| *t == token::Lt) {
-                let ident = self.parse_ident().unwrap();
-                self.eat_to_tokens(&[&token::Gt]);
-                self.bump(); // `>`
-                let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
-                    ("fn", self.recover_first_param(), false)
-                } else if self.check(&token::OpenDelim(token::Brace)) {
-                    ("struct", "struct", false)
-                } else {
-                    ("fn` or `struct", "function or struct", true)
-                };
-                let msg = format!("missing `{}` for {} definition", kw, kw_name);
-                let mut err = self.struct_span_err(sp, &msg);
-                if !ambiguous {
-                    err.span_suggestion_short(
-                        sp,
-                        &format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name),
-                        format!(" {} ", kw),
-                        Applicability::MachineApplicable,
                     );
                 }
-                return Err(err);
             }
-        }
-        self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, vis)
-    }
-
-    pub(super) fn mk_item_with_info(
-        &self,
-        attrs: Vec<Attribute>,
-        lo: Span,
-        vis: Visibility,
-        info: ItemInfo,
-    ) -> PResult<'a, Option<P<Item>>> {
-        let (ident, item, extra_attrs) = info;
-        let span = lo.to(self.prev_span);
-        let attrs = Self::maybe_append(attrs, extra_attrs);
-        Ok(Some(self.mk_item(span, ident, item, vis, attrs)))
-    }
-
-    fn maybe_append<T>(mut lhs: Vec<T>, mut rhs: Option<Vec<T>>) -> Vec<T> {
-        if let Some(ref mut rhs) = rhs {
-            lhs.append(rhs);
-        }
-        lhs
-    }
-
-    /// This is the fall-through for parsing items.
-    fn parse_macro_use_or_failure(
-        &mut self,
-        attrs: Vec<Attribute>,
-        macros_allowed: bool,
-        attributes_allowed: bool,
-        lo: Span,
-        visibility: Visibility,
-    ) -> PResult<'a, Option<P<Item>>> {
-        if macros_allowed
-            && self.token.is_path_start()
-            && !(self.is_async_fn() && self.token.span.rust_2015())
-        {
-            // MACRO INVOCATION ITEM
-
-            let prev_span = self.prev_span;
-            self.complain_if_pub_macro(&visibility.node, prev_span);
-
-            // Item macro
-            let path = self.parse_path(PathStyle::Mod)?;
-            self.expect(&token::Not)?;
-            let args = self.parse_mac_args()?;
-            if args.need_semicolon() && !self.eat(&token::Semi) {
-                self.report_invalid_macro_expansion_item();
+            return Err(err);
+        } else if self.look_ahead(1, |t| *t == token::Lt) {
+            let ident = self.parse_ident().unwrap();
+            self.eat_to_tokens(&[&token::Gt]);
+            self.bump(); // `>`
+            let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) {
+                ("fn", self.recover_first_param(), false)
+            } else if self.check(&token::OpenDelim(token::Brace)) {
+                ("struct", "struct", false)
+            } else {
+                ("fn` or `struct", "function or struct", true)
+            };
+            let msg = format!("missing `{}` for {} definition", kw, kw_name);
+            let mut err = self.struct_span_err(sp, &msg);
+            if !ambiguous {
+                err.span_suggestion_short(
+                    sp,
+                    &format!("add `{}` here to parse `{}` as a public {}", kw, ident, kw_name),
+                    format!(" {} ", kw),
+                    Applicability::MachineApplicable,
+                );
             }
-
-            let hi = self.prev_span;
-            let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription };
-            let item =
-                self.mk_item(lo.to(hi), Ident::invalid(), ItemKind::Mac(mac), visibility, attrs);
-            return Ok(Some(item));
-        }
-
-        // FAILURE TO PARSE ITEM
-        match visibility.node {
-            VisibilityKind::Inherited => {}
-            _ => return Err(self.struct_span_err(self.prev_span, "unmatched visibility `pub`")),
+            return Err(err);
+        } else {
+            Ok(())
         }
+    }
 
-        if !attributes_allowed && !attrs.is_empty() {
-            self.expected_item_err(&attrs)?;
-        }
-        Ok(None)
+    /// Parses an item macro, e.g., `item!();`.
+    fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, Mac> {
+        let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
+        self.expect(&token::Not)?; // `!`
+        let args = self.parse_mac_args()?; // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`.
+        self.eat_semi_for_macro_if_needed(&args);
+        self.complain_if_pub_macro(vis, false);
+        Ok(Mac { path, args, prior_type_ascription: self.last_type_ascription })
     }
 
-    /// Emits an expected-item-after-attributes error.
-    fn expected_item_err(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
-        let message = match attrs.last() {
-            Some(&Attribute { kind: AttrKind::DocComment(_), .. }) => {
-                "expected item after doc comment"
-            }
-            _ => "expected item after attributes",
+    /// Recover if we parsed attributes and expected an item but there was none.
+    fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
+        let (start, end) = match attrs {
+            [] => return Ok(()),
+            [x0] => (x0, x0),
+            [x0, .., xn] => (x0, xn),
         };
-
-        let mut err = self.struct_span_err(self.prev_span, message);
-        if attrs.last().unwrap().is_doc_comment() {
-            err.span_label(self.prev_span, "this doc comment doesn't document anything");
+        let msg = if end.is_doc_comment() {
+            "expected item after doc comment"
+        } else {
+            "expected item after attributes"
+        };
+        let mut err = self.struct_span_err(end.span, msg);
+        if end.is_doc_comment() {
+            err.span_label(end.span, "this doc comment doesn't document anything");
+        }
+        if let [.., penultimate, _] = attrs {
+            err.span_label(start.span.to(penultimate.span), "other attributes here");
         }
         Err(err)
     }
 
-    pub(super) fn is_async_fn(&self) -> bool {
+    fn is_async_fn(&self) -> bool {
         self.token.is_keyword(kw::Async) && self.is_keyword_ahead(1, &[kw::Fn])
     }
 
-    /// Parses a macro invocation inside a `trait`, `impl` or `extern` block.
-    fn parse_assoc_macro_invoc(
-        &mut self,
-        item_kind: &str,
-        vis: Option<&Visibility>,
-        at_end: &mut bool,
-    ) -> PResult<'a, Option<Mac>> {
-        if self.token.is_path_start() && !(self.is_async_fn() && self.token.span.rust_2015()) {
-            let prev_span = self.prev_span;
-            let path = self.parse_path(PathStyle::Mod)?;
-
-            if path.segments.len() == 1 {
-                if !self.eat(&token::Not) {
-                    return Err(self.missing_assoc_item_kind_err(item_kind, prev_span));
-                }
-            } else {
-                self.expect(&token::Not)?;
-            }
-
-            if let Some(vis) = vis {
-                self.complain_if_pub_macro(&vis.node, prev_span);
-            }
-
-            *at_end = true;
-
-            // eat a matched-delimiter token tree:
-            let args = self.parse_mac_args()?;
-            if args.need_semicolon() {
-                self.expect_semi()?;
-            }
-
-            Ok(Some(Mac { path, args, prior_type_ascription: self.last_type_ascription }))
-        } else {
-            Ok(None)
-        }
-    }
-
     fn missing_assoc_item_kind_err(
         &self,
         item_type: &str,
@@ -443,7 +353,7 @@ fn missing_assoc_item_kind_err(
         //   |        ^ missing `fn`, `type`, or `const`
         //     pub  path(
         //        ^^ `sp` below will point to this
-        let sp = prev_span.between(self.prev_span);
+        let sp = prev_span.between(self.token.span);
         let mut err = self
             .struct_span_err(sp, &format!("{} for {}-item declaration", expected_kinds, item_type));
         err.span_label(sp, expected_kinds);
@@ -452,16 +362,21 @@ fn missing_assoc_item_kind_err(
 
     /// Parses an implementation item, `impl` keyword is already parsed.
     ///
-    ///    impl<'a, T> TYPE { /* impl items */ }
-    ///    impl<'a, T> TRAIT for TYPE { /* impl items */ }
-    ///    impl<'a, T> !TRAIT for TYPE { /* impl items */ }
-    ///    impl<'a, T> const TRAIT for TYPE { /* impl items */ }
+    /// ```
+    /// impl<'a, T> TYPE { /* impl items */ }
+    /// impl<'a, T> TRAIT for TYPE { /* impl items */ }
+    /// impl<'a, T> !TRAIT for TYPE { /* impl items */ }
+    /// impl<'a, T> const TRAIT for TYPE { /* impl items */ }
+    /// ```
     ///
     /// We actually parse slightly more relaxed grammar for better error reporting and recovery.
-    ///   `impl` GENERICS `const`? `!`? TYPE `for`? (TYPE | `..`) (`where` PREDICATES)? `{` BODY `}`
-    ///   `impl` GENERICS `const`? `!`? TYPE (`where` PREDICATES)? `{` BODY `}`
+    /// ```
+    /// "impl" GENERICS "const"? "!"? TYPE "for"? (TYPE | "..") ("where" PREDICATES)? "{" BODY "}"
+    /// "impl" GENERICS "const"? "!"? TYPE ("where" PREDICATES)? "{" BODY "}"
+    /// ```
     fn parse_item_impl(
         &mut self,
+        attrs: &mut Vec<Attribute>,
         unsafety: Unsafe,
         defaultness: Defaultness,
     ) -> PResult<'a, ItemInfo> {
@@ -516,7 +431,7 @@ fn parse_item_impl(
 
         generics.where_clause = self.parse_where_clause()?;
 
-        let (impl_items, attrs) = self.parse_impl_body()?;
+        let impl_items = self.parse_item_list(attrs, |p, at_end| p.parse_impl_item(at_end))?;
 
         let item_kind = match ty_second {
             Some(ty_second) => {
@@ -569,18 +484,25 @@ fn parse_item_impl(
             }
         };
 
-        Ok((Ident::invalid(), item_kind, Some(attrs)))
+        Ok((Ident::invalid(), item_kind))
     }
 
-    fn parse_impl_body(&mut self) -> PResult<'a, (Vec<P<AssocItem>>, Vec<Attribute>)> {
+    fn parse_item_list<T>(
+        &mut self,
+        attrs: &mut Vec<Attribute>,
+        mut parse_item: impl FnMut(&mut Parser<'a>, &mut bool) -> PResult<'a, T>,
+    ) -> PResult<'a, Vec<T>> {
         self.expect(&token::OpenDelim(token::Brace))?;
-        let attrs = self.parse_inner_attributes()?;
+        attrs.append(&mut self.parse_inner_attributes()?);
 
-        let mut impl_items = Vec::new();
+        let mut items = Vec::new();
         while !self.eat(&token::CloseDelim(token::Brace)) {
+            if self.recover_doc_comment_before_brace() {
+                continue;
+            }
             let mut at_end = false;
-            match self.parse_impl_item(&mut at_end) {
-                Ok(impl_item) => impl_items.push(impl_item),
+            match parse_item(self, &mut at_end) {
+                Ok(item) => items.push(item),
                 Err(mut err) => {
                     err.emit();
                     if !at_end {
@@ -590,7 +512,30 @@ fn parse_impl_body(&mut self) -> PResult<'a, (Vec<P<AssocItem>>, Vec<Attribute>)
                 }
             }
         }
-        Ok((impl_items, attrs))
+        Ok(items)
+    }
+
+    /// Recover on a doc comment before `}`.
+    fn recover_doc_comment_before_brace(&mut self) -> bool {
+        if let token::DocComment(_) = self.token.kind {
+            if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) {
+                struct_span_err!(
+                    self.diagnostic(),
+                    self.token.span,
+                    E0584,
+                    "found a documentation comment that doesn't document anything",
+                )
+                .span_label(self.token.span, "this doc comment doesn't document anything")
+                .help(
+                    "doc comments must come before what they document, maybe a \
+                    comment was intended with `//`?",
+                )
+                .emit();
+                self.bump();
+                return true;
+            }
+        }
+        false
     }
 
     /// Parses defaultness (i.e., `default` or nothing).
@@ -601,6 +546,7 @@ fn parse_defaultness(&mut self) -> Defaultness {
                 1,
                 &[
                     kw::Impl,
+                    kw::Static,
                     kw::Const,
                     kw::Async,
                     kw::Fn,
@@ -618,8 +564,17 @@ fn parse_defaultness(&mut self) -> Defaultness {
         }
     }
 
-    /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
-    fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafe) -> PResult<'a, ItemInfo> {
+    /// Is this an `(unsafe auto? | auto) trait` item?
+    fn check_auto_or_unsafe_trait_item(&mut self) -> bool {
+        // auto trait
+        self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait])
+            // unsafe auto trait
+            || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto])
+    }
+
+    /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
+    fn parse_item_trait(&mut self, attrs: &mut Vec<Attribute>, lo: Span) -> PResult<'a, ItemInfo> {
+        let unsafety = self.parse_unsafety();
         // Parse optional `auto` prefix.
         let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No };
 
@@ -646,7 +601,7 @@ fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafe) -> PResult<'a, ItemIn
             self.expect_semi()?;
 
             let whole_span = lo.to(self.prev_span);
-            if let IsAuto::Yes = is_auto {
+            if is_auto == IsAuto::Yes {
                 let msg = "trait aliases cannot be `auto`";
                 self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit();
             }
@@ -657,43 +612,12 @@ fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafe) -> PResult<'a, ItemIn
 
             self.sess.gated_spans.gate(sym::trait_alias, whole_span);
 
-            Ok((ident, ItemKind::TraitAlias(tps, bounds), None))
+            Ok((ident, ItemKind::TraitAlias(tps, bounds)))
         } else {
             // It's a normal trait.
             tps.where_clause = self.parse_where_clause()?;
-            self.expect(&token::OpenDelim(token::Brace))?;
-            let mut trait_items = vec![];
-            while !self.eat(&token::CloseDelim(token::Brace)) {
-                if let token::DocComment(_) = self.token.kind {
-                    if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) {
-                        struct_span_err!(
-                            self.diagnostic(),
-                            self.token.span,
-                            E0584,
-                            "found a documentation comment that doesn't document anything",
-                        )
-                        .help(
-                            "doc comments must come before what they document, maybe a \
-                            comment was intended with `//`?",
-                        )
-                        .emit();
-                        self.bump();
-                        continue;
-                    }
-                }
-                let mut at_end = false;
-                match self.parse_trait_item(&mut at_end) {
-                    Ok(item) => trait_items.push(item),
-                    Err(mut e) => {
-                        e.emit();
-                        if !at_end {
-                            self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
-                            break;
-                        }
-                    }
-                }
-            }
-            Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None))
+            let items = self.parse_item_list(attrs, |p, at_end| p.parse_trait_item(at_end))?;
+            Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, items)))
         }
     }
 
@@ -715,12 +639,12 @@ pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, P<AssocItem
     fn parse_assoc_item(
         &mut self,
         at_end: &mut bool,
-        is_name_required: fn(&token::Token) -> bool,
+        req_name: fn(&token::Token) -> bool,
     ) -> PResult<'a, P<AssocItem>> {
         let attrs = self.parse_outer_attributes()?;
         let mut unclosed_delims = vec![];
         let (mut item, tokens) = self.collect_tokens(|this| {
-            let item = this.parse_assoc_item_(at_end, attrs, is_name_required);
+            let item = this.parse_assoc_item_(at_end, attrs, req_name);
             unclosed_delims.append(&mut this.unclosed_delims);
             item
         })?;
@@ -736,53 +660,45 @@ fn parse_assoc_item_(
         &mut self,
         at_end: &mut bool,
         mut attrs: Vec<Attribute>,
-        is_name_required: fn(&token::Token) -> bool,
+        req_name: fn(&token::Token) -> bool,
     ) -> PResult<'a, AssocItem> {
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
         let defaultness = self.parse_defaultness();
-        let (name, kind, generics) = if self.eat_keyword(kw::Type) {
+
+        let (ident, kind) = if self.eat_keyword(kw::Type) {
             self.parse_assoc_ty()?
-        } else if self.is_fn_front_matter() {
-            let cfg = ParamCfg { is_name_required };
-            let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, &cfg)?;
-            (ident, AssocItemKind::Fn(sig, body), generics)
-        } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? {
-            (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default())
+        } 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, 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))?;
+            (ident, AssocItemKind::Static(ty, mutbl, expr))
+        } else if self.eat_keyword(kw::Const) {
+            let (ident, ty, expr) = self.parse_item_const_common(None)?;
+            (ident, AssocItemKind::Const(ty, expr))
+        } else if self.isnt_macro_invocation() {
+            return Err(self.missing_assoc_item_kind_err("associated", 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))
         } else {
-            self.parse_assoc_const()?
+            self.recover_attrs_no_item(&attrs)?;
+            self.unexpected()?
         };
 
-        Ok(AssocItem {
-            id: DUMMY_NODE_ID,
-            span: lo.to(self.prev_span),
-            ident: name,
-            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()))
+        let span = lo.to(self.prev_span);
+        let id = DUMMY_NODE_ID;
+        Ok(AssocItem { id, span, ident, attrs, vis, defaultness, kind, tokens: None })
     }
 
     /// 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()?;
 
@@ -794,7 +710,7 @@ fn parse_assoc_ty(&mut self) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
         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`.
@@ -862,7 +778,7 @@ fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
 
     fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> {
         match self.token.kind {
-            token::Ident(name, false) if name == kw::Underscore => {
+            token::Ident(name @ kw::Underscore, false) => {
                 let span = self.token.span;
                 self.bump();
                 Ok(Ident::new(name, span))
@@ -879,12 +795,7 @@ fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> {
     /// extern crate foo;
     /// extern crate bar as foo;
     /// ```
-    fn parse_item_extern_crate(
-        &mut self,
-        lo: Span,
-        visibility: Visibility,
-        attrs: Vec<Attribute>,
-    ) -> PResult<'a, P<Item>> {
+    fn parse_item_extern_crate(&mut self) -> PResult<'a, ItemInfo> {
         // Accept `extern crate name-like-this` for better diagnostics
         let orig_name = self.parse_crate_name_with_dashes()?;
         let (item_name, orig_name) = if let Some(rename) = self.parse_rename()? {
@@ -893,9 +804,7 @@ fn parse_item_extern_crate(
             (orig_name, None)
         };
         self.expect_semi()?;
-
-        let span = lo.to(self.prev_span);
-        Ok(self.mk_item(span, item_name, ItemKind::ExternCrate(orig_name), visibility, attrs))
+        Ok((item_name, ItemKind::ExternCrate(orig_name)))
     }
 
     fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> {
@@ -938,8 +847,7 @@ fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> {
 
     /// Parses `extern` for foreign ABIs modules.
     ///
-    /// `extern` is expected to have been
-    /// consumed before calling this method.
+    /// `extern` is expected to have been consumed before calling this method.
     ///
     /// # Examples
     ///
@@ -947,129 +855,58 @@ fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> {
     /// extern "C" {}
     /// extern {}
     /// ```
-    fn parse_item_foreign_mod(
-        &mut self,
-        lo: Span,
-        abi: Option<StrLit>,
-        visibility: Visibility,
-        mut attrs: Vec<Attribute>,
-    ) -> PResult<'a, P<Item>> {
-        self.expect(&token::OpenDelim(token::Brace))?;
-
-        attrs.extend(self.parse_inner_attributes()?);
-
-        let mut foreign_items = vec![];
-        while !self.eat(&token::CloseDelim(token::Brace)) {
-            foreign_items.push(self.parse_foreign_item()?);
-        }
-
-        let prev_span = self.prev_span;
-        let m = ast::ForeignMod { abi, items: foreign_items };
-        let invalid = Ident::invalid();
-        Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs))
+    fn parse_item_foreign_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
+        let abi = self.parse_abi(); // ABI?
+        let items = self.parse_item_list(attrs, |p, at_end| p.parse_foreign_item(at_end))?;
+        let module = ast::ForeignMod { abi, items };
+        Ok((Ident::invalid(), ItemKind::ForeignMod(module)))
     }
 
-    /// Parses a foreign item.
-    pub fn parse_foreign_item(&mut self) -> PResult<'a, P<ForeignItem>> {
+    /// Parses a foreign item (one in an `extern { ... }` block).
+    pub fn parse_foreign_item(&mut self, at_end: &mut bool) -> PResult<'a, P<ForeignItem>> {
         maybe_whole!(self, NtForeignItem, |ni| ni);
 
         let mut attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
 
-        if self.check_keyword(kw::Type) {
+        let (ident, kind) = if self.eat_keyword(kw::Type) {
             // FOREIGN TYPE ITEM
-            self.parse_item_foreign_type(vis, lo, attrs)
-        } else if self.is_fn_front_matter() {
+            self.parse_item_foreign_type()?
+        } else if self.check_fn_front_matter() {
             // FOREIGN FUNCTION ITEM
-            let (ident, sig, generics, body) =
-                self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
-            let kind = ForeignItemKind::Fn(sig, generics, body);
-            let span = lo.to(self.prev_span);
-            Ok(P(ast::ForeignItem {
-                ident,
-                attrs,
-                kind,
-                id: DUMMY_NODE_ID,
-                span,
-                vis,
-                tokens: None,
-            }))
+            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(vis, lo, attrs)
-        } 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`")
-                .span_suggestion(
-                    self.prev_span,
-                    "try using a static value",
-                    "static".to_owned(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
-            self.parse_item_foreign_static(vis, lo, attrs)
-        } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), &mut false)? {
-            let kind = ForeignItemKind::Macro(mac);
-            let span = lo.to(self.prev_span);
-            let ident = Ident::invalid();
-            Ok(P(ForeignItem { ident, span, id: DUMMY_NODE_ID, attrs, vis, kind, tokens: None }))
+            let mutbl = self.parse_mutability();
+            let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?;
+            (ident, ForeignItemKind::Static(ty, mutbl, expr))
+        } else if self.eat_keyword(kw::Const) {
+            let (ident, ty, expr) = self.parse_item_const_common(None)?;
+            (ident, ForeignItemKind::Const(ty, expr))
+        } 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 {
-            if !attrs.is_empty() {
-                self.expected_item_err(&attrs)?;
-            }
-            self.unexpected()
-        }
-    }
-
-    /// Parses a static item from a foreign module.
-    /// Assumes that the `static` keyword is already parsed.
-    fn parse_item_foreign_static(
-        &mut self,
-        vis: ast::Visibility,
-        lo: Span,
-        attrs: Vec<Attribute>,
-    ) -> PResult<'a, P<ForeignItem>> {
-        let mutbl = self.parse_mutability();
-        let ident = self.parse_ident()?;
-        self.expect(&token::Colon)?;
-        let ty = self.parse_ty()?;
-        let hi = self.token.span;
-        self.expect_semi()?;
-        Ok(P(ForeignItem {
-            ident,
-            attrs,
-            kind: ForeignItemKind::Static(ty, mutbl),
-            id: DUMMY_NODE_ID,
-            span: lo.to(hi),
-            vis,
-            tokens: None,
-        }))
+            self.recover_attrs_no_item(&attrs)?;
+            self.unexpected()?
+        };
+        Ok(P(self.mk_item(lo, ident, kind, vis, attrs)))
     }
 
     /// Parses a type from a foreign module.
-    fn parse_item_foreign_type(
-        &mut self,
-        vis: ast::Visibility,
-        lo: Span,
-        attrs: Vec<Attribute>,
-    ) -> PResult<'a, P<ForeignItem>> {
-        self.expect_keyword(kw::Type)?;
-
-        let ident = self.parse_ident()?;
-        let hi = self.token.span;
-        self.expect_semi()?;
-        Ok(P(ast::ForeignItem {
-            ident,
-            attrs,
-            kind: ForeignItemKind::Ty,
-            id: DUMMY_NODE_ID,
-            span: lo.to(hi),
-            vis,
-            tokens: None,
-        }))
+    fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
+        let (ident, kind) = self.parse_assoc_ty()?;
+        let kind = match kind {
+            AssocItemKind::TyAlias(g, b, d) => ForeignItemKind::TyAlias(g, b, d),
+            _ => unreachable!(),
+        };
+        Ok((ident, kind))
     }
 
     fn is_static_global(&mut self) -> bool {
@@ -1089,34 +926,59 @@ fn is_static_global(&mut self) -> bool {
         }
     }
 
-    /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with
+    /// Recover on `const mut` with `const` already eaten.
+    fn recover_const_mut(&mut self, const_span: Span) {
+        if self.eat_keyword(kw::Mut) {
+            let span = self.prev_span;
+            self.struct_span_err(span, "const globals cannot be mutable")
+                .span_label(span, "cannot be mutable")
+                .span_suggestion(
+                    const_span,
+                    "you might want to declare a static instead",
+                    "static".to_owned(),
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+        }
+    }
+
+    /// 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, None))
+        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
@@ -1166,7 +1028,7 @@ fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
 
         let enum_definition =
             EnumDef { variants: variants.into_iter().filter_map(|v| v).collect() };
-        Ok((id, ItemKind::Enum(enum_definition, generics), None))
+        Ok((id, ItemKind::Enum(enum_definition, generics)))
     }
 
     fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
@@ -1260,7 +1122,7 @@ fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> {
             return Err(err);
         };
 
-        Ok((class_name, ItemKind::Struct(vdata, generics), None))
+        Ok((class_name, ItemKind::Struct(vdata, generics)))
     }
 
     /// Parses `union Foo { ... }`.
@@ -1284,12 +1146,7 @@ fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> {
             return Err(err);
         };
 
-        Ok((class_name, ItemKind::Union(vdata, generics), None))
-    }
-
-    pub(super) fn is_union_item(&self) -> bool {
-        self.token.is_keyword(kw::Union)
-            && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
+        Ok((class_name, ItemKind::Union(vdata, generics)))
     }
 
     fn parse_record_struct_body(
@@ -1439,112 +1296,109 @@ fn parse_name_and_ty(
         })
     }
 
-    pub(super) fn eat_macro_def(
-        &mut self,
-        attrs: &[Attribute],
-        vis: &Visibility,
-        lo: Span,
-    ) -> PResult<'a, Option<P<Item>>> {
-        let (ident, def) = if self.eat_keyword(kw::Macro) {
-            let ident = self.parse_ident()?;
-            let body = if self.check(&token::OpenDelim(token::Brace)) {
-                self.parse_mac_args()?
-            } else if self.check(&token::OpenDelim(token::Paren)) {
-                let params = self.parse_token_tree();
-                let pspan = params.span();
-                let body = if self.check(&token::OpenDelim(token::Brace)) {
-                    self.parse_token_tree()
-                } else {
-                    return self.unexpected();
-                };
-                let bspan = body.span();
-                let tokens = TokenStream::new(vec![
-                    params.into(),
-                    TokenTree::token(token::FatArrow, pspan.between(bspan)).into(),
-                    body.into(),
-                ]);
-                let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi());
-                P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens))
-            } else {
+    /// Parses a declarative macro 2.0 definition.
+    /// The `macro` keyword has already been parsed.
+    /// ```
+    /// MacBody = "{" TOKEN_STREAM "}" ;
+    /// MacParams = "(" TOKEN_STREAM ")" ;
+    /// DeclMac = "macro" Ident MacParams? MacBody ;
+    /// ```
+    fn parse_item_decl_macro(&mut self, lo: Span) -> PResult<'a, ItemInfo> {
+        let ident = self.parse_ident()?;
+        let body = if self.check(&token::OpenDelim(token::Brace)) {
+            self.parse_mac_args()? // `MacBody`
+        } else if self.check(&token::OpenDelim(token::Paren)) {
+            let params = self.parse_token_tree(); // `MacParams`
+            let pspan = params.span();
+            if !self.check(&token::OpenDelim(token::Brace)) {
                 return self.unexpected();
-            };
+            }
+            let body = self.parse_token_tree(); // `MacBody`
+            // Convert `MacParams MacBody` into `{ MacParams => MacBody }`.
+            let bspan = body.span();
+            let arrow = TokenTree::token(token::FatArrow, pspan.between(bspan)); // `=>`
+            let tokens = TokenStream::new(vec![params.into(), arrow.into(), body.into()]);
+            let dspan = DelimSpan::from_pair(pspan.shrink_to_lo(), bspan.shrink_to_hi());
+            P(MacArgs::Delimited(dspan, MacDelimiter::Brace, tokens))
+        } else {
+            return self.unexpected();
+        };
+
+        self.sess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_span));
+        Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: false })))
+    }
 
-            (ident, ast::MacroDef { body, legacy: false })
-        } else if self.check_keyword(sym::macro_rules)
+    /// Is this unambiguously the start of a `macro_rules! foo` item defnition?
+    fn is_macro_rules_item(&mut self) -> bool {
+        self.check_keyword(sym::macro_rules)
             && self.look_ahead(1, |t| *t == token::Not)
             && self.look_ahead(2, |t| t.is_ident())
-        {
-            let prev_span = self.prev_span;
-            self.complain_if_pub_macro(&vis.node, prev_span);
-            self.bump();
-            self.bump();
-
-            let ident = self.parse_ident()?;
-            let body = self.parse_mac_args()?;
-            if body.need_semicolon() && !self.eat(&token::Semi) {
-                self.report_invalid_macro_expansion_item();
-            }
+    }
 
-            (ident, ast::MacroDef { body, legacy: true })
-        } else {
-            return Ok(None);
-        };
+    /// Parses a legacy `macro_rules! foo { ... }` declarative macro.
+    fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> {
+        self.expect_keyword(sym::macro_rules)?; // `macro_rules`
+        self.expect(&token::Not)?; // `!`
 
-        let span = lo.to(self.prev_span);
+        let ident = self.parse_ident()?;
+        let body = self.parse_mac_args()?;
+        self.eat_semi_for_macro_if_needed(&body);
+        self.complain_if_pub_macro(vis, true);
+
+        Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, legacy: true })))
+    }
 
-        if !def.legacy {
-            self.sess.gated_spans.gate(sym::decl_macro, span);
+    /// Item macro invocations or `macro_rules!` definitions need inherited visibility.
+    /// If that's not the case, emit an error.
+    fn complain_if_pub_macro(&self, vis: &Visibility, macro_rules: bool) {
+        if let VisibilityKind::Inherited = vis.node {
+            return;
         }
 
-        Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec())))
+        let vstr = pprust::vis_to_string(vis);
+        let vstr = vstr.trim_end();
+        if macro_rules {
+            let msg = format!("can't qualify macro_rules invocation with `{}`", vstr);
+            self.struct_span_err(vis.span, &msg)
+                .span_suggestion(
+                    vis.span,
+                    "try exporting the macro",
+                    "#[macro_export]".to_owned(),
+                    Applicability::MaybeIncorrect, // speculative
+                )
+                .emit();
+        } else {
+            self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`")
+                .span_suggestion(
+                    vis.span,
+                    "remove the visibility",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+                .help(&format!("try adjusting the macro to put `{}` inside the invocation", vstr))
+                .emit();
+        }
     }
 
-    fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) {
-        match *vis {
-            VisibilityKind::Inherited => {}
-            _ => {
-                let mut err = if self.token.is_keyword(sym::macro_rules) {
-                    let mut err =
-                        self.struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
-                    err.span_suggestion(
-                        sp,
-                        "try exporting the macro",
-                        "#[macro_export]".to_owned(),
-                        Applicability::MaybeIncorrect, // speculative
-                    );
-                    err
-                } else {
-                    let mut err =
-                        self.struct_span_err(sp, "can't qualify macro invocation with `pub`");
-                    err.help("try adjusting the macro to put `pub` inside the invocation");
-                    err
-                };
-                err.emit();
-            }
+    fn eat_semi_for_macro_if_needed(&mut self, args: &MacArgs) {
+        if args.need_semicolon() && !self.eat(&token::Semi) {
+            self.report_invalid_macro_expansion_item(args);
         }
     }
 
-    fn report_invalid_macro_expansion_item(&self) {
-        let has_close_delim = self
-            .sess
-            .source_map()
-            .span_to_snippet(self.prev_span)
-            .map(|s| s.ends_with(")") || s.ends_with("]"))
-            .unwrap_or(false);
-
+    fn report_invalid_macro_expansion_item(&self, args: &MacArgs) {
         let mut err = self.struct_span_err(
             self.prev_span,
             "macros that expand to items must be delimited with braces or followed by a semicolon",
         );
-
-        // To avoid ICE, we shouldn't emit actual suggestions when it hasn't closing delims
-        if has_close_delim {
+        if self.unclosed_delims.is_empty() {
+            let DelimSpan { open, close } = match args {
+                MacArgs::Empty | MacArgs::Eq(..) => unreachable!(),
+                MacArgs::Delimited(dspan, ..) => *dspan,
+            };
             err.multipart_suggestion(
                 "change the delimiters to curly braces",
-                vec![
-                    (self.prev_span.with_hi(self.prev_span.lo() + BytePos(1)), '{'.to_string()),
-                    (self.prev_span.with_lo(self.prev_span.hi() - BytePos(1)), '}'.to_string()),
-                ],
+                vec![(open, "{".to_string()), (close, '}'.to_string())],
                 Applicability::MaybeIncorrect,
             );
         } else {
@@ -1555,14 +1409,13 @@ fn report_invalid_macro_expansion_item(&self) {
                 Applicability::HasPlaceholders,
             );
         }
-
         err.span_suggestion(
             self.prev_span.shrink_to_hi(),
             "add a semicolon",
             ';'.to_string(),
             Applicability::MaybeIncorrect,
-        )
-        .emit();
+        );
+        err.emit();
     }
 
     /// Checks if current token is one of tokens which cannot be nested like `kw::Enum`. In case
@@ -1594,29 +1447,23 @@ fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> {
         Ok(true)
     }
 
-    fn mk_item(
+    fn mk_item<K>(
         &self,
-        span: Span,
+        lo: Span,
         ident: Ident,
-        kind: ItemKind,
+        kind: K,
         vis: Visibility,
         attrs: Vec<Attribute>,
-    ) -> P<Item> {
-        P(Item { ident, attrs, id: DUMMY_NODE_ID, kind, vis, span, tokens: None })
+    ) -> Item<K> {
+        let span = lo.to(self.prev_span);
+        Item { ident, attrs, id: DUMMY_NODE_ID, kind, vis, span, tokens: None }
     }
 }
 
 /// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
-pub(super) struct ParamCfg {
-    /// `is_name_required` decides if, per-parameter,
-    /// the parameter must have a pattern or just a type.
-    pub is_name_required: fn(&token::Token) -> bool,
-}
-
-impl ParamCfg {
-    /// Configuration for a free function in the sense that it is not associated.
-    const FREE: Self = ParamCfg { is_name_required: |_| true };
-}
+///
+/// The function decides if, per-parameter `p`, `p` must have a pattern or just a type.
+type ReqName = fn(&token::Token) -> bool;
 
 /// Parsing of functions and methods.
 impl<'a> Parser<'a> {
@@ -1625,12 +1472,12 @@ fn parse_fn(
         &mut self,
         at_end: &mut bool,
         attrs: &mut Vec<Attribute>,
-        cfg: &ParamCfg,
+        req_name: ReqName,
     ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
         let header = self.parse_fn_front_matter()?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
         let mut generics = self.parse_generics()?; // `<'a, T, ...>`
-        let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?; // `(p: u8, ...)`
+        let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)`
         generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
         let body = self.parse_fn_body(at_end, attrs)?; // `;` or `{ ... }`.
         Ok((ident, FnSig { header, decl }, generics, body))
@@ -1668,7 +1515,7 @@ fn parse_fn_body(
     }
 
     /// Is the current token the start of an `FnHeader` / not a valid parse?
-    fn is_fn_front_matter(&mut self) -> bool {
+    fn check_fn_front_matter(&mut self) -> bool {
         // We use an over-approximation here.
         // `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
         const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];
@@ -1717,24 +1564,36 @@ fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
         Ok(FnHeader { constness, unsafety, asyncness, ext })
     }
 
+    /// We are parsing `async fn`. If we are on Rust 2015, emit an error.
+    fn ban_async_in_2015(&self, span: Span) {
+        if span.rust_2015() {
+            let diag = self.diagnostic();
+            struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition")
+                .note("to use `async fn`, switch to Rust 2018")
+                .help("set `edition = \"2018\"` in `Cargo.toml`")
+                .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
+                .emit();
+        }
+    }
+
     /// Parses the parameter list and result type of a function declaration.
     pub(super) fn parse_fn_decl(
         &mut self,
-        cfg: &ParamCfg,
+        req_name: ReqName,
         ret_allow_plus: AllowPlus,
     ) -> PResult<'a, P<FnDecl>> {
         Ok(P(FnDecl {
-            inputs: self.parse_fn_params(cfg)?,
+            inputs: self.parse_fn_params(req_name)?,
             output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
         }))
     }
 
     /// Parses the parameter list of a function, including the `(` and `)` delimiters.
-    fn parse_fn_params(&mut self, cfg: &ParamCfg) -> PResult<'a, Vec<Param>> {
+    fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> {
         let mut first_param = true;
         // Parse the arguments, starting out with `self` being allowed...
         let (mut params, _) = self.parse_paren_comma_seq(|p| {
-            let param = p.parse_param_general(&cfg, first_param).or_else(|mut e| {
+            let param = p.parse_param_general(req_name, first_param).or_else(|mut e| {
                 e.emit();
                 let lo = p.prev_span;
                 // Skip every token until next possible arg or end.
@@ -1754,7 +1613,7 @@ fn parse_fn_params(&mut self, cfg: &ParamCfg) -> PResult<'a, Vec<Param>> {
     /// Parses a single function parameter.
     ///
     /// - `self` is syntactically allowed when `first_param` holds.
-    fn parse_param_general(&mut self, cfg: &ParamCfg, first_param: bool) -> PResult<'a, Param> {
+    fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
 
@@ -1766,7 +1625,7 @@ fn parse_param_general(&mut self, cfg: &ParamCfg, first_param: bool) -> PResult<
 
         let is_name_required = match self.token.kind {
             token::DotDotDot => false,
-            _ => (cfg.is_name_required)(&self.token),
+            _ => req_name(&self.token),
         };
         let (pat, ty) = if is_name_required || self.is_named_param() {
             debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);