about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-02-06 15:43:00 +0000
committerbors <bors@rust-lang.org>2020-02-06 15:43:00 +0000
commit442ae7f04026c215a03b155eaaf9cde8bb5cf02a (patch)
treebf7472e8278e4303ee33b50811461f249e019efd
parent1f8df2508f2772d83011f0f651de86181123e519 (diff)
parent1ad674afcf37f1c8fe39317dc65d1aafc37f8694 (diff)
downloadrust-442ae7f04026c215a03b155eaaf9cde8bb5cf02a.tar.gz
rust-442ae7f04026c215a03b155eaaf9cde8bb5cf02a.zip
Auto merge of #68893 - Dylan-DPC:rollup-3f2421a, r=Dylan-DPC
Rollup of 9 pull requests

Successful merges:

 - #68691 (Remove `RefCell` usage from `ObligationForest`.)
 - #68751 (Implement `unused_parens` for `const` and `static` items)
 - #68788 (Towards unified `fn` grammar)
 - #68837 (Make associated item collection a query)
 - #68842 (or_patterns: add regression test for #68785)
 - #68844 (use def_path_str for missing_debug_impls message)
 - #68845 (stop using BytePos for computing spans in librustc_parse/parser/mod.rs)
 - #68869 (clean up E0271 explanation)
 - #68880 (Forbid using `0` as issue number)

Failed merges:

r? @ghost
-rw-r--r--src/librustc/query/mod.rs5
-rw-r--r--src/librustc/ty/mod.rs31
-rw-r--r--src/librustc_ast_lowering/item.rs48
-rw-r--r--src/librustc_ast_lowering/lib.rs28
-rw-r--r--src/librustc_ast_passes/ast_validation.rs336
-rw-r--r--src/librustc_ast_passes/feature_gate.rs69
-rw-r--r--src/librustc_ast_passes/node_count.rs8
-rw-r--r--src/librustc_ast_pretty/pprust.rs64
-rw-r--r--src/librustc_attr/builtin.rs39
-rw-r--r--src/librustc_builtin_macros/global_allocator.rs2
-rw-r--r--src/librustc_builtin_macros/test_harness.rs2
-rw-r--r--src/librustc_data_structures/obligation_forest/mod.rs10
-rw-r--r--src/librustc_error_codes/error_codes/E0271.md12
-rw-r--r--src/librustc_expand/base.rs6
-rw-r--r--src/librustc_expand/expand.rs38
-rw-r--r--src/librustc_lint/builtin.rs57
-rw-r--r--src/librustc_lint/early.rs39
-rw-r--r--src/librustc_lint/passes.rs3
-rw-r--r--src/librustc_lint/unused.rs8
-rw-r--r--src/librustc_parse/parser/diagnostics.rs50
-rw-r--r--src/librustc_parse/parser/expr.rs3
-rw-r--r--src/librustc_parse/parser/item.rs122
-rw-r--r--src/librustc_parse/parser/mod.rs39
-rw-r--r--src/librustc_parse/parser/path.rs3
-rw-r--r--src/librustc_parse/parser/stmt.rs2
-rw-r--r--src/librustc_parse/parser/ty.rs61
-rw-r--r--src/librustc_passes/hir_stats.rs25
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs21
-rw-r--r--src/librustc_resolve/def_collector.rs39
-rw-r--r--src/librustc_resolve/late.rs54
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs9
-rw-r--r--src/librustc_save_analysis/lib.rs4
-rw-r--r--src/librustc_save_analysis/sig.rs3
-rw-r--r--src/librustc_ty/ty.rs9
-rw-r--r--src/libsyntax/ast.rs15
-rw-r--r--src/libsyntax/mut_visit.rs7
-rw-r--r--src/libsyntax/visit.rs136
-rw-r--r--src/test/ui/extern/extern-ffi-fn-with-body.rs2
-rw-r--r--src/test/ui/extern/extern-ffi-fn-with-body.stderr10
-rw-r--r--src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs4
-rw-r--r--src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr12
-rw-r--r--src/test/ui/issues/issue-39616.rs3
-rw-r--r--src/test/ui/issues/issue-39616.stderr4
-rw-r--r--src/test/ui/lint/lint-unnecessary-parens.rs3
-rw-r--r--src/test/ui/lint/lint-unnecessary-parens.stderr36
-rw-r--r--src/test/ui/macros/issue-54441.stderr4
-rw-r--r--src/test/ui/missing_debug_impls.rs4
-rw-r--r--src/test/ui/missing_debug_impls.stderr4
-rw-r--r--src/test/ui/no-patterns-in-args-2.rs4
-rw-r--r--src/test/ui/no-patterns-in-args-2.stderr6
-rw-r--r--src/test/ui/no-patterns-in-args-macro.rs6
-rw-r--r--src/test/ui/no-patterns-in-args-macro.stderr4
-rw-r--r--src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs14
-rw-r--r--src/test/ui/parser/duplicate-visibility.rs2
-rw-r--r--src/test/ui/parser/duplicate-visibility.stderr4
-rw-r--r--src/test/ui/parser/fn-body-optional-semantic-fail.rs27
-rw-r--r--src/test/ui/parser/fn-body-optional-semantic-fail.stderr40
-rw-r--r--src/test/ui/parser/fn-body-optional-syntactic-pass.rs31
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.rs57
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.stderr136
-rw-r--r--src/test/ui/parser/fn-header-syntactic-pass.rs55
-rw-r--r--src/test/ui/parser/issue-24780.rs2
-rw-r--r--src/test/ui/parser/issue-24780.stderr4
-rw-r--r--src/test/ui/parser/issue-63135.rs2
-rw-r--r--src/test/ui/parser/issue-63135.stderr8
-rw-r--r--src/test/ui/parser/issue-68730.stderrbin957 -> 956 bytes
-rw-r--r--src/test/ui/parser/issue-68788-in-trait-item-propagation.rs21
-rw-r--r--src/test/ui/parser/missing_right_paren.rs2
-rw-r--r--src/test/ui/parser/missing_right_paren.stderr8
-rw-r--r--src/test/ui/parser/no-const-fn-in-extern-block.rs4
-rw-r--r--src/test/ui/parser/no-const-fn-in-extern-block.stderr21
-rw-r--r--src/test/ui/parser/not-a-pred.stderr4
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity-2.rs3
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr2
-rw-r--r--src/test/ui/super-fast-paren-parsing.rs1
75 files changed, 1205 insertions, 756 deletions
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 37d5e23535b..228271e0c4c 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -310,6 +310,11 @@ rustc_queries! {
         /// Maps from a trait item to the trait item "descriptor".
         query associated_item(_: DefId) -> ty::AssocItem {}
 
+        /// Collects the associated items defined on a trait or impl.
+        query associated_items(key: DefId) -> ty::AssocItemsIterator<'tcx> {
+            desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
+        }
+
         query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {}
         query impl_polarity(_: DefId) -> ty::ImplPolarity {}
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1b3e42447c4..2538322431e 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2743,19 +2743,6 @@ impl<'tcx> TyCtxt<'tcx> {
         variant.fields.iter().position(|field| self.hygienic_eq(ident, field.ident, variant.def_id))
     }
 
-    pub fn associated_items(self, def_id: DefId) -> AssocItemsIterator<'tcx> {
-        // Ideally, we would use `-> impl Iterator` here, but it falls
-        // afoul of the conservative "capture [restrictions]" we put
-        // in place, so we use a hand-written iterator.
-        //
-        // [restrictions]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999
-        AssocItemsIterator {
-            tcx: self,
-            def_ids: self.associated_item_def_ids(def_id),
-            next_index: 0,
-        }
-    }
-
     /// Returns `true` if the impls are the same polarity and the trait either
     /// has no items or is annotated #[marker] and prevents item overrides.
     pub fn impls_are_allowed_to_overlap(
@@ -2987,20 +2974,22 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-#[derive(Clone)]
+#[derive(Copy, Clone, HashStable)]
 pub struct AssocItemsIterator<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    def_ids: &'tcx [DefId],
-    next_index: usize,
+    pub items: &'tcx [AssocItem],
 }
 
-impl Iterator for AssocItemsIterator<'_> {
+impl<'tcx> Iterator for AssocItemsIterator<'tcx> {
     type Item = AssocItem;
 
+    #[inline]
     fn next(&mut self) -> Option<AssocItem> {
-        let def_id = self.def_ids.get(self.next_index)?;
-        self.next_index += 1;
-        Some(self.tcx.associated_item(*def_id))
+        if let Some((first, rest)) = self.items.split_first() {
+            self.items = rest;
+            Some(*first)
+        } else {
+            None
+        }
     }
 }
 
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index e27f2bdb8d2..dab950e23f6 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -14,7 +14,7 @@ use rustc_target::spec::abi;
 use syntax::ast::*;
 use syntax::attr;
 use syntax::node_id::NodeMap;
-use syntax::visit::{self, Visitor};
+use syntax::visit::{self, AssocCtxt, Visitor};
 
 use log::debug;
 use smallvec::{smallvec, SmallVec};
@@ -81,25 +81,23 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
         }
     }
 
-    fn visit_trait_item(&mut self, item: &'a AssocItem) {
-        self.lctx.with_hir_id_owner(item.id, |lctx| {
-            let hir_item = lctx.lower_trait_item(item);
-            let id = hir::TraitItemId { hir_id: hir_item.hir_id };
-            lctx.trait_items.insert(id, hir_item);
-            lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id);
+    fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
+        self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
+            AssocCtxt::Trait => {
+                let hir_item = lctx.lower_trait_item(item);
+                let id = hir::TraitItemId { hir_id: hir_item.hir_id };
+                lctx.trait_items.insert(id, hir_item);
+                lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id);
+            }
+            AssocCtxt::Impl => {
+                let hir_item = lctx.lower_impl_item(item);
+                let id = hir::ImplItemId { hir_id: hir_item.hir_id };
+                lctx.impl_items.insert(id, hir_item);
+                lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id);
+            }
         });
 
-        visit::walk_trait_item(self, item);
-    }
-
-    fn visit_impl_item(&mut self, item: &'a AssocItem) {
-        self.lctx.with_hir_id_owner(item.id, |lctx| {
-            let hir_item = lctx.lower_impl_item(item);
-            let id = hir::ImplItemId { hir_id: hir_item.hir_id };
-            lctx.impl_items.insert(id, hir_item);
-            lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id);
-        });
-        visit::walk_impl_item(self, item);
+        visit::walk_assoc_item(self, item, ctxt);
     }
 }
 
@@ -299,20 +297,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     // `impl Future<Output = T>` here because lower_body
                     // only cares about the input argument patterns in the function
                     // declaration (decl), not the return types.
+                    let asyncness = header.asyncness.node;
                     let body_id =
-                        this.lower_maybe_async_body(span, &decl, header.asyncness.node, Some(body));
+                        this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
 
                     let (generics, decl) = this.add_in_band_defs(
                         generics,
                         fn_def_id,
                         AnonymousLifetimeMode::PassThrough,
                         |this, idty| {
-                            this.lower_fn_decl(
-                                &decl,
-                                Some((fn_def_id, idty)),
-                                true,
-                                header.asyncness.node.opt_return_id(),
-                            )
+                            let ret_id = asyncness.opt_return_id();
+                            this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id)
                         },
                     );
                     let sig = hir::FnSig { decl, header: this.lower_fn_header(header) };
@@ -658,7 +653,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             ident: i.ident,
             attrs: self.lower_attrs(&i.attrs),
             kind: match i.kind {
-                ForeignItemKind::Fn(ref fdec, ref generics) => {
+                ForeignItemKind::Fn(ref sig, ref generics, _) => {
+                    let fdec = &sig.decl;
                     let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
                         generics,
                         def_id,
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index c3e96a31e40..5816a64fca5 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -32,6 +32,7 @@
 
 #![feature(array_value_iter)]
 #![feature(crate_visibility_modifier)]
+#![recursion_limit = "256"]
 
 use rustc::arena::Arena;
 use rustc::dep_graph::DepGraph;
@@ -63,7 +64,7 @@ use syntax::attr;
 use syntax::node_id::NodeMap;
 use syntax::token::{self, Nonterminal, Token};
 use syntax::tokenstream::{TokenStream, TokenTree};
-use syntax::visit::{self, Visitor};
+use syntax::visit::{self, AssocCtxt, Visitor};
 use syntax::walk_list;
 
 use log::{debug, trace};
@@ -485,25 +486,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 });
             }
 
-            fn visit_trait_item(&mut self, item: &'tcx AssocItem) {
+            fn visit_assoc_item(&mut self, item: &'tcx AssocItem, ctxt: AssocCtxt) {
                 self.lctx.allocate_hir_id_counter(item.id);
-
-                match item.kind {
-                    AssocItemKind::Fn(_, None) => {
-                        // Ignore patterns in trait methods without bodies
-                        self.with_hir_id_owner(None, |this| visit::walk_trait_item(this, item));
-                    }
-                    _ => self.with_hir_id_owner(Some(item.id), |this| {
-                        visit::walk_trait_item(this, item);
-                    }),
-                }
-            }
-
-            fn visit_impl_item(&mut self, item: &'tcx AssocItem) {
-                self.lctx.allocate_hir_id_counter(item.id);
-                self.with_hir_id_owner(Some(item.id), |this| {
-                    visit::walk_impl_item(this, item);
-                });
+                let owner = match (&item.kind, ctxt) {
+                    // Ignore patterns in trait methods without bodies.
+                    (AssocItemKind::Fn(_, None), AssocCtxt::Trait) => None,
+                    _ => Some(item.id),
+                };
+                self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt));
             }
 
             fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index cb64e2e95bf..79ed7f234f7 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -8,7 +8,7 @@
 
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{struct_span_err, Applicability, FatalError};
+use rustc_errors::{error_code, struct_span_err, Applicability, FatalError};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
 use rustc_session::lint::LintBuffer;
@@ -20,7 +20,7 @@ use std::mem;
 use syntax::ast::*;
 use syntax::attr;
 use syntax::expand::is_proc_macro_attr;
-use syntax::visit::{self, Visitor};
+use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use syntax::walk_list;
 
 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
@@ -49,6 +49,13 @@ impl BoundContext {
 
 struct AstValidator<'a> {
     session: &'a Session,
+
+    /// The span of the `extern` in an `extern { ... }` block, if any.
+    extern_mod: Option<&'a Item>,
+
+    /// Are we inside a trait impl?
+    in_trait_impl: bool,
+
     has_proc_macro_decls: bool,
 
     /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
@@ -74,6 +81,12 @@ struct AstValidator<'a> {
 }
 
 impl<'a> AstValidator<'a> {
+    fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.in_trait_impl, is_in);
+        f(self);
+        self.in_trait_impl = old;
+    }
+
     fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.is_impl_trait_banned, true);
         f(self);
@@ -389,13 +402,9 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
-        if body.is_some() {
-            return;
-        }
-
+    fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
         self.err_handler()
