about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-02-13 22:20:58 +0000
committerbors <bors@rust-lang.org>2020-02-13 22:20:58 +0000
commit10104085e4f9f52f405fa1cc5e5e18c4c4cc72d1 (patch)
treee454e1e75dff88439e15462a257cb669b1d4c10d
parent5d04ce67fd14538d03fa47a2598f80d49fd564c6 (diff)
parent7704e590ece52ef265e0ca16bce1180930b69330 (diff)
downloadrust-10104085e4f9f52f405fa1cc5e5e18c4c4cc72d1.tar.gz
rust-10104085e4f9f52f405fa1cc5e5e18c4c4cc72d1.zip
Auto merge of #69144 - Dylan-DPC:rollup-apt6zjj, r=Dylan-DPC
Rollup of 9 pull requests

Successful merges:

 - #68728 (parse: merge `fn` syntax + cleanup item parsing)
 - #68938 (fix lifetime shadowing check in GATs)
 - #69057 (expand: misc cleanups and simplifications)
 - #69108 (Use HirId in TraitCandidate.)
 - #69125 (Add comment to SGX entry code)
 - #69126 (miri: fix exact_div)
 - #69127 (Enable use after scope detection in the new LLVM pass manager)
 - #69135 (Spelling error "represening" to "representing")
 - #69141 (Don't error on network failures)

Failed merges:

r? @ghost
-rw-r--r--src/librustc/ich/impls_hir.rs1
-rw-r--r--src/librustc/ty/context.rs4
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_ast_pretty/pprust.rs1
-rw-r--r--src/librustc_expand/expand.rs121
-rw-r--r--src/librustc_hir/hir.rs19
-rw-r--r--src/librustc_lexer/src/lib.rs2
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs6
-rw-r--r--src/librustc_parse/config.rs100
-rw-r--r--src/librustc_parse/parser/item.rs978
-rw-r--r--src/librustc_parse/parser/mod.rs5
-rw-r--r--src/librustc_parse/parser/module.rs26
-rw-r--r--src/librustc_parse/parser/stmt.rs40
-rw-r--r--src/librustc_resolve/late.rs4
-rw-r--r--src/librustc_resolve/lib.rs2
-rw-r--r--src/librustc_resolve/lifetimes.rs6
-rw-r--r--src/librustc_typeck/check/method/probe.rs15
-rw-r--r--src/libstd/sys/sgx/abi/entry.S1
-rw-r--r--src/rustllvm/PassWrapper.cpp4
-rw-r--r--src/test/pretty/trait-inner-attr.rs7
-rw-r--r--src/test/ui/generic-associated-types/shadowing.rs4
-rw-r--r--src/test/ui/generic-associated-types/shadowing.stderr21
-rw-r--r--src/test/ui/issues/issue-58856-2.stderr4
-rw-r--r--src/test/ui/issues/issue-60075.stderr2
-rw-r--r--src/test/ui/macros/issue-54441.rs3
-rw-r--r--src/test/ui/macros/issue-54441.stderr16
-rw-r--r--src/test/ui/parser/attr-before-eof.stderr4
-rw-r--r--src/test/ui/parser/attr-dangling-in-mod.stderr4
-rw-r--r--src/test/ui/parser/attrs-after-extern-mod.rs10
-rw-r--r--src/test/ui/parser/attrs-after-extern-mod.stderr4
-rw-r--r--src/test/ui/parser/default.rs3
-rw-r--r--src/test/ui/parser/default.stderr6
-rw-r--r--src/test/ui/parser/doc-before-attr.stderr6
-rw-r--r--src/test/ui/parser/doc-before-extern-rbrace.rs4
-rw-r--r--src/test/ui/parser/doc-before-extern-rbrace.stderr7
-rw-r--r--src/test/ui/parser/doc-inside-trait-item.stderr2
-rw-r--r--src/test/ui/parser/duplicate-visibility.rs4
-rw-r--r--src/test/ui/parser/duplicate-visibility.stderr6
-rw-r--r--src/test/ui/parser/inner-attr-in-trait-def.rs9
-rw-r--r--src/test/ui/parser/issue-19398.rs3
-rw-r--r--src/test/ui/parser/issue-19398.stderr13
-rw-r--r--src/test/ui/parser/issue-20711-2.rs3
-rw-r--r--src/test/ui/parser/issue-20711-2.stderr8
-rw-r--r--src/test/ui/parser/issue-20711.rs3
-rw-r--r--src/test/ui/parser/issue-20711.stderr8
-rw-r--r--src/test/ui/parser/issue-32446.stderr4
-rw-r--r--src/test/ui/parser/issue-41155.stderr4
-rw-r--r--src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr4
-rw-r--r--src/test/ui/parser/macro/pub-item-macro.rs11
-rw-r--r--src/test/ui/parser/macro/pub-item-macro.stderr12
-rw-r--r--src/test/ui/parser/macro/trait-non-item-macros.stderr4
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs6
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr25
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs2
-rw-r--r--src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr6
-rw-r--r--src/test/ui/parser/pub-method-macro.rs3
-rw-r--r--src/test/ui/parser/pub-method-macro.stderr2
-rw-r--r--src/test/ui/parser/removed-syntax-static-fn.rs2
-rw-r--r--src/test/ui/parser/removed-syntax-static-fn.stderr13
-rw-r--r--src/test/ui/pub/pub-restricted-error-fn.rs3
-rw-r--r--src/test/ui/pub/pub-restricted-error-fn.stderr16
-rw-r--r--src/tools/rustbook/src/main.rs2
62 files changed, 754 insertions, 866 deletions
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 1a763e43d55..eadc9ddeee6 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -270,7 +270,6 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
 
         let import_keys = import_ids
             .iter()
-            .map(|node_id| hcx.node_to_hir_id(*node_id))
             .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), hir_id.local_id))
             .collect();
         (hcx.def_path_hash(*def_id), import_keys)
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2adf7086417..b2eb122bfee 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1161,6 +1161,10 @@ impl<'tcx> TyCtxt<'tcx> {
         for (k, v) in resolutions.trait_map {
             let hir_id = hir.node_to_hir_id(k);
             let map = trait_map.entry(hir_id.owner).or_default();
+            let v = v
+                .into_iter()
+                .map(|tc| tc.map_import_ids(|id| hir.definitions().node_to_hir_id(id)))
+                .collect();
             map.insert(hir_id.local_id, StableVec::new(v));
         }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 2bda99e6d20..ad51c60ab01 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -126,7 +126,7 @@ pub struct ResolverOutputs {
     pub definitions: hir_map::Definitions,
     pub cstore: Box<CrateStoreDyn>,
     pub extern_crate_map: NodeMap<CrateNum>,
-    pub trait_map: TraitMap,
+    pub trait_map: TraitMap<NodeId>,
     pub maybe_unused_trait_imports: NodeSet,
     pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
     pub export_map: ExportMap<NodeId>,
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index b1fa818d0a8..75938470b6f 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -1269,6 +1269,7 @@ impl<'a> State<'a> {
                 self.print_where_clause(&generics.where_clause);
                 self.s.word(" ");
                 self.bopen();
+                self.print_inner_attributes(&item.attrs);
                 for trait_item in trait_items {
                     self.print_assoc_item(trait_item);
                 }
diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs
index 90692fe1ec9..371d1f744dd 100644
--- a/src/librustc_expand/expand.rs
+++ b/src/librustc_expand/expand.rs
@@ -451,28 +451,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         _ => unreachable!(),
                     };
                     if !item.derive_allowed() {
-                        let attr = attr::find_by_name(item.attrs(), sym::derive)
-                            .expect("`derive` attribute should exist");
-                        let span = attr.span;
-                        let mut err = self.cx.struct_span_err(
-                            span,
-                            "`derive` may only be applied to structs, enums and unions",
-                        );
-                        if let ast::AttrStyle::Inner = attr.style {
-                            let trait_list = derives
-                                .iter()
-                                .map(|t| pprust::path_to_string(t))
-                                .collect::<Vec<_>>();
-                            let suggestion = format!("#[derive({})]", trait_list.join(", "));
-                            err.span_suggestion(
-                                span,
-                                "try an outer attribute",
-                                suggestion,
-                                // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                        err.emit();
+                        self.error_derive_forbidden_on_non_adt(&derives, &item);
                     }
 
                     let mut item = self.fully_configure(item);
@@ -521,6 +500,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         fragment_with_placeholders
     }
 
+    fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
+        let attr =
+            attr::find_by_name(item.attrs(), sym::derive).expect("`derive` attribute should exist");
+        let span = attr.span;
+        let mut err = self
+            .cx
+            .struct_span_err(span, "`derive` may only be applied to structs, enums and unions");
+        if let ast::AttrStyle::Inner = attr.style {
+            let trait_list = derives.iter().map(|t| pprust::path_to_string(t)).collect::<Vec<_>>();
+            let suggestion = format!("#[derive({})]", trait_list.join(", "));
+            err.span_suggestion(
+                span,
+                "try an outer attribute",
+                suggestion,
+                // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
+                Applicability::MaybeIncorrect,
+            );
+        }
+        err.emit();
+    }
+
     fn resolve_imports(&mut self) {
         if self.monotonic {
             self.cx.resolver.resolve_imports();
@@ -606,21 +606,38 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
     }
 
-    fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment {
-        if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
-            let expn_data = self.cx.current_expansion.id.expn_data();
-            let suggested_limit = self.cx.ecfg.recursion_limit * 2;
-            let mut err = self.cx.struct_span_err(
+    fn error_recursion_limit_reached(&mut self) {
+        let expn_data = self.cx.current_expansion.id.expn_data();
+        let suggested_limit = self.cx.ecfg.recursion_limit * 2;
+        self.cx
+            .struct_span_err(
                 expn_data.call_site,
                 &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()),
-            );
-            err.help(&format!(
+            )
+            .help(&format!(
                 "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
                 suggested_limit, self.cx.ecfg.crate_name,
-            ));
-            err.emit();
-            self.cx.trace_macros_diag();
-            FatalError.raise();
+            ))
+            .emit();
+        self.cx.trace_macros_diag();
+        FatalError.raise();
+    }
+
+    /// A macro's expansion does not fit in this fragment kind.
+    /// For example, a non-type macro in a type position.
+    fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::Mac, span: Span) {
+        let msg = format!(
+            "non-{kind} macro in {kind} position: {path}",
+            kind = kind.name(),
+            path = pprust::path_to_string(&mac.path),
+        );
+        self.cx.span_err(span, &msg);
+        self.cx.trace_macros_diag();
+    }
+
+    fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment {
+        if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
+            self.error_recursion_limit_reached();
         }
 
         let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
@@ -638,13 +655,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     let result = if let Some(result) = fragment_kind.make_from(tok_result) {
                         result
                     } else {
-                        let msg = format!(
-                            "non-{kind} macro in {kind} position: {path}",
-                            kind = fragment_kind.name(),
-                            path = pprust::path_to_string(&mac.path),
-                        );
-                        self.cx.span_err(span, &msg);
-                        self.cx.trace_macros_diag();
+                        self.error_wrong_fragment_kind(fragment_kind, &mac, span);
                         fragment_kind.dummy(span)
                     };
                     self.cx.current_expansion.prior_type_ascription = prev;
@@ -867,7 +878,7 @@ pub fn parse_ast_fragment<'a>(
         AstFragmentKind::ForeignItems => {
             let mut items = SmallVec::new();
             while this.token != token::Eof {
-                items.push(this.parse_foreign_item()?);
+                items.push(this.parse_foreign_item(&mut false)?);
             }
             AstFragment::ForeignItems(items)
         }
@@ -1030,13 +1041,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     }
 
     /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
-    fn classify_item<T>(
+    fn classify_item(
         &mut self,
-        item: &mut T,
-    ) -> (Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)
-    where
-        T: HasAttrs,
-    {
+        item: &mut impl HasAttrs,
+    ) -> (Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool) {
         let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
 
         item.visit_attrs(|mut attrs| {
@@ -1050,9 +1058,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough
     /// to the unused-attributes lint (making it an error on statements and expressions
     /// is a breaking change)
-    fn classify_nonitem<T: HasAttrs>(
+    fn classify_nonitem(
         &mut self,
-        nonitem: &mut T,
+        nonitem: &mut impl HasAttrs,
     ) -> (Option<ast::Attribute>, /* after_derive */ bool) {
         let (mut attr, mut after_derive) = (None, false);
 
@@ -1375,21 +1383,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     _ => unreachable!(),
                 })
             }
-            ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
-                if item.ident == Ident::invalid() {
-                    return noop_flat_map_item(item, self);
-                }
-
+            ast::ItemKind::Mod(ast::Mod { inner, inline, .. })
+                if item.ident != Ident::invalid() =>
+            {
                 let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
                 let mut module = (*self.cx.current_expansion.module).clone();
                 module.mod_path.push(item.ident);
 
-                // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
-                // In the non-inline case, `inner` is never the dummy span (cf. `parse_item_mod`).
-                // Thus, if `inner` is the dummy span, we know the module is inline.
-                let inline_module = item.span.contains(inner) || inner.is_dummy();
-
-                if inline_module {
+                if inline {
                     if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, sym::path) {
                         self.cx.current_expansion.directory_ownership =
                             DirectoryOwnership::Owned { relative: None };
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index c2ddaf7df31..80b379218a5 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -16,7 +16,7 @@ use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use syntax::ast::{self, AsmDialect, CrateSugar, Ident, Name, NodeId};
+use syntax::ast::{self, AsmDialect, CrateSugar, Ident, Name};
 use syntax::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy};
 pub use syntax::ast::{BorrowKind, ImplPolarity, IsAuto};
 pub use syntax::ast::{CaptureBy, Movability, Mutability};
@@ -2608,13 +2608,24 @@ pub type CaptureModeMap = NodeMap<CaptureBy>;
 // has length > 0 if the trait is found through an chain of imports, starting with the
 // import/use statement in the scope where the trait is used.
 #[derive(Clone, Debug)]
-pub struct TraitCandidate {
+pub struct TraitCandidate<ID = HirId> {
     pub def_id: DefId,
-    pub import_ids: SmallVec<[NodeId; 1]>,
+    pub import_ids: SmallVec<[ID; 1]>,
+}
+
+impl<ID> TraitCandidate<ID> {
+    pub fn map_import_ids<F, T>(self, f: F) -> TraitCandidate<T>
+    where
+        F: Fn(ID) -> T,
+    {
+        let TraitCandidate { def_id, import_ids } = self;
+        let import_ids = import_ids.into_iter().map(f).collect();
+        TraitCandidate { def_id, import_ids }
+    }
 }
 
 // Trait method resolution
-pub type TraitMap = NodeMap<Vec<TraitCandidate>>;
+pub type TraitMap<ID = HirId> = NodeMap<Vec<TraitCandidate<ID>>>;
 
 // Map from the NodeId of a glob import to a list of items which are actually
 // imported.
diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs
index 969ce9b06e8..25334461a11 100644
--- a/src/librustc_lexer/src/lib.rs
+++ b/src/librustc_lexer/src/lib.rs
@@ -35,7 +35,7 @@ impl Token {
     }
 }
 
-/// Enum represening common lexeme types.
+/// Enum representing common lexeme types.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum TokenKind {
     // Multi-char tokens:
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index a83b5412790..1085b85d7cd 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -384,8 +384,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> InterpResult<'tcx> {
         // Performs an exact division, resulting in undefined behavior where
         // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`.
-        // First, check x % y != 0.
-        if self.binary_op(BinOp::Rem, a, b)?.to_bits()? != 0 {
+        // First, check x % y != 0 (or if that computation overflows).
+        let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, a, b)?;
+        if overflow || res.to_bits(a.layout.size)? != 0 {
             // Then, check if `b` is -1, which is the "min_value / -1" case.
             let minus1 = Scalar::from_int(-1, dest.layout.size);
             let b_scalar = b.to_scalar().unwrap();
@@ -395,6 +396,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 throw_ub_format!("exact_div: {} cannot be divided by {} without remainder", a, b,)
             }
         }
+        // `Rem` says this is all right, so we can let `Div` do its job.
         self.binop_ignore_overflow(BinOp::Div, a, b, dest)
     }
 }
diff --git a/src/librustc_parse/config.rs b/src/librustc_parse/config.rs
index 8dec64c579e..ec0d251a3f8 100644
--- a/src/librustc_parse/config.rs
+++ b/src/librustc_parse/config.rs
@@ -207,30 +207,29 @@ pub fn features(
     edition: Edition,
     allow_features: &Option<Vec<String>>,
 ) -> (ast::Crate, Features) {
-    let features;
-    {
-        let mut strip_unconfigured = StripUnconfigured { sess, features: None };
+    let mut strip_unconfigured = StripUnconfigured { sess, features: None };
 
-        let unconfigured_attrs = krate.attrs.clone();
-        let err_count = sess.span_diagnostic.err_count();
-        if let Some(attrs) = strip_unconfigured.configure(krate.attrs) {
-            krate.attrs = attrs;
-        } else {
-            // the entire crate is unconfigured
+    let unconfigured_attrs = krate.attrs.clone();
+    let diag = &sess.span_diagnostic;
+    let err_count = diag.err_count();
+    let features = match strip_unconfigured.configure(krate.attrs) {
+        None => {
+            // The entire crate is unconfigured.
             krate.attrs = Vec::new();
             krate.module.items = Vec::new();
-            return (krate, Features::default());
+            Features::default()
         }
-
-        features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features);
-
-        // Avoid reconfiguring malformed `cfg_attr`s
-        if err_count == sess.span_diagnostic.err_count() {
-            strip_unconfigured.features = Some(&features);
-            strip_unconfigured.configure(unconfigured_attrs);
+        Some(attrs) => {
+            krate.attrs = attrs;
+            let features = get_features(diag, &krate.attrs, edition, allow_features);
+            if err_count == diag.err_count() {
+                // Avoid reconfiguring malformed `cfg_attr`s.
+                strip_unconfigured.features = Some(&features);
+                strip_unconfigured.configure(unconfigured_attrs);
+            }
+            features
         }
-    }
-
+    };
     (krate, features)
 }
 
@@ -347,7 +346,13 @@ impl<'a> StripUnconfigured<'a> {
             if !is_cfg(attr) {
                 return true;
             }
-
+            let meta_item = match validate_attr::parse_meta(self.sess, attr) {
+                Ok(meta_item) => meta_item,
+                Err(mut err) => {
+                    err.emit();
+                    return true;
+                }
+            };
             let error = |span, msg, suggestion: &str| {
                 let mut err = self.sess.span_diagnostic.struct_span_err(span, msg);
                 if !suggestion.is_empty() {
@@ -361,41 +366,15 @@ impl<'a> StripUnconfigured<'a> {
                 err.emit();
                 true
             };
-
-            let meta_item = match validate_attr::parse_meta(self.sess, attr) {
-                Ok(meta_item) => meta_item,
-                Err(mut err) => {
-                    err.emit();
-                    return true;
-                }
-            };
-            let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() {
-                nested_meta_items
-            } else {
-                return error(
-                    meta_item.span,
-                    "`cfg` is not followed by parentheses",
-                    "cfg(/* predicate */)",
-                );
-            };
-
-            if nested_meta_items.is_empty() {
-                return error(meta_item.span, "`cfg` predicate is not specified", "");
-            } else if nested_meta_items.len() > 1 {
-                return error(
-                    nested_meta_items.last().unwrap().span(),
-                    "multiple `cfg` predicates are specified",
-                    "",
-                );
-            }
-
-            match nested_meta_items[0].meta_item() {
-                Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
-                None => error(
-                    nested_meta_items[0].span(),
-                    "`cfg` predicate key cannot be a literal",
-                    "",
-                ),
+            let span = meta_item.span;
+            match meta_item.meta_item_list() {
+                None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
+                Some([]) => error(span, "`cfg` predicate is not specified", ""),
+                Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
+                Some([single]) => match single.meta_item() {
+                    Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
+                    None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
+                },
             }
         })
     }
@@ -562,14 +541,9 @@ fn is_cfg(attr: &Attribute) -> bool {
 
 /// Process the potential `cfg` attributes on a module.
 /// Also determine if the module should be included in this configuration.
-pub fn process_configure_mod(
-    sess: &ParseSess,
-    cfg_mods: bool,
-    attrs: &[Attribute],
-) -> (bool, Vec<Attribute>) {
+pub fn process_configure_mod(sess: &ParseSess, cfg_mods: bool, attrs: &mut Vec<Attribute>) -> bool {
     // Don't perform gated feature checking.
     let mut strip_unconfigured = StripUnconfigured { sess, features: None };
-    let mut attrs = attrs.to_owned();
-    strip_unconfigured.process_cfg_attrs(&mut attrs);
-    (!cfg_mods || strip_unconfigured.in_cfg(&attrs), attrs)
+    strip_unconfigured.process_cfg_attrs(attrs);
+    !cfg_mods || strip_unconfigured.in_cfg(&attrs)
 }
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index ccd55c5c08a..500aaaf43b9 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -8,10 +8,9 @@ use rustc_ast_pretty::pprust;
 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 syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
 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,71 +82,67 @@ impl<'a> Parser<'a> {
         });
 
         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.check_fn_front_matter() {
-            // FUNCTION ITEM
-            let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?;
-            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])
         {
@@ -155,273 +150,189 @@ impl<'a> Parser<'a> {
             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`
+    }
 
-        // 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");
+    /// 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)
+    }
+
+    /// 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,
@@ -442,7 +353,7 @@ impl<'a> Parser<'a> {
         //   |        ^ 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);
@@ -451,16 +362,21 @@ impl<'a> Parser<'a> {
 
     /// 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> {
@@ -515,7 +431,7 @@ impl<'a> Parser<'a> {
 
         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) => {
@@ -568,18 +484,25 @@ impl<'a> Parser<'a> {
             }
         };
 
-        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 {
@@ -589,7 +512,30 @@ impl<'a> Parser<'a> {
                 }
             }
         }
-        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).
@@ -617,8 +563,17 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// 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 };
 
@@ -656,43 +611,12 @@ impl<'a> Parser<'a> {
 
             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)))
         }
     }
 
@@ -740,28 +664,28 @@ impl<'a> Parser<'a> {
         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, generics) = 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 let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? {
+        } else if self.check_keyword(kw::Const) {
+            self.parse_assoc_const()?
+        } 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), Generics::default())
         } 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,
-        })
+        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:
@@ -860,7 +784,7 @@ impl<'a> Parser<'a> {
 
     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))
@@ -877,12 +801,7 @@ impl<'a> Parser<'a> {
     /// 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()? {
@@ -891,9 +810,7 @@ impl<'a> Parser<'a> {
             (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> {
@@ -936,8 +853,7 @@ impl<'a> Parser<'a> {
 
     /// 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
     ///
@@ -945,57 +861,32 @@ impl<'a> Parser<'a> {
     /// 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.check_keyword(kw::Type) {
             // FOREIGN TYPE ITEM
-            self.parse_item_foreign_type(vis, lo, attrs)
+            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, |_| true)?;
-            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)
+            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`
@@ -1007,66 +898,37 @@ impl<'a> Parser<'a> {
                     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 }))
+            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 {
-            if !attrs.is_empty() {
-                self.expected_item_err(&attrs)?;
-            }
-            self.unexpected()
-        }
+            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,
-        vis: ast::Visibility,
-        lo: Span,
-        attrs: Vec<Attribute>,
-    ) -> PResult<'a, P<ForeignItem>> {
+    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()?;
-        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,
-        }))
+        Ok((ident, ForeignItemKind::Static(ty, mutbl)))
     }
 
     /// 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>> {