-            .struct_span_err(sp, &format!("associated {} in `impl` without body", ctx))
+            .struct_span_err(sp, msg)
             .span_suggestion(
                 self.session.source_map().end_point(sp),
                 &format!("provide a definition for the {}", ctx),
@@ -405,6 +414,13 @@ impl<'a> AstValidator<'a> {
             .emit();
     }
 
+    fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
+        if body.is_none() {
+            let msg = format!("associated {} in `impl` without body", ctx);
+            self.error_item_without_body(sp, ctx, &msg, sugg);
+        }
+    }
+
     fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
         let span = match bounds {
             [] => return,
@@ -416,8 +432,71 @@ impl<'a> AstValidator<'a> {
             .emit();
     }
 
-    fn check_c_varadic_type(&self, decl: &FnDecl) {
-        for Param { ty, span, .. } in &decl.inputs {
+    /// An `fn` in `extern { ... }` cannot have a body `{ ... }`.
+    fn check_foreign_fn_bodyless(&self, ident: Ident, body: Option<&Block>) {
+        let body = match body {
+            None => return,
+            Some(body) => body,
+        };
+        self.err_handler()
+            .struct_span_err(ident.span, "incorrect function inside `extern` block")
+            .span_label(ident.span, "cannot have a body")
+            .span_suggestion(
+                body.span,
+                "remove the invalid body",
+                ";".to_string(),
+                Applicability::MaybeIncorrect,
+            )
+            .help(
+                "you might have meant to write a function accessible through FFI, \
+                which can be done by writing `extern fn` outside of the `extern` block",
+            )
+            .span_label(
+                self.current_extern_span(),
+                "`extern` blocks define existing foreign functions and functions \
+                inside of them cannot have a body",
+            )
+            .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
+            .emit();
+    }
+
+    fn current_extern_span(&self) -> Span {
+        self.session.source_map().def_span(self.extern_mod.unwrap().span)
+    }
+
+    /// An `fn` in `extern { ... }` cannot have qualfiers, e.g. `async fn`.
+    fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
+        if header.has_qualifiers() {
+            self.err_handler()
+                .struct_span_err(ident.span, "functions in `extern` blocks cannot have qualifiers")
+                .span_label(self.current_extern_span(), "in this `extern` block")
+                .span_suggestion(
+                    span.until(ident.span.shrink_to_lo()),
+                    "remove the qualifiers",
+                    "fn ".to_string(),
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+        }
+    }
+
+    /// Reject C-varadic type unless the function is foreign,
+    /// or free and `unsafe extern "C"` semantically.
+    fn check_c_varadic_type(&self, fk: FnKind<'a>) {
+        match (fk.ctxt(), fk.header()) {
+            (Some(FnCtxt::Foreign), _) => return,
+            (Some(FnCtxt::Free), Some(header)) => match header.ext {
+                Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
+                    if header.unsafety == Unsafety::Unsafe =>
+                {
+                    return;
+                }
+                _ => {}
+            },
+            _ => {}
+        };
+
+        for Param { ty, span, .. } in &fk.decl().inputs {
             if let TyKind::CVarArgs = ty.kind {
                 self.err_handler()
                     .struct_span_err(
@@ -428,6 +507,24 @@ impl<'a> AstValidator<'a> {
             }
         }
     }
+
+    /// We currently do not permit const generics in `const fn`,
+    /// as this is tantamount to allowing compile-time dependent typing.
+    ///
+    /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
+    /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
+    fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
+        if sig.header.constness.node == Constness::Const {
+            // Look for const generics and error if we find any.
+            for param in &generics.params {
+                if let GenericParamKind::Const { .. } = param.kind {
+                    self.err_handler()
+                        .struct_span_err(span, "const parameters are not permitted in `const fn`")
+                        .emit();
+                }
+            }
+        }
+    }
 }
 
 enum GenericPosition {
@@ -532,9 +629,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
     fn visit_expr(&mut self, expr: &'a Expr) {
         match &expr.kind {
-            ExprKind::Closure(_, _, _, fn_decl, _, _) => {
-                self.check_fn_decl(fn_decl, SelfSemantic::No);
-            }
             ExprKind::InlineAsm(..) if !self.session.target.target.options.allow_asm => {
                 struct_span_err!(
                     self.session,
@@ -647,31 +741,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 generics: _,
                 of_trait: Some(_),
                 ref self_ty,
-                ref items,
+                items: _,
             } => {
-                self.invalid_visibility(&item.vis, None);
-                if let TyKind::Err = self_ty.kind {
-                    self.err_handler()
-                        .struct_span_err(item.span, "`impl Trait for .. {}` is an obsolete syntax")
-                        .help("use `auto trait Trait {}` instead")
+                self.with_in_trait_impl(true, |this| {
+                    this.invalid_visibility(&item.vis, None);
+                    if let TyKind::Err = self_ty.kind {
+                        this.err_handler()
+                            .struct_span_err(
+                                item.span,
+                                "`impl Trait for .. {}` is an obsolete syntax",
+                            )
+                            .help("use `auto trait Trait {}` instead")
+                            .emit();
+                    }
+                    if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
+                        struct_span_err!(
+                            this.session,
+                            item.span,
+                            E0198,
+                            "negative impls cannot be unsafe"
+                        )
                         .emit();
-                }
-                if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
-                    struct_span_err!(
-                        self.session,
-                        item.span,
-                        E0198,
-                        "negative impls cannot be unsafe"
-                    )
-                    .emit();
-                }
-                for impl_item in items {
-                    self.invalid_visibility(&impl_item.vis, None);
-                    if let AssocItemKind::Fn(ref sig, _) = impl_item.kind {
-                        self.check_trait_fn_not_const(sig.header.constness);
-                        self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness.node);
                     }
-                }
+
+                    visit::walk_item(this, item);
+                });
+                return; // Avoid visiting again.
             }
             ItemKind::Impl {
                 unsafety,
@@ -712,40 +807,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         .emit();
                 }
             }
-            ItemKind::Fn(ref sig, ref generics, _) => {
-                self.visit_fn_header(&sig.header);
-                self.check_fn_decl(&sig.decl, SelfSemantic::No);
-                // We currently do not permit const generics in `const fn`, as
-                // this is tantamount to allowing compile-time dependent typing.
-                if sig.header.constness.node == Constness::Const {
-                    // Look for const generics and error if we find any.
-                    for param in &generics.params {
-                        match param.kind {
-                            GenericParamKind::Const { .. } => {
-                                self.err_handler()
-                                    .struct_span_err(
-                                        item.span,
-                                        "const parameters are not permitted in `const fn`",
-                                    )
-                                    .emit();
-                            }
-                            _ => {}
-                        }
-                    }
-                }
-                // Reject C-varadic type unless the function is `unsafe extern "C"` semantically.
-                match sig.header.ext {
-                    Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. })
-                    | Extern::Implicit
-                        if sig.header.unsafety == Unsafety::Unsafe => {}
-                    _ => self.check_c_varadic_type(&sig.decl),
+            ItemKind::Fn(ref sig, ref generics, ref body) => {
+                self.check_const_fn_const_generic(item.span, sig, generics);
+
+                if body.is_none() {
+                    let msg = "free function without a body";
+                    self.error_item_without_body(item.span, "function", msg, " { <body> }");
                 }
             }
-            ItemKind::ForeignMod(..) => {
+            ItemKind::ForeignMod(_) => {
+                let old_item = mem::replace(&mut self.extern_mod, Some(item));
                 self.invalid_visibility(
                     &item.vis,
                     Some("place qualifiers on individual foreign items instead"),
                 );
+                visit::walk_item(self, item);
+                self.extern_mod = old_item;
+                return; // Avoid visiting again.
             }
             ItemKind::Enum(ref def, _) => {
                 for variant in &def.variants {
@@ -796,7 +874,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.with_bound_context(BoundContext::TraitBounds, |this| {
                     walk_list!(this, visit_param_bound, bounds);
                 });
-                walk_list!(self, visit_trait_item, trait_items);
+                walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return;
             }
@@ -820,19 +898,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
-        match fi.kind {
-            ForeignItemKind::Fn(ref decl, _) => {
-                self.check_fn_decl(decl, SelfSemantic::No);
-                Self::check_decl_no_pat(decl, |span, _| {
-                    struct_span_err!(
-                        self.session,
-                        span,
-                        E0130,
-                        "patterns aren't allowed in foreign function declarations"
-                    )
-                    .span_label(span, "pattern not allowed in foreign function")
-                    .emit();
-                });
+        match &fi.kind {
+            ForeignItemKind::Fn(sig, _, body) => {
+                self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
+                self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
             }
             ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
         }
@@ -1011,67 +1080,84 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         })
     }
 
-    fn visit_impl_item(&mut self, ii: &'a AssocItem) {
-        match &ii.kind {
-            AssocItemKind::Const(_, body) => {
-                self.check_impl_item_provided(ii.span, body, "constant", " = <expr>;");
-            }
-            AssocItemKind::Fn(_, body) => {
-                self.check_impl_item_provided(ii.span, body, "function", " { <body> }");
-            }
-            AssocItemKind::TyAlias(bounds, body) => {
-                self.check_impl_item_provided(ii.span, body, "type", " = <type>;");
-                self.check_impl_assoc_type_no_bounds(bounds);
-            }
-            _ => {}
+    fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
+        // Only associated `fn`s can have `self` parameters.
+        let self_semantic = match fk.ctxt() {
+            Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
+            _ => SelfSemantic::No,
+        };
+        self.check_fn_decl(fk.decl(), self_semantic);
+
+        self.check_c_varadic_type(fk);
+
+        // Functions without bodies cannot have patterns.
+        if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
+            Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
+                let (code, msg, label) = match ctxt {
+                    FnCtxt::Foreign => (
+                        error_code!(E0130),
+                        "patterns aren't allowed in foreign function declarations",
+                        "pattern not allowed in foreign function",
+                    ),
+                    _ => (
+                        error_code!(E0642),
+                        "patterns aren't allowed in functions without bodies",
+                        "pattern not allowed in function without body",
+                    ),
+                };
+                if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
+                    self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
+                } else {
+                    self.err_handler()
+                        .struct_span_err(span, msg)
+                        .span_label(span, label)
+                        .code(code)
+                        .emit();
+                }
+            });
         }
-        visit::walk_impl_item(self, ii);
+
+        visit::walk_fn(self, fk, span);
     }
 
-    fn visit_trait_item(&mut self, ti: &'a AssocItem) {
-        self.invalid_visibility(&ti.vis, None);
-        self.check_defaultness(ti.span, ti.defaultness);
-
-        if let AssocItemKind::Fn(sig, block) = &ti.kind {
-            self.check_trait_fn_not_async(ti.span, sig.header.asyncness.node);
-            self.check_trait_fn_not_const(sig.header.constness);
-            if block.is_none() {
-                Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
-                    if mut_ident {
-                        self.lint_buffer.buffer_lint(
-                            PATTERNS_IN_FNS_WITHOUT_BODY,
-                            ti.id,
-                            span,
-                            "patterns aren't allowed in methods without bodies",
-                        );
-                    } else {
-                        struct_span_err!(
-                            self.session,
-                            span,
-                            E0642,
-                            "patterns aren't allowed in methods without bodies"
-                        )
-                        .emit();
-                    }
-                });
-            }
+    fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
+        if ctxt == AssocCtxt::Trait {
+            self.check_defaultness(item.span, item.defaultness);
         }
 
-        visit::walk_trait_item(self, ti);
-    }
+        if ctxt == AssocCtxt::Impl {
+            match &item.kind {
+                AssocItemKind::Const(_, body) => {
+                    self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
+                }
+                AssocItemKind::Fn(_, body) => {
+                    self.check_impl_item_provided(item.span, body, "function", " { <body> }");
+                }
+                AssocItemKind::TyAlias(bounds, body) => {
+                    self.check_impl_item_provided(item.span, body, "type", " = <type>;");
+                    self.check_impl_assoc_type_no_bounds(bounds);
+                }
+                _ => {}
+            }
+        }
 
-    fn visit_assoc_item(&mut self, item: &'a AssocItem) {
-        if let AssocItemKind::Fn(sig, _) = &item.kind {
-            self.check_fn_decl(&sig.decl, SelfSemantic::Yes);
-            self.check_c_varadic_type(&sig.decl);
+        if ctxt == AssocCtxt::Trait || self.in_trait_impl {
+            self.invalid_visibility(&item.vis, None);
+            if let AssocItemKind::Fn(sig, _) = &item.kind {
+                self.check_trait_fn_not_const(sig.header.constness);
+                self.check_trait_fn_not_async(item.span, sig.header.asyncness.node);
+            }
         }
-        visit::walk_assoc_item(self, item);
+
+        self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
     }
 }
 
 pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
     let mut validator = AstValidator {
         session,
+        extern_mod: None,
+        in_trait_impl: false,
         has_proc_macro_decls: false,
         outer_impl_trait: None,
         bound_context: None,
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index 3b13ab354fd..a10ac94d894 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -8,7 +8,7 @@ use rustc_span::Span;
 use syntax::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
 use syntax::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
 use syntax::attr;
-use syntax::visit::{self, FnKind, Visitor};
+use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 
 use log::debug;
 
@@ -492,25 +492,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_pat(self, pattern)
     }
 
-    fn visit_fn(
-        &mut self,
-        fn_kind: FnKind<'a>,
-        fn_decl: &'a ast::FnDecl,
-        span: Span,
-        _node_id: NodeId,
-    ) {
+    fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
         if let Some(header) = fn_kind.header() {
-            // Stability of const fn methods are covered in
-            // `visit_trait_item` and `visit_impl_item` below; this is
-            // because default methods don't pass through this point.
+            // Stability of const fn methods are covered in `visit_assoc_item` below.
             self.check_extern(header.ext);
         }
 
-        if fn_decl.c_variadic() {
+        if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
             gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
         }
 
-        visit::walk_fn(self, fn_kind, fn_decl, span)
+        visit::walk_fn(self, fn_kind, span)
     }
 
     fn visit_generic_param(&mut self, param: &'a GenericParam) {
@@ -539,56 +531,35 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_assoc_ty_constraint(self, constraint)
     }
 
-    fn visit_trait_item(&mut self, ti: &'a ast::AssocItem) {
-        match ti.kind {
-            ast::AssocItemKind::Fn(ref sig, ref block) => {
-                if block.is_none() {
-                    self.check_extern(sig.header.ext);
-                }
-                if sig.header.constness.node == ast::Constness::Const {
-                    gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
+    fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
+        if i.defaultness == ast::Defaultness::Default {
+            gate_feature_post!(&self, specialization, i.span, "specialization is unstable");
+        }
+
+        match i.kind {
+            ast::AssocItemKind::Fn(ref sig, _) => {
+                let constness = sig.header.constness.node;
+                if let (ast::Constness::Const, AssocCtxt::Trait) = (constness, ctxt) {
+                    gate_feature_post!(&self, const_fn, i.span, "const fn is unstable");
                 }
             }
-            ast::AssocItemKind::TyAlias(_, ref default) => {
-                if let Some(_) = default {
+            ast::AssocItemKind::TyAlias(_, ref ty) => {
+                if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
                     gate_feature_post!(
                         &self,
                         associated_type_defaults,
-                        ti.span,
+                        i.span,
                         "associated type defaults are unstable"
                     );
                 }
-            }
-            _ => {}
-        }
-        visit::walk_trait_item(self, ti)
-    }
-
-    fn visit_assoc_item(&mut self, ii: &'a ast::AssocItem) {
-        if ii.defaultness == ast::Defaultness::Default {
-            gate_feature_post!(&self, specialization, ii.span, "specialization is unstable");
-        }
-
-        match ii.kind {
-            ast::AssocItemKind::Fn(ref sig, _) => {
-                if sig.decl.c_variadic() {
-                    gate_feature_post!(
-                        &self,
-                        c_variadic,
-                        ii.span,
-                        "C-variadic functions are unstable"
-                    );
-                }
-            }
-            ast::AssocItemKind::TyAlias(_, ref ty) => {
                 if let Some(ty) = ty {
                     self.check_impl_trait(ty);
                 }
-                self.check_gat(&ii.generics, ii.span);
+                self.check_gat(&i.generics, i.span);
             }
             _ => {}
         }
-        visit::walk_assoc_item(self, ii)
+        visit::walk_assoc_item(self, i, ctxt)
     }
 
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
diff --git a/src/librustc_ast_passes/node_count.rs b/src/librustc_ast_passes/node_count.rs
index 9fe7238fcfc..ed1ccdf6a76 100644
--- a/src/librustc_ast_passes/node_count.rs
+++ b/src/librustc_ast_passes/node_count.rs
@@ -67,13 +67,13 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_generics(self, g)
     }
-    fn visit_fn(&mut self, fk: FnKind<'_>, fd: &FnDecl, s: Span, _: NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'_>, s: Span, _: NodeId) {
         self.count += 1;
-        walk_fn(self, fk, fd, s)
+        walk_fn(self, fk, s)
     }
-    fn visit_assoc_item(&mut self, ti: &AssocItem) {
+    fn visit_assoc_item(&mut self, ti: &AssocItem, ctxt: AssocCtxt) {
         self.count += 1;
-        walk_assoc_item(self, ti)
+        walk_assoc_item(self, ti, ctxt);
     }
     fn visit_trait_ref(&mut self, t: &TraitRef) {
         self.count += 1;
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 3cc67a7c821..d9077d1606f 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -1020,18 +1020,8 @@ impl<'a> State<'a> {
         self.maybe_print_comment(item.span.lo());
         self.print_outer_attributes(&item.attrs);
         match item.kind {
-            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
-                self.head("");
-                self.print_fn(
-                    decl,
-                    ast::FnHeader::default(),
-                    Some(item.ident),
-                    generics,
-                    &item.vis,
-                );
-                self.end(); // end head-ibox
-                self.s.word(";");
-                self.end(); // end the outer fn box
+            ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => {
+                self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
             }
             ast::ForeignItemKind::Static(ref t, m) => {
                 self.head(visibility_qualified(&item.vis, "static"));
@@ -1154,11 +1144,8 @@ impl<'a> State<'a> {
                 self.s.word(";");
                 self.end(); // end the outer cbox
             }
-            ast::ItemKind::Fn(ref sig, ref param_names, ref body) => {
-                self.head("");
-                self.print_fn(&sig.decl, sig.header, Some(item.ident), param_names, &item.vis);
-                self.s.word(" ");
-                self.print_block_with_attrs(body, &item.attrs);
+            ast::ItemKind::Fn(ref sig, ref gen, ref body) => {
+                self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
             }
             ast::ItemKind::Mod(ref _mod) => {
                 self.head(visibility_qualified(&item.vis, "mod"));
@@ -1483,16 +1470,8 @@ impl<'a> State<'a> {
                 self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis);
             }
             ast::AssocItemKind::Fn(sig, body) => {
-                if body.is_some() {
-                    self.head("");
-                }
-                self.print_fn(&sig.decl, sig.header, Some(item.ident), &item.generics, &item.vis);
-                if let Some(body) = body {
-                    self.nbsp();
-                    self.print_block_with_attrs(body, &item.attrs);
-                } else {
-                    self.s.word(";");
-                }
+                let body = body.as_deref();
+                self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs);
             }
             ast::AssocItemKind::TyAlias(bounds, ty) => {
                 self.print_associated_type(item.ident, bounds, ty.as_deref());
@@ -2412,6 +2391,27 @@ impl<'a> State<'a> {
         }
     }
 
+    fn print_fn_full(
+        &mut self,
+        sig: &ast::FnSig,
+        name: ast::Ident,
+        generics: &ast::Generics,
+        vis: &ast::Visibility,
+        body: Option<&ast::Block>,
+        attrs: &[ast::Attribute],
+    ) {
+        if body.is_some() {
+            self.head("");
+        }
+        self.print_fn(&sig.decl, sig.header, Some(name), generics, vis);
+        if let Some(body) = body {
+            self.nbsp();
+            self.print_block_with_attrs(body, attrs);
+        } else {
+            self.s.word(";");
+        }
+    }
+
     crate fn print_fn(
         &mut self,
         decl: &ast::FnDecl,
@@ -2698,13 +2698,9 @@ impl<'a> State<'a> {
             where_clause: ast::WhereClause { predicates: Vec::new(), span: rustc_span::DUMMY_SP },
             span: rustc_span::DUMMY_SP,
         };
-        self.print_fn(
-            decl,
-            ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() },
-            name,
-            &generics,
-            &dummy_spanned(ast::VisibilityKind::Inherited),
-        );
+        let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
+        let vis = dummy_spanned(ast::VisibilityKind::Inherited);
+        self.print_fn(decl, header, name, &generics, &vis);
         self.end();
     }
 
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index be7c164395b..ab03297fffe 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -396,26 +396,31 @@ where
                                     issue_num = match &*issue.unwrap().as_str() {
                                         "none" => None,
                                         issue => {
+                                            let emit_diag = |msg: &str| {
+                                                struct_span_err!(
+                                                    diagnostic,
+                                                    mi.span,
+                                                    E0545,
+                                                    "`issue` must be a non-zero numeric string \
+                                                    or \"none\"",
+                                                )
+                                                .span_label(
+                                                    mi.name_value_literal().unwrap().span,
+                                                    msg,
+                                                )
+                                                .emit();
+                                            };
                                             match issue.parse() {
-                                                Ok(num) => {
-                                                    // FIXME(rossmacarthur): disallow 0
-                                                    // Disallowing this requires updates to
-                                                    // some submodules
-                                                    NonZeroU32::new(num)
+                                                Ok(num) if num == 0 => {
+                                                    emit_diag(
+                                                        "`issue` must not be \"0\", \
+                                                        use \"none\" instead",
+                                                    );
+                                                    continue 'outer;
                                                 }
+                                                Ok(num) => NonZeroU32::new(num),
                                                 Err(err) => {
-                                                    struct_span_err!(
-                                                        diagnostic,
-                                                        mi.span,
-                                                        E0545,
-                                                        "`issue` must be a numeric string \
-                                                        or \"none\"",
-                                                    )
-                                                    .span_label(
-                                                        mi.name_value_literal().unwrap().span,
-                                                        &err.to_string(),
-                                                    )
-                                                    .emit();
+                                                    emit_diag(&err.to_string());
                                                     continue 'outer;
                                                 }
                                             }
diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs
index 957d34b7d89..ec0d55b38a7 100644
--- a/src/librustc_builtin_macros/global_allocator.rs
+++ b/src/librustc_builtin_macros/global_allocator.rs
@@ -66,7 +66,7 @@ impl AllocFnFactory<'_, '_> {
         let decl = self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty));
         let header = FnHeader { unsafety: Unsafety::Unsafe, ..FnHeader::default() };
         let sig = FnSig { decl, header };
-        let kind = ItemKind::Fn(sig, Generics::default(), self.cx.block_expr(output_expr));
+        let kind = ItemKind::Fn(sig, Generics::default(), Some(self.cx.block_expr(output_expr)));
         let item = self.cx.item(
             self.span,
             self.cx.ident_of(&self.kind.fn_name(method.name), self.span),
diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs
index 6a73f121c99..70f1c0e4e2d 100644
--- a/src/librustc_builtin_macros/test_harness.rs
+++ b/src/librustc_builtin_macros/test_harness.rs
@@ -307,7 +307,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
 
     let decl = ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty));
     let sig = ast::FnSig { decl, header: ast::FnHeader::default() };
-    let main = ast::ItemKind::Fn(sig, ast::Generics::default(), main_body);
+    let main = ast::ItemKind::Fn(sig, ast::Generics::default(), Some(main_body));
 
     // Honor the reexport_test_harness_main attribute
     let main_id = match cx.reexport_test_harness_main {
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 974d9dcfae4..0384776e9fb 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -74,7 +74,7 @@
 
 use crate::fx::{FxHashMap, FxHashSet};
 
-use std::cell::{Cell, RefCell};
+use std::cell::Cell;
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
 use std::hash;
@@ -146,7 +146,7 @@ pub struct ObligationForest<O: ForestObligation> {
     active_cache: FxHashMap<O::Predicate, usize>,
 
     /// A vector reused in compress(), to avoid allocating new vectors.
-    node_rewrites: RefCell<Vec<usize>>,
+    node_rewrites: Vec<usize>,
 
     obligation_tree_id_generator: ObligationTreeIdGenerator,
 
@@ -285,7 +285,7 @@ impl<O: ForestObligation> ObligationForest<O> {
             nodes: vec![],
             done_cache: Default::default(),
             active_cache: Default::default(),
-            node_rewrites: RefCell::new(vec![]),
+            node_rewrites: vec![],
             obligation_tree_id_generator: (0..).map(ObligationTreeId),
             error_cache: Default::default(),
         }
@@ -590,7 +590,7 @@ impl<O: ForestObligation> ObligationForest<O> {
     #[inline(never)]
     fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
         let orig_nodes_len = self.nodes.len();
-        let mut node_rewrites: Vec<_> = self.node_rewrites.replace(vec![]);
+        let mut node_rewrites: Vec<_> = std::mem::take(&mut self.node_rewrites);
         debug_assert!(node_rewrites.is_empty());
         node_rewrites.extend(0..orig_nodes_len);
         let mut dead_nodes = 0;
@@ -651,7 +651,7 @@ impl<O: ForestObligation> ObligationForest<O> {
         }
 
         node_rewrites.truncate(0);
-        self.node_rewrites.replace(node_rewrites);
+        self.node_rewrites = node_rewrites;
 
         if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None }
     }
diff --git a/src/librustc_error_codes/error_codes/E0271.md b/src/librustc_error_codes/error_codes/E0271.md
index 4078598b394..31334069ed8 100644
--- a/src/librustc_error_codes/error_codes/E0271.md
+++ b/src/librustc_error_codes/error_codes/E0271.md
@@ -1,9 +1,6 @@
-This is because of a type mismatch between the associated type of some
-trait (e.g., `T::Bar`, where `T` implements `trait Quux { type Bar; }`)
-and another type `U` that is required to be equal to `T::Bar`, but is not.
-Examples follow.
+A type mismatched an associated type of a trait.
 
-Here is a basic example:
+Erroneous code example:
 
 ```compile_fail,E0271
 trait Trait { type AssociatedType; }
@@ -17,6 +14,11 @@ impl Trait for i8 { type AssociatedType = &'static str; }
 foo(3_i8);
 ```
 
+This is because of a type mismatch between the associated type of some
+trait (e.g., `T::Bar`, where `T` implements `trait Quux { type Bar; }`)
+and another type `U` that is required to be equal to `T::Bar`, but is not.
+Examples follow.
+
 Here is that same example again, with some explanatory comments:
 
 ```compile_fail,E0271
diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs
index 536259e0547..e167089b93a 100644
--- a/src/librustc_expand/base.rs
+++ b/src/librustc_expand/base.rs
@@ -17,7 +17,7 @@ use syntax::mut_visit::{self, MutVisitor};
 use syntax::ptr::P;
 use syntax::token;
 use syntax::tokenstream::{self, TokenStream};
-use syntax::visit::Visitor;
+use syntax::visit::{AssocCtxt, Visitor};
 
 use std::default::Default;
 use std::iter;
@@ -103,8 +103,8 @@ impl Annotatable {
     pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
         match self {
             Annotatable::Item(item) => visitor.visit_item(item),
-            Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item),
-            Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item),
+            Annotatable::TraitItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Trait),
+            Annotatable::ImplItem(item) => visitor.visit_assoc_item(item, AssocCtxt::Impl),
             Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item),
             Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt),
             Annotatable::Expr(expr) => visitor.visit_expr(expr),
diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs
index d10819183d8..90692fe1ec9 100644
--- a/src/librustc_expand/expand.rs
+++ b/src/librustc_expand/expand.rs
@@ -25,7 +25,7 @@ use syntax::ptr::P;
 use syntax::token;
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::util::map_in_place::MapInPlace;
-use syntax::visit::{self, Visitor};
+use syntax::visit::{self, AssocCtxt, Visitor};
 
 use smallvec::{smallvec, SmallVec};
 use std::io::ErrorKind;
@@ -39,7 +39,7 @@ macro_rules! ast_fragments {
         $($Kind:ident($AstTy:ty) {
             $kind_name:expr;
             $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
-            $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident;)?
+            $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
             fn $make_ast:ident;
         })*
     ) => {
@@ -127,7 +127,7 @@ macro_rules! ast_fragments {
                     AstFragment::OptExpr(None) => {}
                     $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
                     $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
-                        visitor.$visit_ast_elt(ast_elt);
+                        visitor.$visit_ast_elt(ast_elt, $($args)*);
                     })?)*
                 }
             }
@@ -147,52 +147,58 @@ ast_fragments! {
     Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
     Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
     Stmts(SmallVec<[ast::Stmt; 1]>) {
-        "statement"; many fn flat_map_stmt; fn visit_stmt; fn make_stmts;
+        "statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts;
     }
     Items(SmallVec<[P<ast::Item>; 1]>) {
-        "item"; many fn flat_map_item; fn visit_item; fn make_items;
+        "item"; many fn flat_map_item; fn visit_item(); fn make_items;
     }
     TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) {
-        "trait item"; many fn flat_map_trait_item; fn visit_trait_item; fn make_trait_items;
+        "trait item";
+        many fn flat_map_trait_item;
+        fn visit_assoc_item(AssocCtxt::Trait);
+        fn make_trait_items;
     }
     ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
-        "impl item"; many fn flat_map_impl_item; fn visit_impl_item; fn make_impl_items;
+        "impl item";
+        many fn flat_map_impl_item;
+        fn visit_assoc_item(AssocCtxt::Impl);
+        fn make_impl_items;
     }
     ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) {
         "foreign item";
         many fn flat_map_foreign_item;
-        fn visit_foreign_item;
+        fn visit_foreign_item();
         fn make_foreign_items;
     }
     Arms(SmallVec<[ast::Arm; 1]>) {
-        "match arm"; many fn flat_map_arm; fn visit_arm; fn make_arms;
+        "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
     }
     Fields(SmallVec<[ast::Field; 1]>) {
-        "field expression"; many fn flat_map_field; fn visit_field; fn make_fields;
+        "field expression"; many fn flat_map_field; fn visit_field(); fn make_fields;
     }
     FieldPats(SmallVec<[ast::FieldPat; 1]>) {
         "field pattern";
         many fn flat_map_field_pattern;
-        fn visit_field_pattern;
+        fn visit_field_pattern();
         fn make_field_patterns;
     }
     GenericParams(SmallVec<[ast::GenericParam; 1]>) {
         "generic parameter";
         many fn flat_map_generic_param;
-        fn visit_generic_param;
+        fn visit_generic_param();
         fn make_generic_params;
     }
     Params(SmallVec<[ast::Param; 1]>) {
-        "function parameter"; many fn flat_map_param; fn visit_param; fn make_params;
+        "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
     }
     StructFields(SmallVec<[ast::StructField; 1]>) {
         "field";
         many fn flat_map_struct_field;
-        fn visit_struct_field;
+        fn visit_struct_field();
         fn make_struct_fields;
     }
     Variants(SmallVec<[ast::Variant; 1]>) {
-        "variant"; many fn flat_map_variant; fn visit_variant; fn make_variants;
+        "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
     }
 }
 
@@ -861,7 +867,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(DUMMY_SP)?);
+                items.push(this.parse_foreign_item()?);
             }
             AstFragment::ForeignItems(items)
         }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 345665de63c..ca66717ac5e 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -43,7 +43,7 @@ use rustc_span::{BytePos, Span};
 use syntax::ast::{self, Expr};
 use syntax::attr::{self, HasAttrs};
 use syntax::tokenstream::{TokenStream, TokenTree};
-use syntax::visit::FnKind;
+use syntax::visit::{FnCtxt, FnKind};
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
 
@@ -259,34 +259,22 @@ impl EarlyLintPass for UnsafeCode {
         }
     }
 
-    fn check_fn(
-        &mut self,
-        cx: &EarlyContext<'_>,
-        fk: FnKind<'_>,
-        _: &ast::FnDecl,
-        span: Span,
-        _: ast::NodeId,
-    ) {
-        match fk {
-            FnKind::ItemFn(_, ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, ..) => {
-                self.report_unsafe(cx, span, "declaration of an `unsafe` function")
-            }
-
-            FnKind::Method(_, sig, ..) => {
-                if sig.header.unsafety == ast::Unsafety::Unsafe {
-                    self.report_unsafe(cx, span, "implementation of an `unsafe` method")
-                }
-            }
-
-            _ => (),
-        }
-    }
-
-    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) {
-        if let ast::AssocItemKind::Fn(ref sig, None) = item.kind {
-            if sig.header.unsafety == ast::Unsafety::Unsafe {
-                self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
-            }
+    fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
+        if let FnKind::Fn(
+            ctxt,
+            _,
+            ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, .. },
+            _,
+            body,
+        ) = fk
+        {
+            let msg = match ctxt {
+                FnCtxt::Foreign => return,
+                FnCtxt::Free => "declaration of an `unsafe` function",
+                FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method",
+                FnCtxt::Assoc(_) => "implementation of an `unsafe` method",
+            };
+            self.report_unsafe(cx, span, msg);
         }
     }
 }
@@ -567,7 +555,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
 declare_lint! {
     MISSING_DEBUG_IMPLEMENTATIONS,
     Allow,
-    "detects missing implementations of fmt::Debug"
+    "detects missing implementations of Debug"
 }
 
 #[derive(Default)]
@@ -611,9 +599,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations {
             cx.span_lint(
                 MISSING_DEBUG_IMPLEMENTATIONS,
                 item.span,
-                "type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` \
-                          or a manual implementation",
-            )
+                &format!(
+                    "type does not implement `{}`; consider adding `#[derive(Debug)]` \
+                     or a manual implementation",
+                    cx.tcx.def_path_str(debug)
+                ),
+            );
         }
     }
 }
diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs
index 490114b2d4d..542cbea0c95 100644
--- a/src/librustc_lint/early.rs
+++ b/src/librustc_lint/early.rs
@@ -116,17 +116,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         ast_visit::walk_stmt(self, s);
     }
 
-    fn visit_fn(
-        &mut self,
-        fk: ast_visit::FnKind<'a>,
-        decl: &'a ast::FnDecl,
-        span: Span,
-        id: ast::NodeId,
-    ) {
-        run_early_pass!(self, check_fn, fk, decl, span, id);
+    fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, span: Span, id: ast::NodeId) {
+        run_early_pass!(self, check_fn, fk, span, id);
         self.check_id(id);
-        ast_visit::walk_fn(self, fk, decl, span);
-        run_early_pass!(self, check_fn_post, fk, decl, span, id);
+        ast_visit::walk_fn(self, fk, span);
+        run_early_pass!(self, check_fn_post, fk, span, id);
     }
 
     fn visit_variant_data(&mut self, s: &'a ast::VariantData) {
@@ -213,19 +207,18 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         ast_visit::walk_poly_trait_ref(self, t, m);
     }
 
-    fn visit_trait_item(&mut self, trait_item: &'a ast::AssocItem) {
-        self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
-            run_early_pass!(cx, check_trait_item, trait_item);
-            ast_visit::walk_trait_item(cx, trait_item);
-            run_early_pass!(cx, check_trait_item_post, trait_item);
-        });
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &'a ast::AssocItem) {
-        self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
-            run_early_pass!(cx, check_impl_item, impl_item);
-            ast_visit::walk_impl_item(cx, impl_item);
-            run_early_pass!(cx, check_impl_item_post, impl_item);
+    fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
+        self.with_lint_attrs(item.id, &item.attrs, |cx| match ctxt {
+            ast_visit::AssocCtxt::Trait => {
+                run_early_pass!(cx, check_trait_item, item);
+                ast_visit::walk_assoc_item(cx, item, ctxt);
+                run_early_pass!(cx, check_trait_item_post, item);
+            }
+            ast_visit::AssocCtxt::Impl => {
+                run_early_pass!(cx, check_impl_item, item);
+                ast_visit::walk_assoc_item(cx, item, ctxt);
+                run_early_pass!(cx, check_impl_item_post, item);
+            }
         });
     }
 
diff --git a/src/librustc_lint/passes.rs b/src/librustc_lint/passes.rs
index 7e5d670767a..36de625cafa 100644
--- a/src/librustc_lint/passes.rs
+++ b/src/librustc_lint/passes.rs
@@ -179,10 +179,9 @@ macro_rules! early_lint_methods {
             fn check_where_predicate(a: &ast::WherePredicate);
             fn check_poly_trait_ref(a: &ast::PolyTraitRef,
                                     b: &ast::TraitBoundModifier);
-            fn check_fn(a: syntax::visit::FnKind<'_>, b: &ast::FnDecl, c: Span, d_: ast::NodeId);
+            fn check_fn(a: syntax::visit::FnKind<'_>, c: Span, d_: ast::NodeId);
             fn check_fn_post(
                 a: syntax::visit::FnKind<'_>,
-                b: &ast::FnDecl,
                 c: Span,
                 d: ast::NodeId
             );
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 272c4f29203..5490e5e2b4d 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -587,6 +587,14 @@ impl EarlyLintPass for UnusedParens {
             }
         }
     }
+
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
+        use ast::ItemKind::*;
+
+        if let Const(.., ref expr) | Static(.., ref expr) = item.kind {
+            self.check_unused_parens_expr(cx, expr, "assigned value", false, None, None);
+        }
+    }
 }
 
 declare_lint! {
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index b1cab591fd9..7c015c7a1d7 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -1,3 +1,4 @@
+use super::ty::AllowPlus;
 use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
 
 use rustc_ast_pretty::pprust;
@@ -693,11 +694,11 @@ impl<'a> Parser<'a> {
 
     pub(super) fn maybe_report_ambiguous_plus(
         &mut self,
-        allow_plus: bool,
+        allow_plus: AllowPlus,
         impl_dyn_multi: bool,
         ty: &Ty,
     ) {
-        if !allow_plus && impl_dyn_multi {
+        if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi {
             let sum_with_parens = format!("({})", pprust::ty_to_string(&ty));
             self.struct_span_err(ty.span, "ambiguous `+` in a type")
                 .span_suggestion(
@@ -712,11 +713,11 @@ impl<'a> Parser<'a> {
 
     pub(super) fn maybe_recover_from_bad_type_plus(
         &mut self,
-        allow_plus: bool,
+        allow_plus: AllowPlus,
         ty: &Ty,
     ) -> PResult<'a, ()> {
         // Do not add `+` to expected tokens.
-        if !allow_plus || !self.token.is_like_plus() {
+        if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() {
             return Ok(());
         }
 
@@ -937,47 +938,6 @@ impl<'a> Parser<'a> {
         self.expect(&token::Semi).map(drop) // Error unconditionally
     }
 
-    pub(super) fn parse_semi_or_incorrect_foreign_fn_body(
-        &mut self,
-        ident: &Ident,
-        extern_sp: Span,
-    ) -> PResult<'a, ()> {
-        if self.token != token::Semi {
-            // This might be an incorrect fn definition (#62109).
-            let parser_snapshot = self.clone();
-            match self.parse_inner_attrs_and_block() {
-                Ok((_, body)) => {
-                    self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block")
-                        .span_label(ident.span, "can't have a body")
-                        .span_label(body.span, "this body is invalid here")
-                        .span_label(
-                            extern_sp,
-                            "`extern` blocks define existing foreign functions and `fn`s \
-                             inside of them cannot have a body",
-                        )
-                        .help(
-                            "you might have meant to write a function accessible through ffi, \
-                               which can be done by writing `extern fn` outside of the \
-                               `extern` block",
-                        )
-                        .note(
-                            "for more information, visit \
-                               https://doc.rust-lang.org/std/keyword.extern.html",
-                        )
-                        .emit();
-                }
-                Err(mut err) => {
-                    err.cancel();
-                    mem::replace(self, parser_snapshot);
-                    self.expect_semi()?;
-                }
-            }
-        } else {
-            self.bump();
-        }
-        Ok(())
-    }
-
     /// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
     /// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
     pub(super) fn recover_incorrect_await_syntax(
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 0d12f8cf6c0..d9832141695 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -1,4 +1,5 @@
 use super::pat::{GateOr, PARAM_EXPECTED};
+use super::ty::{AllowPlus, RecoverQPath};
 use super::{BlockMode, Parser, PathStyle, PrevTokenKind, Restrictions, TokenType};
 use super::{SemiColonMode, SeqSep, TokenExpectType};
 use crate::maybe_recover_from_interpolated_ty_qpath;
@@ -1399,7 +1400,7 @@ impl<'a> Parser<'a> {
             self.expect_or()?;
             args
         };
-        let output = self.parse_ret_ty(true, true)?;
+        let output = self.parse_ret_ty(AllowPlus::Yes, RecoverQPath::Yes)?;
 
         Ok(P(FnDecl { inputs, output }))
     }
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index b7f299e56ae..07d8bae4725 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1,4 +1,5 @@
 use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
+use super::ty::{AllowPlus, RecoverQPath};
 use super::{FollowedByType, Parser, PathStyle};
 
 use crate::maybe_whole;
@@ -96,7 +97,6 @@ impl<'a> Parser<'a> {
         }
 
         if self.eat_keyword(kw::Extern) {
-            let extern_sp = self.prev_span;
             if self.eat_keyword(kw::Crate) {
                 return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
             }
@@ -114,7 +114,7 @@ impl<'a> Parser<'a> {
                 };
                 return self.parse_item_fn(lo, vis, attrs, header);
             } else if self.check(&token::OpenDelim(token::Brace)) {
-                return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs, extern_sp)?));
+                return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?));
             }
 
             self.unexpected()?;
@@ -1045,7 +1045,6 @@ impl<'a> Parser<'a> {
         abi: Option<StrLit>,
         visibility: Visibility,
         mut attrs: Vec<Attribute>,
-        extern_sp: Span,
     ) -> PResult<'a, P<Item>> {
         self.expect(&token::OpenDelim(token::Brace))?;
 
@@ -1053,7 +1052,7 @@ impl<'a> Parser<'a> {
 
         let mut foreign_items = vec![];
         while !self.eat(&token::CloseDelim(token::Brace)) {
-            foreign_items.push(self.parse_foreign_item(extern_sp)?);
+            foreign_items.push(self.parse_foreign_item()?);
         }
 
         let prev_span = self.prev_span;
@@ -1063,51 +1062,42 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a foreign item.
-    pub fn parse_foreign_item(&mut self, extern_sp: Span) -> PResult<'a, P<ForeignItem>> {
+    pub fn parse_foreign_item(&mut self) -> PResult<'a, P<ForeignItem>> {
         maybe_whole!(self, NtForeignItem, |ni| ni);
 
         let attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
         let visibility = self.parse_visibility(FollowedByType::No)?;
 
+        // FOREIGN TYPE ITEM
+        if self.check_keyword(kw::Type) {
+            return self.parse_item_foreign_type(visibility, lo, attrs);
+        }
+
         // FOREIGN STATIC ITEM
-        // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
-        if self.check_keyword(kw::Static) || self.token.is_keyword(kw::Const) {
-            if self.token.is_keyword(kw::Const) {
-                let mut err =
-                    self.struct_span_err(self.token.span, "extern items cannot be `const`");
+        if self.is_static_global() {
+            self.bump(); // `static`
+            return self.parse_item_foreign_static(visibility, lo, attrs);
+        }
 
-                // The user wrote 'const fn'
-                if self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe]) {
-                    err.emit();
-                    // Consume `const`
-                    self.bump();
-                    // Consume `unsafe` if present, since `extern` blocks
-                    // don't allow it. This will leave behind a plain 'fn'
-                    self.eat_keyword(kw::Unsafe);
-                    // Treat 'const fn` as a plain `fn` for error recovery purposes.
-                    // We've already emitted an error, so compilation is guaranteed
-                    // to fail
-                    return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?);
-                }
-                err.span_suggestion(
-                    self.token.span,
+        // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
+        if self.is_kw_followed_by_ident(kw::Const) {
+            self.bump(); // `const`
+            self.struct_span_err(self.prev_span, "extern items cannot be `const`")
+                .span_suggestion(
+                    self.prev_span,
                     "try using a static value",
                     "static".to_owned(),
                     Applicability::MachineApplicable,
-                );
-                err.emit();
-            }
-            self.bump(); // `static` or `const`
-            return Ok(self.parse_item_foreign_static(visibility, lo, attrs)?);
+                )
+                .emit();
+            return self.parse_item_foreign_static(visibility, lo, attrs);
         }
+
         // FOREIGN FUNCTION ITEM
-        if self.check_keyword(kw::Fn) {
-            return Ok(self.parse_item_foreign_fn(visibility, lo, attrs, extern_sp)?);
-        }
-        // FOREIGN TYPE ITEM
-        if self.check_keyword(kw::Type) {
-            return Ok(self.parse_item_foreign_type(visibility, lo, attrs)?);
+        const MAY_INTRODUCE_FN: &[Symbol] = &[kw::Const, kw::Async, kw::Unsafe, kw::Extern, kw::Fn];
+        if MAY_INTRODUCE_FN.iter().any(|&kw| self.check_keyword(kw)) {
+            return self.parse_item_foreign_fn(visibility, lo, attrs);
         }
 
         match self.parse_assoc_macro_invoc("extern", Some(&visibility), &mut false)? {
@@ -1726,14 +1716,14 @@ impl<'a> Parser<'a> {
         &mut self,
         lo: Span,
         vis: Visibility,
-        attrs: Vec<Attribute>,
+        mut attrs: Vec<Attribute>,
         header: FnHeader,
     ) -> PResult<'a, Option<P<Item>>> {
         let cfg = ParamCfg { is_name_required: |_| true };
         let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
-        let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
+        let body = self.parse_fn_body(&mut false, &mut attrs)?;
         let kind = ItemKind::Fn(FnSig { decl, header }, generics, body);
-        self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs)))
+        self.mk_item_with_info(attrs, lo, vis, (ident, kind, None))
     }
 
     /// Parses a function declaration from a foreign module.