+    fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
         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,
-        }))
+        Ok((ident, ForeignItemKind::Ty))
     }
 
     fn is_static_global(&mut self) -> bool {
@@ -1086,6 +948,22 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// 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`.
     ///
@@ -1110,7 +988,7 @@ impl<'a> Parser<'a> {
             Some(m) => ItemKind::Static(ty, m, e),
             None => ItemKind::Const(ty, e),
         };
-        Ok((id, item, None))
+        Ok((id, item))
     }
 
     /// We were supposed to parse `:` but instead, we're already at `=`.
@@ -1163,7 +1041,7 @@ impl<'a> Parser<'a> {
 
         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>> {
@@ -1257,7 +1135,7 @@ impl<'a> Parser<'a> {
             return Err(err);
         };
 
-        Ok((class_name, ItemKind::Struct(vdata, generics), None))
+        Ok((class_name, ItemKind::Struct(vdata, generics)))
     }
 
     /// Parses `union Foo { ... }`.
@@ -1281,12 +1159,7 @@ impl<'a> Parser<'a> {
             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(
@@ -1436,112 +1309,109 @@ impl<'a> Parser<'a> {
         })
     }
 
-    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 {
@@ -1552,14 +1422,13 @@ impl<'a> Parser<'a> {
                 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
@@ -1591,15 +1460,16 @@ impl<'a> Parser<'a> {
         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 }
     }
 }
 
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index 4716d722778..79944dc35e5 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -572,6 +572,11 @@ impl<'a> Parser<'a> {
         if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) }
     }
 
+    /// Is the given keyword `kw` followed by a non-reserved identifier?
+    fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
+        self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
+    }
+
     fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool {
         if ok {
             true
diff --git a/src/librustc_parse/parser/module.rs b/src/librustc_parse/parser/module.rs
index 0c8fad03d86..754923ae55e 100644
--- a/src/librustc_parse/parser/module.rs
+++ b/src/librustc_parse/parser/module.rs
@@ -40,36 +40,34 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
-    pub(super) fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> {
-        let (in_cfg, outer_attrs) =
-            crate::config::process_configure_mod(self.sess, self.cfg_mods, outer_attrs);
+    pub(super) fn parse_item_mod(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, ItemInfo> {
+        let in_cfg = crate::config::process_configure_mod(self.sess, self.cfg_mods, attrs);
 
         let id_span = self.token.span;
         let id = self.parse_ident()?;
-        if self.eat(&token::Semi) {
+        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
             if in_cfg && self.recurse_into_file_modules {
                 // This mod is in an external file. Let's go get it!
                 let ModulePathSuccess { path, directory_ownership } =
-                    self.submod_path(id, &outer_attrs, id_span)?;
-                let (module, attrs) =
-                    self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?;
-                Ok((id, ItemKind::Mod(module), Some(attrs)))
+                    self.submod_path(id, &attrs, id_span)?;
+                self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?
             } else {
-                let placeholder = ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false };
-                Ok((id, ItemKind::Mod(placeholder), None))
+                (ast::Mod { inner: DUMMY_SP, items: Vec::new(), inline: false }, Vec::new())
             }
         } else {
             let old_directory = self.directory.clone();
-            self.push_directory(id, &outer_attrs);
+            self.push_directory(id, &attrs);
 
             self.expect(&token::OpenDelim(token::Brace))?;
             let mod_inner_lo = self.token.span;
-            let attrs = self.parse_inner_attributes()?;
+            let inner_attrs = self.parse_inner_attributes()?;
             let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
 
             self.directory = old_directory;
-            Ok((id, ItemKind::Mod(module), Some(attrs)))
-        }
+            (module, inner_attrs)
+        };
+        attrs.append(&mut inner_attrs);
+        Ok((id, ItemKind::Mod(module)))
     }
 
     /// Given a termination token, parses all of the items in a module.
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index e97af0dc00c..742fc4802fd 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -7,10 +7,10 @@ use crate::maybe_whole;
 use crate::DirectoryOwnership;
 
 use rustc_errors::{Applicability, PResult};
-use rustc_span::source_map::{respan, BytePos, Span};
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::source_map::{BytePos, Span};
+use rustc_span::symbol::{kw, sym};
 use syntax::ast;
-use syntax::ast::{AttrStyle, AttrVec, Attribute, Mac, MacStmtStyle, VisibilityKind};
+use syntax::ast::{AttrStyle, AttrVec, Attribute, Mac, MacStmtStyle};
 use syntax::ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID};
 use syntax::ptr::P;
 use syntax::token::{self, TokenKind};
@@ -55,21 +55,11 @@ impl<'a> Parser<'a> {
             return self.recover_stmt_local(lo, attrs.into(), msg, "let");
         }
 
-        let mac_vis = respan(lo, VisibilityKind::Inherited);
-        if let Some(macro_def) = self.eat_macro_def(&attrs, &mac_vis, lo)? {
-            return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Item(macro_def))));
-        }
-
-        // Starts like a simple path, being careful to avoid contextual keywords
-        // such as a union items, item with `crate` visibility or auto trait items.
-        // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts
-        // like a path (1 token), but it fact not a path.
-        if self.token.is_path_start()
-            && !self.token.is_qpath_start()
-            && !self.is_union_item() // `union::b::c` - path, `union U { ... }` - not a path.
-            && !self.is_crate_vis() // `crate::b::c` - path, `crate struct S;` - not a path.
-            && !self.is_auto_trait_item()
-            && !self.is_async_fn()
+        // Starts like a simple path, being careful to avoid contextual keywords,
+        // e.g., `union`, items with `crate` visibility, or `auto trait` items.
+        // We aim to parse an arbitrary path `a::b` but not something that starts like a path
+        // (1 token), but it fact not a path. Also, we avoid stealing syntax from `parse_item_`.
+        if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_path_start_item()
         {
             let path = self.parse_path(PathStyle::Expr)?;
 
@@ -199,10 +189,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
-        self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
-    }
-
     fn recover_stmt_local(
         &mut self,
         lo: Span,
@@ -299,16 +285,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn is_auto_trait_item(&self) -> bool {
-        // auto trait
-        (self.token.is_keyword(kw::Auto) &&
-            self.is_keyword_ahead(1, &[kw::Trait]))
-        || // unsafe auto trait
-        (self.token.is_keyword(kw::Unsafe) &&
-         self.is_keyword_ahead(1, &[kw::Auto]) &&
-         self.is_keyword_ahead(2, &[kw::Trait]))
-    }
-
     /// Parses a block. No inner attributes are allowed.
     pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
         maybe_whole!(self, NtBlock, |x| x);
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 58ff7f44789..bcf558d1563 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -2078,7 +2078,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         &mut self,
         mut ident: Ident,
         ns: Namespace,
-    ) -> Vec<TraitCandidate> {
+    ) -> Vec<TraitCandidate<NodeId>> {
         debug!("(getting traits containing item) looking for '{}'", ident.name);
 
         let mut found_traits = Vec::new();
@@ -2123,7 +2123,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         ident: Ident,
         ns: Namespace,
         module: Module<'a>,
-        found_traits: &mut Vec<TraitCandidate>,
+        found_traits: &mut Vec<TraitCandidate<NodeId>>,
     ) {
         assert!(ns == TypeNS || ns == ValueNS);
         let mut traits = module.traits.borrow_mut();
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 2e63c3e1706..4278bf867f3 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -865,7 +865,7 @@ pub struct Resolver<'a> {
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: NodeMap<CrateNum>,
     export_map: ExportMap<NodeId>,
-    trait_map: TraitMap,
+    trait_map: TraitMap<NodeId>,
 
     /// A map from nodes to anonymous modules.
     /// Anonymous modules are pseudo-modules that are implicitly created around items
diff --git a/src/librustc_resolve/lifetimes.rs b/src/librustc_resolve/lifetimes.rs
index fd4d2c718c0..5bc5222f9fc 100644
--- a/src/librustc_resolve/lifetimes.rs
+++ b/src/librustc_resolve/lifetimes.rs
@@ -747,7 +747,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     track_lifetime_uses: true,
                     opaque_type_parent: true,
                 };