@@ -1741,15 +1731,14 @@ impl<'a> Parser<'a> {
         &mut self,
         vis: ast::Visibility,
         lo: Span,
-        attrs: Vec<Attribute>,
-        extern_sp: Span,
+        mut attrs: Vec<Attribute>,
     ) -> PResult<'a, P<ForeignItem>> {
         let cfg = ParamCfg { is_name_required: |_| true };
-        self.expect_keyword(kw::Fn)?;
+        let header = self.parse_fn_front_matter()?;
         let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
-        let span = lo.to(self.token.span);
-        self.parse_semi_or_incorrect_foreign_fn_body(&ident, extern_sp)?;
-        let kind = ForeignItemKind::Fn(decl, generics);
+        let body = self.parse_fn_body(&mut false, &mut attrs)?;
+        let kind = ForeignItemKind::Fn(FnSig { header, decl }, generics, body);
+        let span = lo.to(self.prev_span);
         Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None }))
     }
 
@@ -1760,45 +1749,40 @@ impl<'a> Parser<'a> {
         is_name_required: fn(&token::Token) -> bool,
     ) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
         let header = self.parse_fn_front_matter()?;
-        let (ident, decl, generics) = self.parse_fn_sig(&ParamCfg { is_name_required })?;
-        let sig = FnSig { header, decl };
-        let body = self.parse_assoc_fn_body(at_end, attrs)?;
-        Ok((ident, AssocItemKind::Fn(sig, body), generics))
+        let (ident, decl, generics) = self.parse_fn_sig(&&ParamCfg { is_name_required })?;
+        let body = self.parse_fn_body(at_end, attrs)?;
+        Ok((ident, AssocItemKind::Fn(FnSig { header, decl }, body), generics))
     }
 