-                self.with(scope, |_old_scope, this| {
+                self.with(scope, |old_scope, this| {
+                    this.check_lifetime_params(old_scope, &generics.params);
                     this.visit_generics(generics);
                     for bound in bounds {
                         this.visit_param_bound(bound);
@@ -804,7 +805,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     track_lifetime_uses: true,
                     opaque_type_parent: true,
                 };
-                self.with(scope, |_old_scope, this| {
+                self.with(scope, |old_scope, this| {
+                    this.check_lifetime_params(old_scope, &generics.params);
                     this.visit_generics(generics);
                     this.visit_ty(ty);
                 });
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 760b6487045..8f0fbc2d60c 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -902,13 +902,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             for trait_candidate in applicable_traits.iter() {
                 let trait_did = trait_candidate.def_id;
                 if duplicates.insert(trait_did) {
-                    let import_ids = trait_candidate
-                        .import_ids
-                        .iter()
-                        .map(|node_id| self.fcx.tcx.hir().node_to_hir_id(*node_id))
-                        .collect();
-                    let result =
-                        self.assemble_extension_candidates_for_trait(import_ids, trait_did);
+                    let result = self.assemble_extension_candidates_for_trait(
+                        &trait_candidate.import_ids,
+                        trait_did,
+                    );
                     result?;
                 }
             }
@@ -920,7 +917,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         let mut duplicates = FxHashSet::default();
         for trait_info in suggest::all_traits(self.tcx) {
             if duplicates.insert(trait_info.def_id) {
-                self.assemble_extension_candidates_for_trait(smallvec![], trait_info.def_id)?;
+                self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id)?;
             }
         }
         Ok(())
@@ -959,7 +956,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
     fn assemble_extension_candidates_for_trait(
         &mut self,
-        import_ids: SmallVec<[hir::HirId; 1]>,
+        import_ids: &SmallVec<[hir::HirId; 1]>,
         trait_def_id: DefId,
     ) -> Result<(), MethodError<'tcx>> {
         debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index ed4db287229..1f06c9da3a9 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -151,6 +151,7 @@ elf_entry:
     pushfq
     andq $~0x40400, (%rsp)
     popfq
+/*  check for abort */
     bt $0,.Laborted(%rip)
     jc .Lreentry_panic
 .endm
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 2c283149be8..65071c3ed86 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -824,14 +824,14 @@ LLVMRustOptimizeWithNewPassManager(
     }
 
     if (SanitizerOptions->SanitizeAddress) {
-      // FIXME: Rust does not expose the UseAfterScope option.
       PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) {
         MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
       });
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
           FPM.addPass(AddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover));
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover,
+              /*UseAfterScope=*/true));
         }
       );
       PipelineStartEPCallbacks.push_back(
diff --git a/src/test/pretty/trait-inner-attr.rs b/src/test/pretty/trait-inner-attr.rs
new file mode 100644
index 00000000000..bb4fb1459bd
--- /dev/null
+++ b/src/test/pretty/trait-inner-attr.rs
@@ -0,0 +1,7 @@
+// pp-exact
+
+trait Foo {
+    #![allow(bar)]
+}
+
+fn main() { }
diff --git a/src/test/ui/generic-associated-types/shadowing.rs b/src/test/ui/generic-associated-types/shadowing.rs
index 7277c0d87c6..5c308948bd3 100644
--- a/src/test/ui/generic-associated-types/shadowing.rs
+++ b/src/test/ui/generic-associated-types/shadowing.rs
@@ -2,8 +2,8 @@
 #![feature(generic_associated_types)]
 
 trait Shadow<'a> {
-    //FIXME(#44265): The lifetime parameter shadowing should cause an error.
     type Bar<'a>;
+    //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope
 }
 
 trait NoShadow<'a> {
@@ -11,8 +11,8 @@ trait NoShadow<'a> {
 }
 
 impl<'a> NoShadow<'a> for &'a u32 {
-    //FIXME(#44265): The lifetime parameter shadowing should cause an error.
     type Bar<'a> = i32;
+    //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope
 }
 
 trait ShadowT<T> {
diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr
index 3ae1e1a40c8..2d9a0d6fceb 100644
--- a/src/test/ui/generic-associated-types/shadowing.stderr
+++ b/src/test/ui/generic-associated-types/shadowing.stderr
@@ -14,6 +14,22 @@ LL | impl<T> NoShadowT<T> for Option<T> {
 LL |     type Bar<T> = i32;
    |              ^ already used
 
+error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
+  --> $DIR/shadowing.rs:5:14
+   |
+LL | trait Shadow<'a> {
+   |              -- first declared here
+LL |     type Bar<'a>;
+   |              ^^ lifetime 'a already in scope
+
+error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
+  --> $DIR/shadowing.rs:14:14
+   |
+LL | impl<'a> NoShadow<'a> for &'a u32 {
+   |      -- first declared here
+LL |     type Bar<'a> = i32;
+   |              ^^ lifetime 'a already in scope
+
 error: type-generic associated types are not yet implemented
   --> $DIR/shadowing.rs:19:5
    |
@@ -30,6 +46,7 @@ LL |     type Bar<U>; // OK
    |
    = note: for more information, see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0403`.
+Some errors have detailed explanations: E0403, E0496.
+For more information about an error, try `rustc --explain E0403`.
diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr
index 01d70d861e2..6221b90b31d 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 `}`, found `)`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `)`
   --> $DIR/issue-58856-2.rs:11:1
    |
 LL |     }
-   |      - expected one of 10 possible tokens
+   |      - expected one of 11 possible tokens
 LL | }
    | ^ unexpected token
 
diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr
index 60eb99b46b7..b2beb73503b 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 `}`, found `;`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `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 afdf76b7b58..a70163df1cb 100644
--- a/src/test/ui/macros/issue-54441.rs
+++ b/src/test/ui/macros/issue-54441.rs
@@ -1,6 +1,7 @@
 macro_rules! m {
+    //~^ ERROR missing `fn`, `type`, or `static` for extern-item declaration
     () => {
-        let //~ ERROR expected
+        let
     };
 }
 
diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr
index c94355f4716..761e7aec723 100644
--- a/src/test/ui/macros/issue-54441.stderr
+++ b/src/test/ui/macros/issue-54441.stderr
@@ -1,13 +1,11 @@
-error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `static`, `type`, or `unsafe`, found keyword `let`
-  --> $DIR/issue-54441.rs:3:9
+error: missing `fn`, `type`, or `static` for extern-item declaration
+  --> $DIR/issue-54441.rs:1:1
    |
-LL |         let
-   |         ^^^ expected one of 9 possible tokens
-...
-LL |     m!();
-   |     ----- in this macro invocation
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / macro_rules! m {
+LL | |
+LL | |     () => {
+LL | |         let
+   | |________^ missing `fn`, `type`, or `static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/attr-before-eof.stderr b/src/test/ui/parser/attr-before-eof.stderr
index eb5daf84981..a2acb94372b 100644
--- a/src/test/ui/parser/attr-before-eof.stderr
+++ b/src/test/ui/parser/attr-before-eof.stderr
@@ -1,8 +1,8 @@
 error: expected item after attributes
-  --> $DIR/attr-before-eof.rs:3:16
+  --> $DIR/attr-before-eof.rs:3:1
    |
 LL | #[derive(Debug)]
-   |                ^
+   | ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/attr-dangling-in-mod.stderr b/src/test/ui/parser/attr-dangling-in-mod.stderr
index d896b61ce49..1c892eac08f 100644
--- a/src/test/ui/parser/attr-dangling-in-mod.stderr
+++ b/src/test/ui/parser/attr-dangling-in-mod.stderr
@@ -1,8 +1,8 @@
 error: expected item after attributes
-  --> $DIR/attr-dangling-in-mod.rs:6:14
+  --> $DIR/attr-dangling-in-mod.rs:6:1
    |
 LL | #[foo = "bar"]
-   |              ^
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/attrs-after-extern-mod.rs b/src/test/ui/parser/attrs-after-extern-mod.rs
index 4bdd16471cd..ea899dca7b2 100644
--- a/src/test/ui/parser/attrs-after-extern-mod.rs
+++ b/src/test/ui/parser/attrs-after-extern-mod.rs
@@ -1,13 +1,7 @@
-// Constants (static variables) can be used to match in patterns, but mutable
-// statics cannot. This ensures that there's some form of error if this is
-// attempted.
+// Make sure there's an error when given `extern { ... #[attr] }`.
 
-extern crate libc;
+fn main() {}
 
 extern {
-    static mut rust_dbg_static_mut: libc::c_int;
-    pub fn rust_dbg_static_mut_check_four();
     #[cfg(stage37)] //~ ERROR expected item after attributes
 }
-
-pub fn main() {}
diff --git a/src/test/ui/parser/attrs-after-extern-mod.stderr b/src/test/ui/parser/attrs-after-extern-mod.stderr
index cecdab4d631..6060f3afe1e 100644
--- a/src/test/ui/parser/attrs-after-extern-mod.stderr
+++ b/src/test/ui/parser/attrs-after-extern-mod.stderr
@@ -1,8 +1,8 @@
 error: expected item after attributes
-  --> $DIR/attrs-after-extern-mod.rs:10:19
+  --> $DIR/attrs-after-extern-mod.rs:6:5
    |
 LL |     #[cfg(stage37)]
-   |                   ^
+   |     ^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/default.rs b/src/test/ui/parser/default.rs
index 17cd06864bf..65ecb1ebbe9 100644
--- a/src/test/ui/parser/default.rs
+++ b/src/test/ui/parser/default.rs
@@ -19,7 +19,8 @@ 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 expected one of
+    default pub fn foo<T: Default>() -> T { T::default() }
+    //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr
index dde36cf8dde..ede9e471518 100644
--- a/src/test/ui/parser/default.stderr
+++ b/src/test/ui/parser/default.stderr
@@ -1,8 +1,8 @@
-error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `pub`
-  --> $DIR/default.rs:22:13
+error: missing `fn`, `type`, or `const` for associated-item declaration
+  --> $DIR/default.rs:22:12
    |
 LL |     default pub fn foo<T: Default>() -> T { T::default() }
-   |             ^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`
+   |            ^ missing `fn`, `type`, or `const`
 
 error[E0449]: unnecessary visibility qualifier
   --> $DIR/default.rs:16:5
diff --git a/src/test/ui/parser/doc-before-attr.stderr b/src/test/ui/parser/doc-before-attr.stderr
index 0fae44ce5c8..14fd01af2f9 100644
--- a/src/test/ui/parser/doc-before-attr.stderr
+++ b/src/test/ui/parser/doc-before-attr.stderr
@@ -1,8 +1,10 @@
 error: expected item after attributes
-  --> $DIR/doc-before-attr.rs:4:16
+  --> $DIR/doc-before-attr.rs:4:1
    |
+LL | /// hi
+   | ------ other attributes here
 LL | #[derive(Debug)]
-   |                ^
+   | ^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/doc-before-extern-rbrace.rs b/src/test/ui/parser/doc-before-extern-rbrace.rs
index 695d4da1dca..040206b80ff 100644
--- a/src/test/ui/parser/doc-before-extern-rbrace.rs
+++ b/src/test/ui/parser/doc-before-extern-rbrace.rs
@@ -1,4 +1,6 @@
+fn main() {}
+
 extern {
     /// hi
-    //~^ ERROR expected item after doc comment
+    //~^ ERROR found a documentation comment that doesn't document anything
 }
diff --git a/src/test/ui/parser/doc-before-extern-rbrace.stderr b/src/test/ui/parser/doc-before-extern-rbrace.stderr
index 8cc9c916a7a..0edceb268a7 100644
--- a/src/test/ui/parser/doc-before-extern-rbrace.stderr
+++ b/src/test/ui/parser/doc-before-extern-rbrace.stderr
@@ -1,8 +1,11 @@
-error: expected item after doc comment
-  --> $DIR/doc-before-extern-rbrace.rs:2:5
+error[E0584]: found a documentation comment that doesn't document anything
+  --> $DIR/doc-before-extern-rbrace.rs:4:5
    |
 LL |     /// hi
    |     ^^^^^^ this doc comment doesn't document anything
+   |
+   = help: doc comments must come before what they document, maybe a comment was intended with `//`?
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0584`.
diff --git a/src/test/ui/parser/doc-inside-trait-item.stderr b/src/test/ui/parser/doc-inside-trait-item.stderr
index 261e27b6e0d..246255a0a46 100644
--- a/src/test/ui/parser/doc-inside-trait-item.stderr
+++ b/src/test/ui/parser/doc-inside-trait-item.stderr
@@ -2,7 +2,7 @@ error[E0584]: found a documentation comment that doesn't document anything
   --> $DIR/doc-inside-trait-item.rs:3:5
    |
 LL |     /// empty doc
-   |     ^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^ this doc comment doesn't document anything
    |
    = help: doc comments must come before what they document, maybe a comment was intended with `//`?
 
diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs
index a8f0b7d61b9..1d271fa64b0 100644
--- a/src/test/ui/parser/duplicate-visibility.rs
+++ b/src/test/ui/parser/duplicate-visibility.rs
@@ -1,4 +1,6 @@
-// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn`
+fn main() {}
+
 extern {
     pub pub fn foo();
+    //~^ ERROR missing `fn`, `type`, or `static` for extern-item declaration
 }
diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr
index cba4058e482..36a3a1ed5a0 100644
--- a/src/test/ui/parser/duplicate-visibility.stderr
+++ b/src/test/ui/parser/duplicate-visibility.stderr
@@ -1,8 +1,8 @@
-error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub`
-  --> $DIR/duplicate-visibility.rs:3:9
+error: missing `fn`, `type`, or `static` for extern-item declaration
+  --> $DIR/duplicate-visibility.rs:4:8
    |
 LL |     pub pub fn foo();
-   |         ^^^ expected one of 8 possible tokens
+   |        ^ missing `fn`, `type`, or `static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/inner-attr-in-trait-def.rs b/src/test/ui/parser/inner-attr-in-trait-def.rs
new file mode 100644
index 00000000000..8dba6b362cd
--- /dev/null
+++ b/src/test/ui/parser/inner-attr-in-trait-def.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![deny(non_camel_case_types)]
+
+fn main() {}
+
+trait foo_bar {
+    #![allow(non_camel_case_types)]
+}
diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs
index 2158a2fd6c1..982a6be23ac 100644
--- a/src/test/ui/parser/issue-19398.rs
+++ b/src/test/ui/parser/issue-19398.rs
@@ -1,5 +1,6 @@
 trait T {
-    extern "Rust" unsafe fn foo(); //~ ERROR expected one of `async`, `const`
+    //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration
+    extern "Rust" unsafe fn foo();
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr
index 201a6b2d66a..2bd6ac3a4b3 100644
--- a/src/test/ui/parser/issue-19398.stderr
+++ b/src/test/ui/parser/issue-19398.stderr
@@ -1,10 +1,11 @@
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `extern`
-  --> $DIR/issue-19398.rs:2:5
+error: missing `fn`, `type`, or `const` for associated-item declaration
+  --> $DIR/issue-19398.rs:1:10
    |
-LL | trait T {
-   |          - expected one of 10 possible tokens
-LL |     extern "Rust" unsafe fn foo();
-   |     ^^^^^^ unexpected token
+LL |   trait T {
+   |  __________^
+LL | |
+LL | |     extern "Rust" unsafe fn foo();
+   | |____^ missing `fn`, `type`, or `const`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-20711-2.rs b/src/test/ui/parser/issue-20711-2.rs
index 0063a334182..168c7e76162 100644
--- a/src/test/ui/parser/issue-20711-2.rs
+++ b/src/test/ui/parser/issue-20711-2.rs
@@ -4,6 +4,7 @@ impl Foo {
     fn foo() {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
+    //~^ ERROR expected item after attributes
+}
 
 fn main() {}
diff --git a/src/test/ui/parser/issue-20711-2.stderr b/src/test/ui/parser/issue-20711-2.stderr
index ee484890fad..10ef31584de 100644
--- a/src/test/ui/parser/issue-20711-2.stderr
+++ b/src/test/ui/parser/issue-20711-2.stderr
@@ -1,10 +1,8 @@
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
-  --> $DIR/issue-20711-2.rs:7:1
+error: expected item after attributes
+  --> $DIR/issue-20711-2.rs:6:5
    |
 LL |     #[stable(feature = "rust1", since = "1.0.0")]
-   |                                                  - expected one of 9 possible tokens
-LL | }
-   | ^ unexpected token
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-20711.rs b/src/test/ui/parser/issue-20711.rs
index dc216167b8a..020bb79d6e7 100644
--- a/src/test/ui/parser/issue-20711.rs
+++ b/src/test/ui/parser/issue-20711.rs
@@ -2,6 +2,7 @@ struct Foo;
 
 impl Foo {
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
+    //~^ ERROR expected item after attributes
+}
 
 fn main() {}
diff --git a/src/test/ui/parser/issue-20711.stderr b/src/test/ui/parser/issue-20711.stderr
index 152c9f1c689..66768de5694 100644
--- a/src/test/ui/parser/issue-20711.stderr
+++ b/src/test/ui/parser/issue-20711.stderr
@@ -1,10 +1,8 @@
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
-  --> $DIR/issue-20711.rs:5:1
+error: expected item after attributes
+  --> $DIR/issue-20711.rs:4:5
    |
 LL |     #[stable(feature = "rust1", since = "1.0.0")]
-   |                                                  - expected one of 9 possible tokens
-LL | }
-   | ^ unexpected token
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 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 1a97f54160b..25c1efe35ae 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 `}`, found `...`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, `}`, or identifier, found `...`
   --> $DIR/issue-32446.rs:4:11
    |
 LL | trait T { ... }
-   |           ^^^ expected one of 10 possible tokens
+   |           ^^^ expected one of 11 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 0e191eb7e0a..327bc65818f 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`, or `unsafe`, found `}`
+error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, `unsafe`, or identifier, found `}`
   --> $DIR/issue-41155.rs:5:1
    |
 LL |     pub
-   |        - expected one of 8 possible tokens
+   |        - expected one of 9 possible tokens
 LL | }
    | ^ unexpected token
 
diff --git a/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr b/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr
index 00f6652b311..8a44ee761ed 100644
--- a/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr
+++ b/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr
@@ -7,10 +7,10 @@ LL | #[Ѕ
    |  unclosed delimiter
 
 error: expected item after attributes
-  --> $DIR/issue-58094-missing-right-square-bracket.rs:4:4
+  --> $DIR/issue-58094-missing-right-square-bracket.rs:4:1
    |
 LL | #[Ѕ
-   |    ^
+   | ^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/macro/pub-item-macro.rs b/src/test/ui/parser/macro/pub-item-macro.rs
index bae90227c62..f5f8a01e6a4 100644
--- a/src/test/ui/parser/macro/pub-item-macro.rs
+++ b/src/test/ui/parser/macro/pub-item-macro.rs
@@ -1,12 +1,15 @@
 // Issue #14660
 
-macro_rules! priv_x { () => {
-    static x: u32 = 0;
-}}
+macro_rules! priv_x {
+    () => {
+        static x: u32 = 0;
+    };
+}
 
 macro_rules! pub_x { () => {
     pub priv_x!(); //~ ERROR can't qualify macro invocation with `pub`
-    //~^ HELP try adjusting the macro to put `pub` inside the invocation
+    //~^ HELP remove the visibility
+    //~| HELP try adjusting the macro to put `pub` inside the invocation
 }}
 
 mod foo {
diff --git a/src/test/ui/parser/macro/pub-item-macro.stderr b/src/test/ui/parser/macro/pub-item-macro.stderr
index 49644cf6a0e..4ff96532e03 100644
--- a/src/test/ui/parser/macro/pub-item-macro.stderr
+++ b/src/test/ui/parser/macro/pub-item-macro.stderr
@@ -1,8 +1,8 @@
 error: can't qualify macro invocation with `pub`
-  --> $DIR/pub-item-macro.rs:8:5
+  --> $DIR/pub-item-macro.rs:10:5
    |
 LL |     pub priv_x!();
-   |     ^^^
+   |     ^^^ help: remove the visibility
 ...
 LL |     pub_x!();
    |     --------- in this macro invocation
@@ -11,16 +11,16 @@ LL |     pub_x!();
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0603]: static `x` is private
-  --> $DIR/pub-item-macro.rs:17:23
+  --> $DIR/pub-item-macro.rs:20:23
    |
 LL |     let y: u32 = foo::x;
    |                       ^ this static is private
    |
 note: the static `x` is defined here
-  --> $DIR/pub-item-macro.rs:4:5
+  --> $DIR/pub-item-macro.rs:5:9
    |
-LL |     static x: u32 = 0;
-   |     ^^^^^^^^^^^^^^^^^^
+LL |         static x: u32 = 0;
+   |         ^^^^^^^^^^^^^^^^^^
 ...
 LL |     pub_x!();
    |     --------- in this macro invocation
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 5a89b5b936f..9d05e85bcc0 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`, or `unsafe`, found `2`
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or identifier, found `2`
   --> $DIR/trait-non-item-macros.rs:2:19
    |
 LL |     ($a:expr) => ($a)
-   |                   ^^ expected one of 9 possible tokens
+   |                   ^^ expected one of 10 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 9f02a7a997b..592215030f5 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
@@ -1,12 +1,14 @@
+fn main() {}
+
 impl T for () { //~ ERROR cannot find trait `T` in this scope
 
 fn foo(&self) {}
+//~^ ERROR missing `fn`, `type`, or `const`
 
-trait T { //~ ERROR expected one of
+trait T {
     fn foo(&self);
 }
 
 pub(crate) struct Bar<T>();
 
-fn main() {}
 //~ ERROR this file contains an unclosed delimiter
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 a23cfeac58f..1ec54525105 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
@@ -1,5 +1,5 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/missing-close-brace-in-impl-trait.rs:12:52
+  --> $DIR/missing-close-brace-in-impl-trait.rs:14:52
    |
 LL | impl T for () {
    |               - unclosed delimiter
@@ -7,23 +7,18 @@ LL | impl T for () {
 LL |
    |                                                    ^
 
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `trait`
-  --> $DIR/missing-close-brace-in-impl-trait.rs:5:1
+error: missing `fn`, `type`, or `const` for associated-item declaration
+  --> $DIR/missing-close-brace-in-impl-trait.rs:5:17
    |
-LL | impl T for () {
-   |               - unclosed delimiter
-LL | 
-LL | fn foo(&self) {}
-   |                 -
-   |                 |
-   |                 expected one of 10 possible tokens
-   |                 help: `}` may belong here
-LL | 
-LL | trait T {
-   | ^^^^^ unexpected token
+LL |   fn foo(&self) {}
+   |  _________________^
+LL | |
+LL | |
+LL | | trait T {
+   | |_ missing `fn`, `type`, or `const`
 
 error[E0405]: cannot find trait `T` in this scope
-  --> $DIR/missing-close-brace-in-impl-trait.rs:1:6
+  --> $DIR/missing-close-brace-in-impl-trait.rs:3:6
    |
 LL | impl T for () {
    |      ^ not found in this scope
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 5ec5d45bbe7..077e3347194 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 expected one of
+//~^ ERROR missing `fn`, `type`, or `const`
 
 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 21364012782..1bb153c461d 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: expected one of `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct`
-  --> $DIR/missing-close-brace-in-trait.rs:5:12
+error: missing `fn`, `type`, or `const` for associated-item declaration
+  --> $DIR/missing-close-brace-in-trait.rs:5:11
    |
 LL | pub(crate) struct Bar<T>();
-   |            ^^^^^^ expected one of 7 possible tokens
+   |           ^ missing `fn`, `type`, or `const`
 
 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/pub-method-macro.rs b/src/test/ui/parser/pub-method-macro.rs
index f04af1a0d65..0183bdcf622 100644
--- a/src/test/ui/parser/pub-method-macro.rs
+++ b/src/test/ui/parser/pub-method-macro.rs
@@ -15,7 +15,8 @@ mod bleh {
 
     impl S {
         pub defn!(f); //~ ERROR can't qualify macro invocation with `pub`
-        //~^ HELP try adjusting the macro to put `pub` inside the invocation
+        //~^ HELP remove the visibility
+        //~| HELP try adjusting the macro to put `pub` inside the invocation
     }
 }
 
diff --git a/src/test/ui/parser/pub-method-macro.stderr b/src/test/ui/parser/pub-method-macro.stderr
index 7b0fe493461..7c7a909267a 100644
--- a/src/test/ui/parser/pub-method-macro.stderr
+++ b/src/test/ui/parser/pub-method-macro.stderr
@@ -2,7 +2,7 @@ error: can't qualify macro invocation with `pub`
   --> $DIR/pub-method-macro.rs:17:9
    |
 LL |         pub defn!(f);
-   |         ^^^
+   |         ^^^ help: remove the visibility
    |
    = help: try adjusting the macro to put `pub` inside the invocation
 
diff --git a/src/test/ui/parser/removed-syntax-static-fn.rs b/src/test/ui/parser/removed-syntax-static-fn.rs
index 0caddb9855d..9e12222f3fd 100644
--- a/src/test/ui/parser/removed-syntax-static-fn.rs
+++ b/src/test/ui/parser/removed-syntax-static-fn.rs
@@ -1,8 +1,8 @@
 struct S;
 
 impl S {
+    //~^ ERROR missing `fn`, `type`, or `const` for associated-item declaration
     static fn f() {}
-    //~^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`,
 }
 
 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 dfadefee23c..5edf88026fb 100644
--- a/src/test/ui/parser/removed-syntax-static-fn.stderr
+++ b/src/test/ui/parser/removed-syntax-static-fn.stderr
@@ -1,10 +1,11 @@
-error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `static`
-  --> $DIR/removed-syntax-static-fn.rs:4:5
+error: missing `fn`, `type`, or `const` for associated-item declaration
+  --> $DIR/removed-syntax-static-fn.rs:3:9
    |
-LL | impl S {
-   |         - expected one of 10 possible tokens
-LL |     static fn f() {}
-   |     ^^^^^^ unexpected token
+LL |   impl S {
+   |  _________^
+LL | |
+LL | |     static fn f() {}
+   | |____^ missing `fn`, `type`, or `const`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pub/pub-restricted-error-fn.rs b/src/test/ui/pub/pub-restricted-error-fn.rs
index 56ee02f517c..3f8904fbe79 100644
--- a/src/test/ui/pub/pub-restricted-error-fn.rs
+++ b/src/test/ui/pub/pub-restricted-error-fn.rs
@@ -1,3 +1,2 @@
-#![feature(pub_restricted)]
-
 pub(crate) () fn foo() {} //~ unmatched visibility
+//~^ ERROR expected item, found `(`
diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr
index fcff5334890..c0168b02da6 100644
--- a/src/test/ui/pub/pub-restricted-error-fn.stderr
+++ b/src/test/ui/pub/pub-restricted-error-fn.stderr
@@ -1,8 +1,16 @@
-error: unmatched visibility `pub`
-  --> $DIR/pub-restricted-error-fn.rs:3:10
+error: unmatched visibility `pub(crate)`
+  --> $DIR/pub-restricted-error-fn.rs:1:1
    |
 LL | pub(crate) () fn foo() {}
-   |          ^
+   | ^^^^^^^^^^ the unmatched visibility
+   |
+   = help: you likely meant to define an item, e.g., `pub(crate) fn foo() {}`
+
+error: expected item, found `(`
+  --> $DIR/pub-restricted-error-fn.rs:1:12
+   |
+LL | pub(crate) () fn foo() {}
+   |            ^ expected item
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs
index 023f5aa1e28..226779ad0c0 100644
--- a/src/tools/rustbook/src/main.rs
+++ b/src/tools/rustbook/src/main.rs
@@ -115,6 +115,8 @@ pub fn linkcheck(
                     eprintln!("Timeout for link `{}`", link.link.uri);
                 } else if err.is_server_error() {
                     eprintln!("Server error for link `{}`", link.link.uri);
+                } else if !err.is_http() {
+                    eprintln!("Non-HTTP-related error for link: {} {}", link.link.uri, err);
                 } else {
                     is_real_error = true;
                 }