-    /// Parse the "body" of a method in an associated item definition.
+    /// Parse the "body" of a function.
     /// This can either be `;` when there's no body,
-    /// or e.g. a block when the method is a provided one.
-    fn parse_assoc_fn_body(
+    /// or e.g. a block when the function is a provided one.
+    fn parse_fn_body(
         &mut self,
         at_end: &mut bool,
         attrs: &mut Vec<Attribute>,
     ) -> PResult<'a, Option<P<Block>>> {
-        Ok(match self.token.kind {
+        let (inner_attrs, body) = match self.token.kind {
             token::Semi => {
-                debug!("parse_assoc_fn_body(): parsing required method");
                 self.bump();
-                *at_end = true;
-                None
+                (Vec::new(), None)
             }
             token::OpenDelim(token::Brace) => {
-                debug!("parse_assoc_fn_body(): parsing provided method");
-                *at_end = true;
-                let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-                attrs.extend(inner_attrs.iter().cloned());
-                Some(body)
+                let (attrs, body) = self.parse_inner_attrs_and_block()?;
+                (attrs, Some(body))
             }
             token::Interpolated(ref nt) => match **nt {
                 token::NtBlock(..) => {
-                    *at_end = true;
-                    let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-                    attrs.extend(inner_attrs.iter().cloned());
-                    Some(body)
+                    let (attrs, body) = self.parse_inner_attrs_and_block()?;
+                    (attrs, Some(body))
                 }
                 _ => return self.expected_semi_or_open_brace(),
             },
             _ => return self.expected_semi_or_open_brace(),
-        })
+        };
+        attrs.extend(inner_attrs);
+        *at_end = true;
+        Ok(body)
     }
 
     /// Parses all the "front matter" for a `fn` declaration, up to
@@ -1839,7 +1823,7 @@ impl<'a> Parser<'a> {
     fn parse_fn_sig(&mut self, cfg: &ParamCfg) -> PResult<'a, (Ident, P<FnDecl>, Generics)> {
         let ident = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
-        let decl = self.parse_fn_decl(cfg, true)?;
+        let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?;
         generics.where_clause = self.parse_where_clause()?;
         Ok((ident, decl, generics))
     }
@@ -1848,11 +1832,11 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_fn_decl(
         &mut self,
         cfg: &ParamCfg,
-        ret_allow_plus: bool,
+        ret_allow_plus: AllowPlus,
     ) -> PResult<'a, P<FnDecl>> {
         Ok(P(FnDecl {
             inputs: self.parse_fn_params(cfg)?,
-            output: self.parse_ret_ty(ret_allow_plus, true)?,
+            output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
         }))
     }
 
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index 8c1839da1cb..825607a2348 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -21,7 +21,7 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::respan;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{BytePos, FileName, Span, DUMMY_SP};
+use rustc_span::{FileName, Span, DUMMY_SP};
 use syntax::ast::{self, AttrStyle, AttrVec, CrateSugar, Extern, Ident, Unsafety, DUMMY_NODE_ID};
 use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind};
 use syntax::ptr::P;
@@ -615,8 +615,8 @@ impl<'a> Parser<'a> {
                 true
             }
             token::BinOpEq(token::Plus) => {
-                let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
-                self.bump_with(token::Eq, span);
+                let start_point = self.sess.source_map().start_point(self.token.span);
+                self.bump_with(token::Eq, self.token.span.with_lo(start_point.hi()));
                 true
             }
             _ => false,
@@ -633,8 +633,9 @@ impl<'a> Parser<'a> {
                 Ok(())
             }
             token::AndAnd => {
-                let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
-                Ok(self.bump_with(token::BinOp(token::And), span))
+                let start_point = self.sess.source_map().start_point(self.token.span);
+                Ok(self
+                    .bump_with(token::BinOp(token::And), self.token.span.with_lo(start_point.hi())))
             }
             _ => self.unexpected(),
         }
@@ -650,8 +651,9 @@ impl<'a> Parser<'a> {
                 Ok(())
             }
             token::OrOr => {
-                let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
-                Ok(self.bump_with(token::BinOp(token::Or), span))
+                let start_point = self.sess.source_map().start_point(self.token.span);
+                Ok(self
+                    .bump_with(token::BinOp(token::Or), self.token.span.with_lo(start_point.hi())))
             }
             _ => self.unexpected(),
         }
@@ -671,13 +673,16 @@ impl<'a> Parser<'a> {
                 true
             }
             token::BinOp(token::Shl) => {
-                let span = self.sess.source_map().next_point(self.token.span);
-                self.bump_with(token::Lt, span);
+                let start_point = self.sess.source_map().start_point(self.token.span);
+                self.bump_with(token::Lt, self.token.span.with_lo(start_point.hi()));
                 true
             }
             token::LArrow => {
-                let span = self.sess.source_map().next_point(self.token.span);
-                self.bump_with(token::BinOp(token::Minus), span);
+                let start_point = self.sess.source_map().start_point(self.token.span);
+                self.bump_with(
+                    token::BinOp(token::Minus),
+                    self.token.span.with_lo(start_point.hi()),
+                );
                 true
             }
             _ => false,
@@ -707,16 +712,16 @@ impl<'a> Parser<'a> {
                 Some(())
             }
             token::BinOp(token::Shr) => {
-                let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
-                Some(self.bump_with(token::Gt, span))
+                let start_point = self.sess.source_map().start_point(self.token.span);
+                Some(self.bump_with(token::Gt, self.token.span.with_lo(start_point.hi())))
             }
             token::BinOpEq(token::Shr) => {
-                let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
-                Some(self.bump_with(token::Ge, span))
+                let start_point = self.sess.source_map().start_point(self.token.span);
+                Some(self.bump_with(token::Ge, self.token.span.with_lo(start_point.hi())))
             }
             token::Ge => {
-                let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
-                Some(self.bump_with(token::Eq, span))
+                let start_point = self.sess.source_map().start_point(self.token.span);
+                Some(self.bump_with(token::Eq, self.token.span.with_lo(start_point.hi())))
             }
             _ => None,
         };
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index a09eb42dcfe..cb14ffb4bd0 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -1,3 +1,4 @@
+use super::ty::{AllowPlus, RecoverQPath};
 use super::{Parser, TokenType};
 use crate::maybe_whole;
 use rustc_errors::{pluralize, Applicability, PResult};
@@ -224,7 +225,7 @@ impl<'a> Parser<'a> {
                     // `(T, U) -> R`
                     let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
                     let span = ident.span.to(self.prev_span);
-                    let output = self.parse_ret_ty(false, false)?;
+                    let output = self.parse_ret_ty(AllowPlus::No, RecoverQPath::No)?;
                     ParenthesizedArgs { inputs, output, span }.into()
                 };
 
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index ae8f1e4db1b..f3a69729399 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -199,7 +199,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
+    pub(super) 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())
     }
 
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index c9c2cbb98ca..990661bf6b5 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -36,6 +36,25 @@ impl BoundModifiers {
     }
 }
 
+#[derive(Copy, Clone, PartialEq)]
+pub(super) enum AllowPlus {
+    Yes,
+    No,
+}
+
+#[derive(PartialEq)]
+pub(super) enum RecoverQPath {
+    Yes,
+    No,
+}
+
+// Is `...` (`CVarArgs`) legal at this level of type parsing?
+#[derive(PartialEq)]
+enum AllowCVariadic {
+    Yes,
+    No,
+}
+
 /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT<u8, u8>`,
 /// `IDENT<<u8 as Trait>::AssocTy>`.
 ///
@@ -48,14 +67,14 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool {
 impl<'a> Parser<'a> {
     /// Parses a type.
     pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
-        self.parse_ty_common(true, true, false)
+        self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::No)
     }
 
     /// Parse a type suitable for a function or function pointer parameter.
     /// The difference from `parse_ty` is that this version allows `...`
     /// (`CVarArgs`) at the top level of the the type.
     pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
-        self.parse_ty_common(true, true, true)
+        self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes)
     }
 
     /// Parses a type in restricted contexts where `+` is not permitted.
@@ -65,18 +84,19 @@ impl<'a> Parser<'a> {
     /// Example 2: `value1 as TYPE + value2`
     ///     `+` is prohibited to avoid interactions with expression grammar.
     pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
-        self.parse_ty_common(false, true, false)
+        self.parse_ty_common(AllowPlus::No, RecoverQPath::Yes, AllowCVariadic::No)
     }
 
     /// Parses an optional return type `[ -> TY ]` in a function declaration.
     pub(super) fn parse_ret_ty(
         &mut self,
-        allow_plus: bool,
-        allow_qpath_recovery: bool,
+        allow_plus: AllowPlus,
+        recover_qpath: RecoverQPath,
     ) -> PResult<'a, FunctionRetTy> {
         Ok(if self.eat(&token::RArrow) {
             // FIXME(Centril): Can we unconditionally `allow_plus`?
-            FunctionRetTy::Ty(self.parse_ty_common(allow_plus, allow_qpath_recovery, false)?)
+            let ty = self.parse_ty_common(allow_plus, recover_qpath, AllowCVariadic::No)?;
+            FunctionRetTy::Ty(ty)
         } else {
             FunctionRetTy::Default(self.token.span.shrink_to_lo())
         })
@@ -84,11 +104,11 @@ impl<'a> Parser<'a> {
 
     fn parse_ty_common(
         &mut self,
-        allow_plus: bool,
-        allow_qpath_recovery: bool,
-        // Is `...` (`CVarArgs`) legal in the immediate top level call?
-        allow_c_variadic: bool,
+        allow_plus: AllowPlus,
+        recover_qpath: RecoverQPath,
+        allow_c_variadic: AllowCVariadic,
     ) -> PResult<'a, P<Ty>> {
+        let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
         maybe_whole!(self, NtTy, |x| x);
 
@@ -124,7 +144,7 @@ impl<'a> Parser<'a> {
                 self.parse_ty_bare_fn(lifetime_defs)?
             } else {
                 let path = self.parse_path(PathStyle::Type)?;
-                let parse_plus = allow_plus && self.check_plus();
+                let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
                 self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
             }
         } else if self.eat_keyword(kw::Impl) {
@@ -144,7 +164,7 @@ impl<'a> Parser<'a> {
         } else if self.token.is_path_start() {
             self.parse_path_start_ty(lo, allow_plus)?
         } else if self.eat(&token::DotDotDot) {
-            if allow_c_variadic {
+            if allow_c_variadic == AllowCVariadic::Yes {
                 TyKind::CVarArgs
             } else {
                 // FIXME(Centril): Should we just allow `...` syntactically
@@ -172,7 +192,7 @@ impl<'a> Parser<'a> {
     /// Parses either:
     /// - `(TYPE)`, a parenthesized type.
     /// - `(TYPE,)`, a tuple with a single field of type TYPE.
-    fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> {
+    fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
         let mut trailing_plus = false;
         let (ts, trailing) = self.parse_paren_comma_seq(|p| {
             let ty = p.parse_ty()?;
@@ -182,7 +202,7 @@ impl<'a> Parser<'a> {
 
         if ts.len() == 1 && !trailing {
             let ty = ts.into_iter().nth(0).unwrap().into_inner();
-            let maybe_bounds = allow_plus && self.token.is_like_plus();
+            let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus();
             match ty.kind {
                 // `(TY_BOUND_NOPAREN) + BOUND + ...`.
                 TyKind::Path(None, path) if maybe_bounds => {
@@ -288,7 +308,8 @@ impl<'a> Parser<'a> {
         let unsafety = self.parse_unsafety();
         let ext = self.parse_extern()?;
         self.expect_keyword(kw::Fn)?;
-        let decl = self.parse_fn_decl(&ParamCfg { is_name_required: |_| false }, false)?;
+        let cfg = ParamCfg { is_name_required: |_| false };
+        let decl = self.parse_fn_decl(&cfg, AllowPlus::No)?;
         Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl })))
     }
 
@@ -326,7 +347,7 @@ impl<'a> Parser<'a> {
     /// 1. a type macro, `mac!(...)`,
     /// 2. a bare trait object, `B0 + ... + Bn`,
     /// 3. or a path, `path::to::MyType`.
-    fn parse_path_start_ty(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> {
+    fn parse_path_start_ty(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
         // Simple path
         let path = self.parse_path(PathStyle::Type)?;
         if self.eat(&token::Not) {
@@ -336,7 +357,7 @@ impl<'a> Parser<'a> {
                 args: self.parse_mac_args()?,
                 prior_type_ascription: self.last_type_ascription,
             }))
-        } else if allow_plus && self.check_plus() {
+        } else if allow_plus == AllowPlus::Yes && self.check_plus() {
             // `Trait1 + Trait2 + 'a`
             self.parse_remaining_bounds(Vec::new(), path, lo, true)
         } else {
@@ -359,7 +380,7 @@ impl<'a> Parser<'a> {
         &mut self,
         colon_span: Option<Span>,
     ) -> PResult<'a, GenericBounds> {
-        self.parse_generic_bounds_common(true, colon_span)
+        self.parse_generic_bounds_common(AllowPlus::Yes, colon_span)
     }
 
     /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
@@ -367,7 +388,7 @@ impl<'a> Parser<'a> {
     /// See `parse_generic_bound` for the `BOUND` grammar.
     fn parse_generic_bounds_common(
         &mut self,
-        allow_plus: bool,
+        allow_plus: AllowPlus,
         colon_span: Option<Span>,
     ) -> PResult<'a, GenericBounds> {
         let mut bounds = Vec::new();
@@ -377,7 +398,7 @@ impl<'a> Parser<'a> {
                 Ok(bound) => bounds.push(bound),
                 Err(neg_sp) => negative_bounds.push(neg_sp),
             }
-            if !allow_plus || !self.eat_plus() {
+            if allow_plus == AllowPlus::No || !self.eat_plus() {
                 break;
             }
         }
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index b6ca2b3a595..c6c201fa38e 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -302,19 +302,18 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_ty(self, t)
     }
 
-    fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, fd: &'v ast::FnDecl, s: Span, _: NodeId) {
-        self.record("FnDecl", Id::None, fd);
-        ast_visit::walk_fn(self, fk, fd, s)
-    }
-
-    fn visit_trait_item(&mut self, ti: &'v ast::AssocItem) {
-        self.record("TraitItem", Id::None, ti);
-        ast_visit::walk_trait_item(self, ti)
-    }
-
-    fn visit_impl_item(&mut self, ii: &'v ast::AssocItem) {
-        self.record("ImplItem", Id::None, ii);
-        ast_visit::walk_impl_item(self, ii)
+    fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) {
+        self.record("FnDecl", Id::None, fk.decl());
+        ast_visit::walk_fn(self, fk, s)
+    }
+
+    fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
+        let label = match ctxt {
+            ast_visit::AssocCtxt::Trait => "TraitItem",
+            ast_visit::AssocCtxt::Impl => "ImplItem",
+        };
+        self.record(label, Id::None, item);
+        ast_visit::walk_assoc_item(self, item, ctxt);
     }
 
     fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound) {
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index c77b588d7fb..d6ea737385c 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -36,7 +36,7 @@ use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, Nod
 use syntax::ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind};
 use syntax::ast::{Ident, Name};
 use syntax::token::{self, Token};
-use syntax::visit::{self, Visitor};
+use syntax::visit::{self, AssocCtxt, Visitor};
 
 use log::debug;
 use std::cell::Cell;
@@ -1234,7 +1234,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         self.parent_scope.legacy = orig_current_legacy_scope;
     }
 
-    fn visit_trait_item(&mut self, item: &'b AssocItem) {
+    fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) {
         let parent = self.parent_scope.module;
 
         if let AssocItemKind::Macro(_) = item.kind {
@@ -1242,6 +1242,12 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
             return;
         }
 
+        if let AssocCtxt::Impl = ctxt {
+            self.resolve_visibility(&item.vis);
+            visit::walk_assoc_item(self, item, ctxt);
+            return;
+        }
+
         // Add the item to the trait info.
         let item_def_id = self.r.definitions.local_def_id(item.id);
         let (res, ns) = match item.kind {
@@ -1260,16 +1266,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         let expansion = self.parent_scope.expansion;
         self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
 
-        visit::walk_trait_item(self, item);
-    }
-
-    fn visit_impl_item(&mut self, item: &'b ast::AssocItem) {
-        if let ast::AssocItemKind::Macro(..) = item.kind {
-            self.visit_invoc(item.id);
-        } else {
-            self.resolve_visibility(&item.vis);
-            visit::walk_impl_item(self, item);
-        }
+        visit::walk_assoc_item(self, item, ctxt);
     }
 
     fn visit_token(&mut self, t: Token) {
diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs
index 696ba0e994c..3a26197c160 100644
--- a/src/librustc_resolve/def_collector.rs
+++ b/src/librustc_resolve/def_collector.rs
@@ -125,7 +125,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
                     &sig.header,
                     generics,
                     &sig.decl,
-                    Some(body),
+                    body.as_deref(),
                 );
             }
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => {
@@ -213,39 +213,26 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         visit::walk_generic_param(self, param);
     }
 
-    fn visit_trait_item(&mut self, ti: &'a AssocItem) {
-        let def_data = match ti.kind {
-            AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ti.ident.name),
-            AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ti.ident.name),
-            AssocItemKind::Macro(..) => return self.visit_macro_invoc(ti.id),
-        };
-
-        let def = self.create_def(ti.id, def_data, ti.span);
-        self.with_parent(def, |this| visit::walk_trait_item(this, ti));
-    }
-
-    fn visit_impl_item(&mut self, ii: &'a AssocItem) {
-        let def_data = match ii.kind {
-            AssocItemKind::Fn(FnSig { ref header, ref decl }, ref body)
-                if header.asyncness.node.is_async() =>
-            {
+    fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
+        let def_data = match &i.kind {
+            AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.node.is_async() => {
                 return self.visit_async_fn(
-                    ii.id,
-                    ii.ident.name,
-                    ii.span,
+                    i.id,
+                    i.ident.name,
+                    i.span,
                     header,
-                    &ii.generics,
+                    &i.generics,
                     decl,
                     body.as_deref(),
                 );
             }
-            AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(ii.ident.name),
-            AssocItemKind::TyAlias(..) => DefPathData::TypeNs(ii.ident.name),
-            AssocItemKind::Macro(..) => return self.visit_macro_invoc(ii.id),
+            AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name),
+            AssocItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
+            AssocItemKind::Macro(..) => return self.visit_macro_invoc(i.id),
         };
 
-        let def = self.create_def(ii.id, def_data, ii.span);
-        self.with_parent(def, |this| visit::walk_impl_item(this, ii));
+        let def = self.create_def(i.id, def_data, i.span);
+        self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt));
     }
 
     fn visit_pat(&mut self, pat: &'a Pat) {
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index f1622af130e..01a0e568137 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -24,7 +24,7 @@ use smallvec::{smallvec, SmallVec};
 use syntax::ast::*;
 use syntax::ptr::P;
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax::visit::{self, FnKind, Visitor};
+use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use syntax::{unwrap_or, walk_list};
 
 use log::debug;
@@ -437,7 +437,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
     }
     fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
         match foreign_item.kind {
-            ForeignItemKind::Fn(_, ref generics) => {
+            ForeignItemKind::Fn(_, ref generics, _) => {
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
@@ -452,13 +452,15 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
             }
         }
     }
-    fn visit_fn(&mut self, fn_kind: FnKind<'ast>, declaration: &'ast FnDecl, sp: Span, _: NodeId) {
-        let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp));
-        debug!("(resolving function) entering function");
+    fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
         let rib_kind = match fn_kind {
-            FnKind::ItemFn(..) => FnItemRibKind,
-            FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind,
+            FnKind::Fn(FnCtxt::Foreign, ..) => return visit::walk_fn(self, fn_kind, sp),
+            FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
+            FnKind::Fn(FnCtxt::Assoc(_), ..) | FnKind::Closure(..) => NormalRibKind,
         };
+        let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp));
+        debug!("(resolving function) entering function");
+        let declaration = fn_kind.decl();
 
         // Create a value rib for the function.
         self.with_rib(ValueNS, rib_kind, |this| {
@@ -471,8 +473,8 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
 
                 // Resolve the function body, potentially inside the body of an async closure
                 match fn_kind {
-                    FnKind::ItemFn(.., body) | FnKind::Method(.., body) => this.visit_block(body),
-                    FnKind::Closure(body) => this.visit_expr(body),
+                    FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
+                    FnKind::Closure(_, body) => this.visit_expr(body),
                 };
 
                 debug!("(resolving function) leaving function");
@@ -843,12 +845,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                                     });
                                                 }
                                             }
-                                            AssocItemKind::Fn(_, _) => {
-                                                visit::walk_trait_item(this, trait_item)
-                                            }
-                                            AssocItemKind::TyAlias(..) => {
-                                                visit::walk_trait_item(this, trait_item)
-                                            }
+                                            AssocItemKind::Fn(_, _) => visit::walk_assoc_item(
+                                                this,
+                                                trait_item,
+                                                AssocCtxt::Trait,
+                                            ),
+                                            AssocItemKind::TyAlias(..) => visit::walk_assoc_item(
+                                                this,
+                                                trait_item,
+                                                AssocCtxt::Trait,
+                                            ),
                                             AssocItemKind::Macro(_) => {
                                                 panic!("unexpanded macro in resolve!")
                                             }
@@ -1128,7 +1134,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                                 );
 
                                                 this.with_constant_rib(|this| {
-                                                    visit::walk_impl_item(this, impl_item)
+                                                    visit::walk_assoc_item(
+                                                        this,
+                                                        impl_item,
+                                                        AssocCtxt::Impl,
+                                                    )
                                                 });
                                             }
                                             AssocItemKind::Fn(..) => {
@@ -1139,7 +1149,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                                                       impl_item.span,
                                                     |n, s| MethodNotMemberOfTrait(n, s));
 
-                                                visit::walk_impl_item(this, impl_item);
+                                                visit::walk_assoc_item(
+                                                    this,
+                                                    impl_item,
+                                                    AssocCtxt::Impl,
+                                                )
                                             }
                                             AssocItemKind::TyAlias(_, _) => {
                                                 // If this is a trait impl, ensure the type
@@ -1149,7 +1163,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                                                                       impl_item.span,
                                                     |n, s| TypeNotMemberOfTrait(n, s));
 
-                                                visit::walk_impl_item(this, impl_item);
+                                                visit::walk_assoc_item(
+                                                    this,
+                                                    impl_item,
+                                                    AssocCtxt::Impl,
+                                                )
                                             }
                                             AssocItemKind::Macro(_) =>
                                                 panic!("unexpanded macro in resolve!"),
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 3f436a1e27c..5ce81c104e1 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -358,7 +358,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
         decl: &'l ast::FnDecl,
         header: &'l ast::FnHeader,
         ty_params: &'l ast::Generics,
-        body: &'l ast::Block,
+        body: Option<&'l ast::Block>,
     ) {
         let hir_id = self.tcx.hir().node_to_hir_id(item.id);
         self.nest_tables(item.id, |v| {
@@ -392,7 +392,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 }
             }
 
-            v.visit_block(&body);
+            walk_list!(v, visit_block, body);
         });
     }
 
@@ -1291,7 +1291,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                 }
             }
             Fn(ref sig, ref ty_params, ref body) => {
-                self.process_fn(item, &sig.decl, &sig.header, ty_params, &body)
+                self.process_fn(item, &sig.decl, &sig.header, ty_params, body.as_deref())
             }
             Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr),
             Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr),
@@ -1515,7 +1515,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
         let access = access_from!(self.save_ctxt, item, hir_id);
 
         match item.kind {
-            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
+            ast::ForeignItemKind::Fn(ref sig, ref generics, _) => {
+                let decl = &sig.decl;
                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(fn_data, DefData, item.span);
 
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 89054441fa3..e32f4744366 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -133,7 +133,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
             self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id))
         );
         match item.kind {
-            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
+            ast::ForeignItemKind::Fn(ref sig, ref generics, _) => {
                 filter!(self.span_utils, item.ident.span);
 
                 Some(Data::DefData(Def {
@@ -142,7 +142,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     span: self.span_from_span(item.ident.span),
                     name: item.ident.to_string(),
                     qualname,
-                    value: make_signature(decl, generics),
+                    value: make_signature(&sig.decl, generics),
                     parent: None,
                     children: vec![],
                     decl_id: None,
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index dbf29b6531d..6401cabdcd5 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -723,7 +723,8 @@ impl Sig for ast::ForeignItem {
     fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext<'_, '_>) -> Result {
         let id = Some(self.id);
         match self.kind {
-            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
+            ast::ForeignItemKind::Fn(ref sig, ref generics, _) => {
+                let decl = &sig.decl;
                 let mut text = String::new();
                 text.push_str("fn ");
 
diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs
index 9f867cf8ab4..aa05165e3de 100644
--- a/src/librustc_ty/ty.rs
+++ b/src/librustc_ty/ty.rs
@@ -206,6 +206,14 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
     }
 }
 
+fn associated_items<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::AssocItemsIterator<'tcx> {
+    ty::AssocItemsIterator {
+        items: tcx.arena.alloc_from_iter(
+            tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)),
+        ),
+    }
+}
+
 fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
     tcx.hir().span_if_local(def_id).unwrap()
 }
@@ -356,6 +364,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         asyncness,
         associated_item,
         associated_item_def_ids,
+        associated_items,
         adt_sized_constraint,
         def_span,
         param_env,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 5a8c9f76ea9..b22406124e0 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2533,6 +2533,17 @@ pub struct FnHeader {
     pub ext: Extern,
 }
 
+impl FnHeader {
+    /// Does this function header have any qualifiers or is it empty?
+    pub fn has_qualifiers(&self) -> bool {
+        let Self { unsafety, asyncness, constness, ext } = self;
+        matches!(unsafety, Unsafety::Unsafe)
+            || asyncness.node.is_async()
+            || matches!(constness.node, Constness::Const)
+            || !matches!(ext, Extern::None)
+    }
+}
+
 impl Default for FnHeader {
     fn default() -> FnHeader {
         FnHeader {
@@ -2565,7 +2576,7 @@ pub enum ItemKind {
     /// A function declaration (`fn`).
     ///
     /// E.g., `fn foo(bar: usize) -> usize { .. }`.
-    Fn(FnSig, Generics, P<Block>),
+    Fn(FnSig, Generics, Option<P<Block>>),
     /// A module declaration (`mod`).
     ///
     /// E.g., `mod foo;` or `mod foo { .. }`.
@@ -2667,7 +2678,7 @@ pub type ForeignItem = Item<ForeignItemKind>;
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub enum ForeignItemKind {
     /// A foreign function.
-    Fn(P<FnDecl>, Generics),
+    Fn(FnSig, Generics, Option<P<Block>>),
     /// A foreign static item (`static ext: u8`).
     Static(P<Ty>, Mutability),
     /// A foreign type.
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 3bcdf8fe286..8517f223f92 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -901,7 +901,7 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
         ItemKind::Fn(sig, generics, body) => {
             visit_fn_sig(sig, vis);
             vis.visit_generics(generics);
-            vis.visit_block(body);
+            visit_opt(body, |body| vis.visit_block(body));
         }
         ItemKind::Mod(m) => vis.visit_mod(m),
         ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
@@ -1044,9 +1044,10 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
     visitor.visit_ident(ident);
     visit_attrs(attrs, visitor);
     match kind {
-        ForeignItemKind::Fn(fdec, generics) => {
-            visitor.visit_fn_decl(fdec);
+        ForeignItemKind::Fn(sig, generics, body) => {
+            visit_fn_sig(sig, visitor);
             visitor.visit_generics(generics);
+            visit_opt(body, |body| visitor.visit_block(body));
         }
         ForeignItemKind::Static(t, _m) => visitor.visit_ty(t),
         ForeignItemKind::Ty => {}
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 946a0d29cd3..73e731397c3 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -19,24 +19,47 @@ use crate::tokenstream::{TokenStream, TokenTree};
 
 use rustc_span::Span;
 
+#[derive(Copy, Clone, PartialEq)]
+pub enum AssocCtxt {
+    Trait,
+    Impl,
+}
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum FnCtxt {
+    Free,
+    Foreign,
+    Assoc(AssocCtxt),
+}
+
 #[derive(Copy, Clone)]
 pub enum FnKind<'a> {
-    /// E.g., `fn foo()` or `extern "Abi" fn foo()`.
-    ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block),
-
-    /// E.g., `fn foo(&self)`.
-    Method(Ident, &'a FnSig, &'a Visibility, &'a Block),
+    /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
+    Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
 
     /// E.g., `|x, y| body`.
-    Closure(&'a Expr),
+    Closure(&'a FnDecl, &'a Expr),
 }
 
 impl<'a> FnKind<'a> {
     pub fn header(&self) -> Option<&'a FnHeader> {
         match *self {
-            FnKind::ItemFn(_, header, _, _) => Some(header),
-            FnKind::Method(_, sig, _, _) => Some(&sig.header),
-            FnKind::Closure(_) => None,
+            FnKind::Fn(_, _, sig, _, _) => Some(&sig.header),
+            FnKind::Closure(_, _) => None,
+        }
+    }
+
+    pub fn decl(&self) -> &'a FnDecl {
+        match self {
+            FnKind::Fn(_, _, sig, _, _) => &sig.decl,
+            FnKind::Closure(decl, _) => decl,
+        }
+    }
+
+    pub fn ctxt(&self) -> Option<FnCtxt> {
+        match self {
+            FnKind::Fn(ctxt, ..) => Some(*ctxt),
+            FnKind::Closure(..) => None,
         }
     }
 }
@@ -106,17 +129,11 @@ pub trait Visitor<'ast>: Sized {
     fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
         walk_where_predicate(self, p)
     }
-    fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) {
-        walk_fn(self, fk, fd, s)
-    }
-    fn visit_trait_item(&mut self, i: &'ast AssocItem) {
-        walk_trait_item(self, i)
+    fn visit_fn(&mut self, fk: FnKind<'ast>, s: Span, _: NodeId) {
+        walk_fn(self, fk, s)
     }
-    fn visit_impl_item(&mut self, i: &'ast AssocItem) {
-        walk_impl_item(self, i)
-    }
-    fn visit_assoc_item(&mut self, i: &'ast AssocItem) {
-        walk_assoc_item(self, i)
+    fn visit_assoc_item(&mut self, i: &'ast AssocItem, ctxt: AssocCtxt) {
+        walk_assoc_item(self, i, ctxt)
     }
     fn visit_trait_ref(&mut self, t: &'ast TraitRef) {
         walk_trait_ref(self, t)
@@ -287,13 +304,8 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         }
         ItemKind::Fn(ref sig, ref generics, ref body) => {
             visitor.visit_generics(generics);
-            visitor.visit_fn_header(&sig.header);
-            visitor.visit_fn(
-                FnKind::ItemFn(item.ident, &sig.header, &item.vis, body),
-                &sig.decl,
-                item.span,
-                item.id,
-            )
+            let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+            visitor.visit_fn(kind, item.span, item.id)
         }
         ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id),
         ItemKind::ForeignMod(ref foreign_module) => {
@@ -321,17 +333,17 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_trait_ref, of_trait);
             visitor.visit_ty(self_ty);
-            walk_list!(visitor, visit_impl_item, items);
+            walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Impl);
         }
         ItemKind::Struct(ref struct_definition, ref generics)
         | ItemKind::Union(ref struct_definition, ref generics) => {
             visitor.visit_generics(generics);
             visitor.visit_variant_data(struct_definition);
         }
-        ItemKind::Trait(.., ref generics, ref bounds, ref methods) => {
+        ItemKind::Trait(.., ref generics, ref bounds, ref items) => {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds);
-            walk_list!(visitor, visit_trait_item, methods);
+            walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
         }
         ItemKind::TraitAlias(ref generics, ref bounds) => {
             visitor.visit_generics(generics);
@@ -512,21 +524,22 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
     }
 }
 
-pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a ForeignItem) {
-    visitor.visit_vis(&foreign_item.vis);
-    visitor.visit_ident(foreign_item.ident);
+pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) {
+    visitor.visit_vis(&item.vis);
+    visitor.visit_ident(item.ident);
 
-    match foreign_item.kind {
-        ForeignItemKind::Fn(ref function_declaration, ref generics) => {
-            walk_fn_decl(visitor, function_declaration);
-            visitor.visit_generics(generics)
+    match item.kind {
+        ForeignItemKind::Fn(ref sig, ref generics, ref body) => {
+            visitor.visit_generics(generics);
+            let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref());
+            visitor.visit_fn(kind, item.span, item.id);
         }
         ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
         ForeignItemKind::Ty => (),
         ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac),
     }
 
-    walk_list!(visitor, visit_attribute, &foreign_item.attrs);
+    walk_list!(visitor, visit_attribute, &item.attrs);
 }
 
 pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) {
@@ -594,37 +607,21 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &
     visitor.visit_fn_ret_ty(&function_declaration.output);
 }
 
-pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl, _span: Span)
-where
-    V: Visitor<'a>,
-{
+pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Span) {
     match kind {
-        FnKind::ItemFn(_, header, _, body) => {
-            visitor.visit_fn_header(header);
-            walk_fn_decl(visitor, declaration);
-            visitor.visit_block(body);
-        }
-        FnKind::Method(_, sig, _, body) => {
+        FnKind::Fn(_, _, sig, _, body) => {
             visitor.visit_fn_header(&sig.header);
-            walk_fn_decl(visitor, declaration);
-            visitor.visit_block(body);
+            walk_fn_decl(visitor, &sig.decl);
+            walk_list!(visitor, visit_block, body);
         }
-        FnKind::Closure(body) => {
-            walk_fn_decl(visitor, declaration);
+        FnKind::Closure(decl, body) => {
+            walk_fn_decl(visitor, decl);
             visitor.visit_expr(body);
         }
     }
 }
 
-pub fn walk_impl_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
-    visitor.visit_assoc_item(item);
-}
-
-pub fn walk_trait_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
-    visitor.visit_assoc_item(item);
-}
-
-pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem) {
+pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, ctxt: AssocCtxt) {
     visitor.visit_vis(&item.vis);
     visitor.visit_ident(item.ident);
     walk_list!(visitor, visit_attribute, &item.attrs);
@@ -634,17 +631,9 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem)
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_expr, expr);
         }
-        AssocItemKind::Fn(ref sig, None) => {
-            visitor.visit_fn_header(&sig.header);
-            walk_fn_decl(visitor, &sig.decl);
-        }
-        AssocItemKind::Fn(ref sig, Some(ref body)) => {
-            visitor.visit_fn(
-                FnKind::Method(item.ident, sig, &item.vis, body),
-                &sig.decl,
-                item.span,
-                item.id,
-            );
+        AssocItemKind::Fn(ref sig, ref body) => {
+            let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
+            visitor.visit_fn(kind, item.span, item.id);
         }
         AssocItemKind::TyAlias(ref bounds, ref ty) => {
             walk_list!(visitor, visit_param_bound, bounds);
@@ -765,8 +754,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(subexpression);
             walk_list!(visitor, visit_arm, arms);
         }
-        ExprKind::Closure(_, _, _, ref function_declaration, ref body, _decl_span) => visitor
-            .visit_fn(FnKind::Closure(body), function_declaration, expression.span, expression.id),
+        ExprKind::Closure(_, _, _, ref decl, ref body, _decl_span) => {
+            visitor.visit_fn(FnKind::Closure(decl, body), expression.span, expression.id)
+        }
         ExprKind::Block(ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
diff --git a/src/test/ui/extern/extern-ffi-fn-with-body.rs b/src/test/ui/extern/extern-ffi-fn-with-body.rs
index 4cf563514ea..ef234e8afd8 100644
--- a/src/test/ui/extern/extern-ffi-fn-with-body.rs
+++ b/src/test/ui/extern/extern-ffi-fn-with-body.rs
@@ -1,5 +1,5 @@
 extern "C" {
-    fn foo() -> i32 { //~ ERROR incorrect `fn` inside `extern` block
+    fn foo() -> i32 { //~ ERROR incorrect function inside `extern` block
         return 0;
     }
 }
diff --git a/src/test/ui/extern/extern-ffi-fn-with-body.stderr b/src/test/ui/extern/extern-ffi-fn-with-body.stderr
index 4ac3ce1f93e..079c9cecd8e 100644
--- a/src/test/ui/extern/extern-ffi-fn-with-body.stderr
+++ b/src/test/ui/extern/extern-ffi-fn-with-body.stderr
@@ -1,17 +1,17 @@
-error: incorrect `fn` inside `extern` block
+error: incorrect function inside `extern` block
   --> $DIR/extern-ffi-fn-with-body.rs:2:8
    |
 LL |   extern "C" {
-   |   ------ `extern` blocks define existing foreign functions and `fn`s inside of them cannot have a body
+   |   ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
 LL |       fn foo() -> i32 {
    |  ________^^^__________-
    | |        |
-   | |        can't have a body
+   | |        cannot have a body
 LL | |         return 0;
 LL | |     }
-   | |_____- this body is invalid here
+   | |_____- help: remove the invalid body: `;`
    |
-   = help: you might have meant to write a function accessible through ffi, which can be done by writing `extern fn` outside of the `extern` block
+   = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
    = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
 
 error: aborting due to previous error
diff --git a/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs b/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs
index 7a2bf468f89..bffe43262e0 100644
--- a/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs
+++ b/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.rs
@@ -4,10 +4,10 @@
 #![stable(feature = "stable_test_feature", since = "1.0.0")]
 
 #[unstable(feature = "unstable_test_feature", issue = "0")]
-fn unstable_issue_0() {}
+fn unstable_issue_0() {} //~^ ERROR `issue` must be a non-zero numeric string or "none"
 
 #[unstable(feature = "unstable_test_feature", issue = "none")]
 fn unstable_issue_none() {}
 
 #[unstable(feature = "unstable_test_feature", issue = "something")]
-fn unstable_issue_not_allowed() {} //~^ ERROR `issue` must be a numeric string or "none"
+fn unstable_issue_not_allowed() {} //~^ ERROR `issue` must be a non-zero numeric string or "none"
diff --git a/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr b/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr
index 21ff12185ec..7bbaf92fc68 100644
--- a/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr
+++ b/src/test/ui/feature-gate/unstable-attribute-allow-issue-0.stderr
@@ -1,4 +1,12 @@
-error[E0545]: `issue` must be a numeric string or "none"
+error[E0545]: `issue` must be a non-zero numeric string or "none"
+  --> $DIR/unstable-attribute-allow-issue-0.rs:6:47
+   |
+LL | #[unstable(feature = "unstable_test_feature", issue = "0")]
+   |                                               ^^^^^^^^---
+   |                                                       |
+   |                                                       `issue` must not be "0", use "none" instead
+
+error[E0545]: `issue` must be a non-zero numeric string or "none"
   --> $DIR/unstable-attribute-allow-issue-0.rs:12:47
    |
 LL | #[unstable(feature = "unstable_test_feature", issue = "something")]
@@ -6,5 +14,5 @@ LL | #[unstable(feature = "unstable_test_feature", issue = "something")]
    |                                                       |
    |                                                       invalid digit found in string
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-39616.rs b/src/test/ui/issues/issue-39616.rs
index 3d8e28e5c2f..428856a36b4 100644
--- a/src/test/ui/issues/issue-39616.rs
+++ b/src/test/ui/issues/issue-39616.rs
@@ -1,5 +1,4 @@
 fn foo(a: [0; 1]) {} //~ ERROR expected type, found `0`
-//~| ERROR expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
-// FIXME(jseyfried): avoid emitting the second error (preexisting)
+//~| ERROR expected `;` or `{`, found `]`
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-39616.stderr b/src/test/ui/issues/issue-39616.stderr
index 74e94eda51f..ced58274661 100644
--- a/src/test/ui/issues/issue-39616.stderr
+++ b/src/test/ui/issues/issue-39616.stderr
@@ -4,11 +4,11 @@ error: expected type, found `0`
 LL | fn foo(a: [0; 1]) {}
    |            ^ expected type
 
-error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]`
+error: expected `;` or `{`, found `]`
   --> $DIR/issue-39616.rs:1:16
    |
 LL | fn foo(a: [0; 1]) {}
-   |                ^ expected one of `)`, `,`, `->`, `where`, or `{`
+   |                ^ expected `;` or `{`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lint/lint-unnecessary-parens.rs b/src/test/ui/lint/lint-unnecessary-parens.rs
index 4e8339a8e6b..5ce1f576081 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.rs
+++ b/src/test/ui/lint/lint-unnecessary-parens.rs
@@ -38,6 +38,9 @@ macro_rules! baz {
     }
 }
 
+const CONST_ITEM: usize = (10); //~ ERROR unnecessary parentheses around assigned value
+static STATIC_ITEM: usize = (10); //~ ERROR unnecessary parentheses around assigned value
+
 fn main() {
     foo();
     bar((true)); //~ ERROR unnecessary parentheses around function argument
diff --git a/src/test/ui/lint/lint-unnecessary-parens.stderr b/src/test/ui/lint/lint-unnecessary-parens.stderr
index 3663f1d98bb..8858c953273 100644
--- a/src/test/ui/lint/lint-unnecessary-parens.stderr
+++ b/src/test/ui/lint/lint-unnecessary-parens.stderr
@@ -34,26 +34,38 @@ error: unnecessary parentheses around block return value
 LL |     (5)
    |     ^^^ help: remove these parentheses
 
+error: unnecessary parentheses around assigned value
+  --> $DIR/lint-unnecessary-parens.rs:41:27
+   |
+LL | const CONST_ITEM: usize = (10);
+   |                           ^^^^ help: remove these parentheses
+
+error: unnecessary parentheses around assigned value
+  --> $DIR/lint-unnecessary-parens.rs:42:29
+   |
+LL | static STATIC_ITEM: usize = (10);
+   |                             ^^^^ help: remove these parentheses
+
 error: unnecessary parentheses around function argument
-  --> $DIR/lint-unnecessary-parens.rs:43:9
+  --> $DIR/lint-unnecessary-parens.rs:46:9
    |
 LL |     bar((true));
    |         ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `if` condition
-  --> $DIR/lint-unnecessary-parens.rs:45:8
+  --> $DIR/lint-unnecessary-parens.rs:48:8
    |
 LL |     if (true) {}
    |        ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `while` condition
-  --> $DIR/lint-unnecessary-parens.rs:46:11
+  --> $DIR/lint-unnecessary-parens.rs:49:11
    |
 LL |     while (true) {}
    |           ^^^^^^ help: remove these parentheses
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/lint-unnecessary-parens.rs:46:5
+  --> $DIR/lint-unnecessary-parens.rs:49:5
    |
 LL |     while (true) {}
    |     ^^^^^^^^^^^^ help: use `loop`
@@ -61,46 +73,46 @@ LL |     while (true) {}
    = note: `#[warn(while_true)]` on by default
 
 error: unnecessary parentheses around `match` head expression
-  --> $DIR/lint-unnecessary-parens.rs:48:11
+  --> $DIR/lint-unnecessary-parens.rs:51:11
    |
 LL |     match (true) {
    |           ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `let` head expression
-  --> $DIR/lint-unnecessary-parens.rs:51:16
+  --> $DIR/lint-unnecessary-parens.rs:54:16
    |
 LL |     if let 1 = (1) {}
    |                ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around `let` head expression
-  --> $DIR/lint-unnecessary-parens.rs:52:19
+  --> $DIR/lint-unnecessary-parens.rs:55:19
    |
 LL |     while let 1 = (2) {}
    |                   ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around method argument
-  --> $DIR/lint-unnecessary-parens.rs:66:24
+  --> $DIR/lint-unnecessary-parens.rs:69:24
    |
 LL |     X { y: false }.foo((true));
    |                        ^^^^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:68:18
+  --> $DIR/lint-unnecessary-parens.rs:71:18
    |
 LL |     let mut _a = (0);
    |                  ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:69:10
+  --> $DIR/lint-unnecessary-parens.rs:72:10
    |
 LL |     _a = (0);
    |          ^^^ help: remove these parentheses
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:70:11
+  --> $DIR/lint-unnecessary-parens.rs:73:11
    |
 LL |     _a += (1);
    |           ^^^ help: remove these parentheses
 
-error: aborting due to 15 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr
index 1139ef06a12..92d1afe1b64 100644
--- a/src/test/ui/macros/issue-54441.stderr
+++ b/src/test/ui/macros/issue-54441.stderr
@@ -1,8 +1,8 @@
-error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found keyword `let`
+error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `static`, `type`, or `unsafe`, found keyword `let`
   --> $DIR/issue-54441.rs:3:9
    |
 LL |         let
-   |         ^^^ expected one of `crate`, `fn`, `pub`, `static`, or `type`
+   |         ^^^ expected one of 9 possible tokens
 ...
 LL |     m!();
    |     ----- in this macro invocation
diff --git a/src/test/ui/missing_debug_impls.rs b/src/test/ui/missing_debug_impls.rs
index ff919292ae2..72fcba51588 100644
--- a/src/test/ui/missing_debug_impls.rs
+++ b/src/test/ui/missing_debug_impls.rs
@@ -4,7 +4,7 @@
 
 use std::fmt;
 
-pub enum A {} //~ ERROR type does not implement `fmt::Debug`
+pub enum A {} //~ ERROR type does not implement `std::fmt::Debug`
 
 #[derive(Debug)]
 pub enum B {}
@@ -17,7 +17,7 @@ impl fmt::Debug for C {
     }
 }
 
-pub struct Foo; //~ ERROR type does not implement `fmt::Debug`
+pub struct Foo; //~ ERROR type does not implement `std::fmt::Debug`
 
 #[derive(Debug)]
 pub struct Bar;
diff --git a/src/test/ui/missing_debug_impls.stderr b/src/test/ui/missing_debug_impls.stderr
index 5f8adb791f6..51c65589b0c 100644
--- a/src/test/ui/missing_debug_impls.stderr
+++ b/src/test/ui/missing_debug_impls.stderr
@@ -1,4 +1,4 @@
-error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
+error: type does not implement `std::fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
   --> $DIR/missing_debug_impls.rs:7:1
    |
 LL | pub enum A {}
@@ -10,7 +10,7 @@ note: the lint level is defined here
 LL | #![deny(missing_debug_implementations)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
+error: type does not implement `std::fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
   --> $DIR/missing_debug_impls.rs:20:1
    |
 LL | pub struct Foo;
diff --git a/src/test/ui/no-patterns-in-args-2.rs b/src/test/ui/no-patterns-in-args-2.rs
index ccf57478b48..85b7fc5cdba 100644
--- a/src/test/ui/no-patterns-in-args-2.rs
+++ b/src/test/ui/no-patterns-in-args-2.rs
@@ -1,9 +1,9 @@
 #![deny(patterns_in_fns_without_body)]
 
 trait Tr {
-    fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
+    fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in functions without bodies
                         //~^ WARN was previously accepted
-    fn f2(&arg: u8); //~ ERROR patterns aren't allowed in methods without bodies
+    fn f2(&arg: u8); //~ ERROR patterns aren't allowed in functions without bodies
     fn g1(arg: u8); // OK
     fn g2(_: u8); // OK
     #[allow(anonymous_parameters)]
diff --git a/src/test/ui/no-patterns-in-args-2.stderr b/src/test/ui/no-patterns-in-args-2.stderr
index 905a89af4e5..21f4439d890 100644
--- a/src/test/ui/no-patterns-in-args-2.stderr
+++ b/src/test/ui/no-patterns-in-args-2.stderr
@@ -1,10 +1,10 @@
-error[E0642]: patterns aren't allowed in methods without bodies
+error[E0642]: patterns aren't allowed in functions without bodies
   --> $DIR/no-patterns-in-args-2.rs:6:11
    |
 LL |     fn f2(&arg: u8);
-   |           ^^^^
+   |           ^^^^ pattern not allowed in function without body
 
-error: patterns aren't allowed in methods without bodies
+error: patterns aren't allowed in functions without bodies
   --> $DIR/no-patterns-in-args-2.rs:4:11
    |
 LL |     fn f1(mut arg: u8);
diff --git a/src/test/ui/no-patterns-in-args-macro.rs b/src/test/ui/no-patterns-in-args-macro.rs
index 59cb9945398..b5109f9c286 100644
--- a/src/test/ui/no-patterns-in-args-macro.rs
+++ b/src/test/ui/no-patterns-in-args-macro.rs
@@ -6,10 +6,10 @@ macro_rules! m {
 
         type A = fn($pat: u8);
 
-        extern {
+        extern "C" {
             fn foreign_fn($pat: u8);
         }
-    }
+    };
 }
 
 mod good_pat {
@@ -20,7 +20,7 @@ mod bad_pat {
     m!((bad, pat));
     //~^ ERROR patterns aren't allowed in function pointer types
     //~| ERROR patterns aren't allowed in foreign function declarations
-    //~| ERROR patterns aren't allowed in methods without bodies
+    //~| ERROR patterns aren't allowed in functions without bodies
 }
 
 fn main() {}
diff --git a/src/test/ui/no-patterns-in-args-macro.stderr b/src/test/ui/no-patterns-in-args-macro.stderr
index f21df68d5a2..0016c7953f3 100644
--- a/src/test/ui/no-patterns-in-args-macro.stderr
+++ b/src/test/ui/no-patterns-in-args-macro.stderr
@@ -1,8 +1,8 @@
-error[E0642]: patterns aren't allowed in methods without bodies
+error[E0642]: patterns aren't allowed in functions without bodies
   --> $DIR/no-patterns-in-args-macro.rs:20:8
    |
 LL |     m!((bad, pat));
-   |        ^^^^^^^^^^
+   |        ^^^^^^^^^^ pattern not allowed in function without body
 
 error[E0561]: patterns aren't allowed in function pointer types
   --> $DIR/no-patterns-in-args-macro.rs:20:8
diff --git a/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs b/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs
new file mode 100644
index 00000000000..1a65a1e544b
--- /dev/null
+++ b/src/test/ui/or-patterns/issue-68785-irrefutable-param-with-at.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+#![feature(or_patterns)]
+
+enum MyEnum {
+    FirstCase(u8),
+    OtherCase(u16),
+}
+
+fn my_fn(x @ (MyEnum::FirstCase(_) | MyEnum::OtherCase(_)): MyEnum) {}
+
+fn main() {
+    my_fn(MyEnum::FirstCase(0));
+}
diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs
index bb17e97e950..a8f0b7d61b9 100644
--- a/src/test/ui/parser/duplicate-visibility.rs
+++ b/src/test/ui/parser/duplicate-visibility.rs
@@ -1,4 +1,4 @@
-// error-pattern:expected one of `(`, `fn`, `static`, or `type`
+// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn`
 extern {
     pub pub fn foo();
 }
diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr
index 313e88e812b..cba4058e482 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 `(`, `fn`, `static`, or `type`, found keyword `pub`
+error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub`
   --> $DIR/duplicate-visibility.rs:3:9
    |
 LL |     pub pub fn foo();
-   |         ^^^ expected one of `(`, `fn`, `static`, or `type`
+   |         ^^^ expected one of 8 possible tokens
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/fn-body-optional-semantic-fail.rs b/src/test/ui/parser/fn-body-optional-semantic-fail.rs
new file mode 100644
index 00000000000..38def05e8f2
--- /dev/null
+++ b/src/test/ui/parser/fn-body-optional-semantic-fail.rs
@@ -0,0 +1,27 @@
+// Tests the different rules for `fn` forms requiring the presence or lack of a body.
+
+fn main() {
+    fn f1(); //~ ERROR free function without a body
+    fn f2() {} // OK.
+
+    trait X {
+        fn f1(); // OK.
+        fn f2() {} // OK.
+    }
+
+    struct Y;
+    impl X for Y {
+        fn f1(); //~ ERROR associated function in `impl` without body
+        fn f2() {} // OK.
+    }
+
+    impl Y {
+        fn f3(); //~ ERROR associated function in `impl` without body
+        fn f4() {} // OK.
+    }
+
+    extern {
+        fn f5(); // OK.
+        fn f6() {} //~ ERROR incorrect function inside `extern` block
+    }
+}
diff --git a/src/test/ui/parser/fn-body-optional-semantic-fail.stderr b/src/test/ui/parser/fn-body-optional-semantic-fail.stderr
new file mode 100644
index 00000000000..23ce98fb5d7
--- /dev/null
+++ b/src/test/ui/parser/fn-body-optional-semantic-fail.stderr
@@ -0,0 +1,40 @@
+error: free function without a body
+  --> $DIR/fn-body-optional-semantic-fail.rs:4:5
+   |
+LL |     fn f1();
+   |     ^^^^^^^-
+   |            |
+   |            help: provide a definition for the function: `{ <body> }`
+
+error: associated function in `impl` without body
+  --> $DIR/fn-body-optional-semantic-fail.rs:14:9
+   |
+LL |         fn f1();
+   |         ^^^^^^^-
+   |                |
+   |                help: provide a definition for the function: `{ <body> }`
+
+error: associated function in `impl` without body
+  --> $DIR/fn-body-optional-semantic-fail.rs:19:9
+   |
+LL |         fn f3();
+   |         ^^^^^^^-
+   |                |
+   |                help: provide a definition for the function: `{ <body> }`
+
+error: incorrect function inside `extern` block
+  --> $DIR/fn-body-optional-semantic-fail.rs:25:12
+   |
+LL |     extern {
+   |     ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+LL |         fn f5(); // OK.
+LL |         fn f6() {}
+   |            ^^   -- help: remove the invalid body: `;`
+   |            |
+   |            cannot have a body
+   |
+   = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/parser/fn-body-optional-syntactic-pass.rs b/src/test/ui/parser/fn-body-optional-syntactic-pass.rs
new file mode 100644
index 00000000000..e7991c73b4b
--- /dev/null
+++ b/src/test/ui/parser/fn-body-optional-syntactic-pass.rs
@@ -0,0 +1,31 @@
+// Ensures that all `fn` forms having or lacking a body are syntactically valid.
+
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    fn f();
+    fn f() {}
+
+    trait X {
+        fn f();
+        fn f() {}
+    }
+
+    impl X for Y {
+        fn f();
+        fn f() {}
+    }
+
+    impl Y {
+        fn f();
+        fn f() {}
+    }
+
+    extern {
+        fn f();
+        fn f() {}
+    }
+}
diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
new file mode 100644
index 00000000000..c2b7e69c80d
--- /dev/null
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -0,0 +1,57 @@
+// Ensures that all `fn` forms can have all the function qualifiers syntactically.
+
+// edition:2018
+
+#![feature(const_extern_fn)]
+#![feature(const_fn)]
+
+fn main() {
+    async fn ff1() {} // OK.
+    unsafe fn ff2() {} // OK.
+    const fn ff3() {} // OK.
+    extern "C" fn ff4() {} // OK.
+    const /* async */ unsafe extern "C" fn ff5() {} // OK.
+    //^ FIXME(Centril): `async` should be legal syntactically, ensure it's illegal semantically.
+
+    trait X {
+        async fn ft1(); //~ ERROR trait fns cannot be declared `async`
+        unsafe fn ft2(); // OK.
+        const fn ft3(); //~ ERROR trait fns cannot be declared const
+        extern "C" fn ft4(); // OK.
+        /* const */ async unsafe extern "C" fn ft5();
+        //~^ ERROR trait fns cannot be declared `async`
+        //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
+    }
+
+    struct Y;
+    impl X for Y {
+        async fn ft1() {} //~ ERROR trait fns cannot be declared `async`
+        //~^ ERROR method `ft1` has an incompatible type for trait
+        unsafe fn ft2() {} // OK.
+        const fn ft3() {} //~ ERROR trait fns cannot be declared const
+        extern "C" fn ft4() {}
+        /* const */ async unsafe extern "C" fn ft5() {}
+        //~^ ERROR trait fns cannot be declared `async`
+        //~| ERROR method `ft5` has an incompatible type for trait
+        //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
+    }
+
+    impl Y {
+        async fn fi1() {} // OK.
+        unsafe fn fi2() {} // OK.
+        const fn fi3() {} // OK.
+        extern "C" fn fi4() {} // OK.
+        /* const */ async unsafe extern "C" fn fi5() {} // OK.
+        //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
+    }
+
+    extern {
+        async fn fe1(); //~ ERROR functions in `extern` blocks cannot have qualifiers
+        unsafe fn fe2(); //~ ERROR functions in `extern` blocks cannot have qualifiers
+        const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers
+        extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers
+        /* const */ async unsafe extern "C" fn fe5();
+        //~^ ERROR functions in `extern` blocks cannot have qualifiers
+        //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
+    }
+}
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
new file mode 100644
index 00000000000..41d2d9b7faa
--- /dev/null
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -0,0 +1,136 @@
+error[E0706]: trait fns cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:17:9
+   |
+LL |         async fn ft1();
+   |         ^^^^^^^^^^^^^^^
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/fn-header-semantic-fail.rs:19:9
+   |
+LL |         const fn ft3();
+   |         ^^^^^ trait fns cannot be const
+
+error[E0706]: trait fns cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:21:21
+   |
+LL |         /* const */ async unsafe extern "C" fn ft5();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+error[E0706]: trait fns cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:28:9
+   |
+LL |         async fn ft1() {}
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/fn-header-semantic-fail.rs:31:9
+   |
+LL |         const fn ft3() {}
+   |         ^^^^^ trait fns cannot be const
+
+error[E0706]: trait fns cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:33:21
+   |
+LL |         /* const */ async unsafe extern "C" fn ft5() {}
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:49:18
+   |
+LL |     extern {
+   |     ------ in this `extern` block
+LL |         async fn fe1();
+   |         ---------^^^
+   |         |
+   |         help: remove the qualifiers: `fn`
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:50:19
+   |
+LL |     extern {
+   |     ------ in this `extern` block
+LL |         async fn fe1();
+LL |         unsafe fn fe2();
+   |         ----------^^^
+   |         |
+   |         help: remove the qualifiers: `fn`
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:51:18
+   |
+LL |     extern {
+   |     ------ in this `extern` block
+...
+LL |         const fn fe3();
+   |         ---------^^^
+   |         |
+   |         help: remove the qualifiers: `fn`
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:52:23
+   |
+LL |     extern {
+   |     ------ in this `extern` block
+...
+LL |         extern "C" fn fe4();
+   |         --------------^^^
+   |         |
+   |         help: remove the qualifiers: `fn`
+
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/fn-header-semantic-fail.rs:53:48
+   |
+LL |     extern {
+   |     ------ in this `extern` block
+...
+LL |         /* const */ async unsafe extern "C" fn fe5();
+   |                     ---------------------------^^^
+   |                     |
+   |                     help: remove the qualifiers: `fn`
+
+error[E0053]: method `ft1` has an incompatible type for trait
+  --> $DIR/fn-header-semantic-fail.rs:28:24
+   |
+LL |         async fn ft1();
+   |                       - type in trait
+...
+LL |         async fn ft1() {}
+   |                        ^
+   |                        |
+   |                        the `Output` of this `async fn`'s found opaque type
+   |                        expected `()`, found opaque type
+   |
+   = note: expected fn pointer `fn()`
+              found fn pointer `fn() -> impl std::future::Future`
+
+error[E0053]: method `ft5` has an incompatible type for trait
+  --> $DIR/fn-header-semantic-fail.rs:33:54
+   |
+LL |         /* const */ async unsafe extern "C" fn ft5();
+   |                                                     - type in trait
+...
+LL |         /* const */ async unsafe extern "C" fn ft5() {}
+   |                                                      ^
+   |                                                      |
+   |                                                      the `Output` of this `async fn`'s found opaque type
+   |                                                      expected `()`, found opaque type
+   |
+   = note: expected fn pointer `unsafe extern "C" fn()`
+              found fn pointer `unsafe extern "C" fn() -> impl std::future::Future`
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0053, E0379, E0706.
+For more information about an error, try `rustc --explain E0053`.
diff --git a/src/test/ui/parser/fn-header-syntactic-pass.rs b/src/test/ui/parser/fn-header-syntactic-pass.rs
new file mode 100644
index 00000000000..145a208cb24
--- /dev/null
+++ b/src/test/ui/parser/fn-header-syntactic-pass.rs
@@ -0,0 +1,55 @@
+// Ensures that all `fn` forms can have all the function qualifiers syntactically.
+
+// check-pass
+// edition:2018
+
+#![feature(const_extern_fn)]
+//^ FIXME(Centril): move check to ast_validation.
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    async fn f();
+    unsafe fn f();
+    const fn f();
+    extern "C" fn f();
+    const /* async */ unsafe extern "C" fn f();
+    //^ FIXME(Centril): `async` should be legal syntactically.
+
+    trait X {
+        async fn f();
+        unsafe fn f();
+        const fn f();
+        extern "C" fn f();
+        /* const */ async unsafe extern "C" fn f();
+        //^ FIXME(Centril): `const` should be legal syntactically.
+    }
+
+    impl X for Y {
+        async fn f();
+        unsafe fn f();
+        const fn f();
+        extern "C" fn f();
+        /* const */ async unsafe extern "C" fn f();
+        //^ FIXME(Centril): `const` should be legal syntactically.
+    }
+
+    impl Y {
+        async fn f();
+        unsafe fn f();
+        const fn f();
+        extern "C" fn f();
+        /* const */ async unsafe extern "C" fn f();
+        //^ FIXME(Centril): `const` should be legal syntactically.
+    }
+
+    extern {
+        async fn f();
+        unsafe fn f();
+        const fn f();
+        extern "C" fn f();
+        /* const */ async unsafe extern "C" fn f();
+        //^ FIXME(Centril): `const` should be legal syntactically.
+    }
+}
diff --git a/src/test/ui/parser/issue-24780.rs b/src/test/ui/parser/issue-24780.rs
index 799cdd80222..8b46aa2bf22 100644
--- a/src/test/ui/parser/issue-24780.rs
+++ b/src/test/ui/parser/issue-24780.rs
@@ -3,6 +3,6 @@
 // expected one of ..., `>`, ... found `>`
 
 fn foo() -> Vec<usize>> {
-    //~^ ERROR expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
+    //~^ ERROR expected `;` or `{`, found `>`
     Vec::new()
 }
diff --git a/src/test/ui/parser/issue-24780.stderr b/src/test/ui/parser/issue-24780.stderr
index d9470191b25..d65a5f44873 100644
--- a/src/test/ui/parser/issue-24780.stderr
+++ b/src/test/ui/parser/issue-24780.stderr
@@ -1,8 +1,8 @@
-error: expected one of `!`, `+`, `::`, `where`, or `{`, found `>`
+error: expected `;` or `{`, found `>`
   --> $DIR/issue-24780.rs:5:23
    |
 LL | fn foo() -> Vec<usize>> {
-   |                       ^ expected one of `!`, `+`, `::`, `where`, or `{`
+   |                       ^ expected `;` or `{`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/issue-63135.rs b/src/test/ui/parser/issue-63135.rs
index d5f5f1469f3..7d46b8904f0 100644
--- a/src/test/ui/parser/issue-63135.rs
+++ b/src/test/ui/parser/issue-63135.rs
@@ -1,3 +1,3 @@
-// error-pattern: aborting due to 6 previous errors
+// error-pattern: aborting due to 7 previous errors
 
 fn i(n{...,f #
diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr
index 462fdf11f40..04afae93be0 100644
--- a/src/test/ui/parser/issue-63135.stderr
+++ b/src/test/ui/parser/issue-63135.stderr
@@ -43,5 +43,11 @@ error: expected one of `:` or `|`, found `)`
 LL | fn i(n{...,f #
    |                ^ expected one of `:` or `|`
 
-error: aborting due to 6 previous errors
+error: expected `;` or `{`, found `<eof>`
+  --> $DIR/issue-63135.rs:3:16
+   |
+LL | fn i(n{...,f #
+   |                ^ expected `;` or `{`
+
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/parser/issue-68730.stderr b/src/test/ui/parser/issue-68730.stderr
index 5f9ed56e2d7..090b41d839f 100644
--- a/src/test/ui/parser/issue-68730.stderr
+++ b/src/test/ui/parser/issue-68730.stderr
Binary files differdiff --git a/src/test/ui/parser/issue-68788-in-trait-item-propagation.rs b/src/test/ui/parser/issue-68788-in-trait-item-propagation.rs
new file mode 100644
index 00000000000..7c3dd1d5a98
--- /dev/null
+++ b/src/test/ui/parser/issue-68788-in-trait-item-propagation.rs
@@ -0,0 +1,21 @@
+// Make sure we don't propagate restrictions on trait impl items to items inside them.
+
+// check-pass
+// edition:2018
+
+fn main() {}
+
+trait X {
+    fn foo();
+}
+
+impl X for () {
+    fn foo() {
+        struct S;
+        impl S {
+            pub const X: u8 = 0;
+            pub const fn bar() {}
+            async fn qux() {}
+        }
+    }
+}
diff --git a/src/test/ui/parser/missing_right_paren.rs b/src/test/ui/parser/missing_right_paren.rs
index c35236ce793..810dee9571d 100644
--- a/src/test/ui/parser/missing_right_paren.rs
+++ b/src/test/ui/parser/missing_right_paren.rs
@@ -1,3 +1,3 @@
 // ignore-tidy-trailing-newlines
-// error-pattern: aborting due to 3 previous errors
+// error-pattern: aborting due to 4 previous errors
 fn main((ؼ
\ No newline at end of file
diff --git a/src/test/ui/parser/missing_right_paren.stderr b/src/test/ui/parser/missing_right_paren.stderr
index d67e7c88912..c1ceb81a07c 100644
--- a/src/test/ui/parser/missing_right_paren.stderr
+++ b/src/test/ui/parser/missing_right_paren.stderr
@@ -22,5 +22,11 @@ error: expected one of `:` or `|`, found `)`
 LL | fn main((ؼ
    |           ^ expected one of `:` or `|`
 
-error: aborting due to 3 previous errors
+error: expected `;` or `{`, found `<eof>`
+  --> $DIR/missing_right_paren.rs:3:11
+   |
+LL | fn main((ؼ
+   |           ^ expected `;` or `{`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.rs b/src/test/ui/parser/no-const-fn-in-extern-block.rs
index 29f26389ded..4cae703a163 100644
--- a/src/test/ui/parser/no-const-fn-in-extern-block.rs
+++ b/src/test/ui/parser/no-const-fn-in-extern-block.rs
@@ -1,8 +1,8 @@
 extern {
     const fn foo();
-    //~^ ERROR extern items cannot be `const`
+    //~^ ERROR functions in `extern` blocks cannot have qualifiers
     const unsafe fn bar();
-    //~^ ERROR extern items cannot be `const`
+    //~^ ERROR functions in `extern` blocks cannot have qualifiers
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/no-const-fn-in-extern-block.stderr b/src/test/ui/parser/no-const-fn-in-extern-block.stderr
index 5b4663a702f..de653987e40 100644
--- a/src/test/ui/parser/no-const-fn-in-extern-block.stderr
+++ b/src/test/ui/parser/no-const-fn-in-extern-block.stderr
@@ -1,14 +1,23 @@
-error: extern items cannot be `const`
-  --> $DIR/no-const-fn-in-extern-block.rs:2:5
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/no-const-fn-in-extern-block.rs:2:14
    |
+LL | extern {
+   | ------ in this `extern` block
 LL |     const fn foo();
-   |     ^^^^^
+   |     ---------^^^
+   |     |
+   |     help: remove the qualifiers: `fn`
 
-error: extern items cannot be `const`
-  --> $DIR/no-const-fn-in-extern-block.rs:4:5
+error: functions in `extern` blocks cannot have qualifiers
+  --> $DIR/no-const-fn-in-extern-block.rs:4:21
    |
+LL | extern {
+   | ------ in this `extern` block
+...
 LL |     const unsafe fn bar();
-   |     ^^^^^
+   |     ----------------^^^
+   |     |
+   |     help: remove the qualifiers: `fn`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr
index 90246b92bf0..dce54655fa0 100644
--- a/src/test/ui/parser/not-a-pred.stderr
+++ b/src/test/ui/parser/not-a-pred.stderr
@@ -1,8 +1,8 @@
-error: expected one of `->`, `where`, or `{`, found `:`
+error: expected `;` or `{`, found `:`
   --> $DIR/not-a-pred.rs:3:26
    |
 LL | fn f(a: isize, b: isize) : lt(a, b) { }
-   |                          ^ expected one of `->`, `where`, or `{`
+   |                          ^ expected `;` or `{`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.rs b/src/test/ui/stability-attribute/stability-attribute-sanity-2.rs
index e74147ce900..de3ea4eaca9 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.rs
@@ -10,7 +10,8 @@ fn f1() { }
 #[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse'
 fn f2() { }
 
-#[unstable(feature = "a", issue = "no")] //~ ERROR `issue` must be a numeric string or "none"
+#[unstable(feature = "a", issue = "no")]
+//~^ ERROR `issue` must be a non-zero numeric string or "none"
 fn f3() { }
 
 fn main() { }
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
index 541b94afe0f..3b826191899 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity-2.stderr
@@ -10,7 +10,7 @@ error[E0541]: unknown meta item 'sinse'
 LL | #[stable(feature = "a", sinse = "1.0.0")]
    |                         ^^^^^^^^^^^^^^^ expected one of `since`, `note`
 
-error[E0545]: `issue` must be a numeric string or "none"
+error[E0545]: `issue` must be a non-zero numeric string or "none"
   --> $DIR/stability-attribute-sanity-2.rs:13:27
    |
 LL | #[unstable(feature = "a", issue = "no")]
diff --git a/src/test/ui/super-fast-paren-parsing.rs b/src/test/ui/super-fast-paren-parsing.rs
index 60c8db53a8c..cb42ff2c644 100644
--- a/src/test/ui/super-fast-paren-parsing.rs
+++ b/src/test/ui/super-fast-paren-parsing.rs
@@ -1,5 +1,6 @@
 // run-pass
 
+#![allow(unused_parens)]
 #![allow(non_upper_case_globals)]
 #![allow(dead_code)]
 // exec-env:RUST_MIN_STACK=16000000