about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-02-13 09:42:10 +0000
committerbors <bors@rust-lang.org>2020-02-13 09:42:10 +0000
commitbe493fe8cc40c3d3f6030a1313c1ff747fce770d (patch)
treef5f5389477017c943087b76cdbec10c1a58b5b53
parent2e6eaceedeeda764056eb0e2134735793533770d (diff)
parent9828559aad8672bb320517bd0fa1992ce144b848 (diff)
downloadrust-be493fe8cc40c3d3f6030a1313c1ff747fce770d.tar.gz
rust-be493fe8cc40c3d3f6030a1313c1ff747fce770d.zip
Auto merge of #69023 - Centril:parse_fn, r=petrochenkov
parse: unify function front matter parsing

Part of https://github.com/rust-lang/rust/pull/68728.

- `const extern fn` feature gating is now done post-expansion such that we do not have conditional compatibilities of function qualifiers *in parsing*.

- The `FnFrontMatter` grammar becomes:
   ```rust
   Extern = "extern" StringLit ;
   FnQual = "const"? "async"? "unsafe"? Extern? ;
   FnFrontMatter = FnQual "fn" ;
   ```

   That is, all item contexts now *syntactically* allow `const async unsafe extern "C" fn` and use semantic restrictions to rule out combinations previously prevented syntactically. The semantic restrictions include in particular:

   - `fn`s in `extern { ... }` can have no qualifiers.
   - `const` and `async` cannot be combined.

- We change `ast::{Unsafety, Spanned<Constness>}>` into `enum ast::{Unsafe, Const} { Yes(Span), No }` respectively. This change in formulation allow us to exclude `Span` in the case of `No`, which facilitates parsing. Moreover, we also add a `Span` to `IsAsync` which is renamed to `Async`. The new `Span`s in `Unsafety` and `Async` are then taken advantage of for better diagnostics. A reason this change was made is to have a more uniform and clear naming scheme.

  The HIR keeps the structures in AST (with those definitions moved into HIR) for now to avoid regressing perf.

r? @petrochenkov
-rw-r--r--src/librustc/traits/auto_trait.rs3
-rw-r--r--src/librustc/traits/error_reporting/mod.rs2
-rw-r--r--src/librustc/traits/select.rs8
-rw-r--r--src/librustc/ty/fold.rs3
-rw-r--r--src/librustc/ty/mod.rs4
-rw-r--r--src/librustc/ty/print/pretty.rs2
-rw-r--r--src/librustc/ty/structural_impls.rs4
-rw-r--r--src/librustc_ast_lowering/expr.rs2
-rw-r--r--src/librustc_ast_lowering/item.rs57
-rw-r--r--src/librustc_ast_lowering/lib.rs2
-rw-r--r--src/librustc_ast_passes/ast_validation.rs67
-rw-r--r--src/librustc_ast_passes/feature_gate.rs15
-rw-r--r--src/librustc_ast_pretty/pprust.rs24
-rw-r--r--src/librustc_builtin_macros/deriving/generic/mod.rs6
-rw-r--r--src/librustc_builtin_macros/deriving/mod.rs4
-rw-r--r--src/librustc_builtin_macros/global_allocator.rs4
-rw-r--r--src/librustc_builtin_macros/test.rs12
-rw-r--r--src/librustc_expand/build.rs4
-rw-r--r--src/librustc_hir/hir.rs48
-rw-r--r--src/librustc_hir/print.rs2
-rw-r--r--src/librustc_interface/util.rs2
-rw-r--r--src/librustc_lint/builtin.rs6
-rw-r--r--src/librustc_mir/borrow_check/type_check/mod.rs5
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs3
-rw-r--r--src/librustc_parse/parser/expr.rs4
-rw-r--r--src/librustc_parse/parser/item.rs365
-rw-r--r--src/librustc_parse/parser/mod.rs34
-rw-r--r--src/librustc_parse/parser/stmt.rs2
-rw-r--r--src/librustc_parse/parser/ty.rs4
-rw-r--r--src/librustc_resolve/def_collector.rs12
-rw-r--r--src/librustc_resolve/late.rs2
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs8
-rw-r--r--src/librustc_save_analysis/sig.rs20
-rw-r--r--src/librustc_typeck/astconv.rs6
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/collect.rs10
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/doctree.rs2
-rw-r--r--src/libsyntax/ast.rs94
-rw-r--r--src/libsyntax/mut_visit.rs10
-rw-r--r--src/libsyntax/token.rs8
-rw-r--r--src/libsyntax/util/literal.rs2
-rw-r--r--src/test/ui-fulldeps/pprust-expr-roundtrip.rs2
-rw-r--r--src/test/ui/async-await/async-trait-fn.rs4
-rw-r--r--src/test/ui/async-await/async-trait-fn.stderr12
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.rs2
-rw-r--r--src/test/ui/async-await/edition-deny-async-fns-2015.stderr42
-rw-r--r--src/test/ui/async-await/no-async-const.rs2
-rw-r--r--src/test/ui/async-await/no-async-const.stderr4
-rw-r--r--src/test/ui/async-await/no-const-async.rs3
-rw-r--r--src/test/ui/async-await/no-const-async.stderr17
-rw-r--r--src/test/ui/async-await/no-unsafe-async.rs2
-rw-r--r--src/test/ui/async-await/no-unsafe-async.stderr4
-rw-r--r--src/test/ui/coherence/coherence-negative-impls-safe.stderr4
-rw-r--r--src/test/ui/const-generics/const-fn-with-const-param.rs2
-rw-r--r--src/test/ui/const-generics/const-fn-with-const-param.stderr8
-rw-r--r--src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs14
-rw-r--r--src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr36
-rw-r--r--src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs1
-rw-r--r--src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr12
-rw-r--r--src/test/ui/consts/const-fn-mismatch.rs8
-rw-r--r--src/test/ui/consts/const-fn-mismatch.stderr6
-rw-r--r--src/test/ui/consts/const-fn-not-in-trait.rs10
-rw-r--r--src/test/ui/consts/const-fn-not-in-trait.stderr10
-rw-r--r--src/test/ui/error-codes/E0197.stderr4
-rw-r--r--src/test/ui/error-codes/E0198.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_fn.rs6
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_fn.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-min_const_fn.rs6
-rw-r--r--src/test/ui/feature-gates/feature-gate-min_const_fn.stderr12
-rw-r--r--src/test/ui/issues/issue-54954.rs2
-rw-r--r--src/test/ui/issues/issue-54954.stderr4
-rw-r--r--src/test/ui/issues/issue-60075.rs1
-rw-r--r--src/test/ui/issues/issue-60075.stderr8
-rw-r--r--src/test/ui/label/label_break_value_illegal_uses.rs2
-rw-r--r--src/test/ui/label/label_break_value_illegal_uses.stderr4
-rw-r--r--src/test/ui/mismatched_types/const-fn-in-trait.stderr8
-rw-r--r--src/test/ui/parser/extern-crate-async.rs12
-rw-r--r--src/test/ui/parser/extern-crate-unexpected-token.rs2
-rw-r--r--src/test/ui/parser/extern-crate-unexpected-token.stderr4
-rw-r--r--src/test/ui/parser/extern-expected-fn-or-brace.rs5
-rw-r--r--src/test/ui/parser/extern-expected-fn-or-brace.stderr6
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.rs35
-rw-r--r--src/test/ui/parser/fn-header-semantic-fail.stderr139
-rw-r--r--src/test/ui/parser/fn-header-syntactic-pass.rs18
-rw-r--r--src/test/ui/parser/issue-19398.rs2
-rw-r--r--src/test/ui/parser/issue-19398.stderr8
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr16
-rw-r--r--src/test/ui/syntax-trait-polarity.stderr8
-rw-r--r--src/test/ui/traits/trait-safety-inherent-impl.stderr6
-rw-r--r--src/test/ui/unsafe/unsafe-block-without-braces.rs2
-rw-r--r--src/test/ui/unsafe/unsafe-block-without-braces.stderr4
94 files changed, 737 insertions, 694 deletions
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index 1255728de37..3ab87ce8eb4 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -9,7 +9,6 @@ use crate::ty::fold::TypeFolder;
 use crate::ty::{Region, RegionVid};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use syntax::ast;
 
 use std::collections::hash_map::Entry;
 use std::collections::VecDeque;
@@ -350,7 +349,7 @@ impl AutoTraitFinder<'tcx> {
                         already_visited.remove(&pred);
                         self.add_user_pred(
                             &mut user_computed_preds,
-                            ty::Predicate::Trait(pred, ast::Constness::NotConst),
+                            ty::Predicate::Trait(pred, hir::Constness::NotConst),
                         );
                         predicates.push_back(pred);
                     } else {
diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs
index a7a2b578b82..c25b392ec23 100644
--- a/src/librustc/traits/error_reporting/mod.rs
+++ b/src/librustc/traits/error_reporting/mod.rs
@@ -695,7 +695,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                             let unit_obligation = Obligation {
                                 predicate: ty::Predicate::Trait(
                                     predicate,
-                                    ast::Constness::NotConst,
+                                    hir::Constness::NotConst,
                                 ),
                                 ..obligation.clone()
                             };
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index bf82d743c2b..1fe8ab58d15 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -40,19 +40,19 @@ use crate::ty::fast_reject;
 use crate::ty::relate::TypeRelation;
 use crate::ty::subst::{Subst, SubstsRef};
 use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
-use rustc_hir::def_id::DefId;
-
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
+use syntax::attr;
+
 use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::fmt::{self, Display};
 use std::iter;
 use std::rc::Rc;
-use syntax::{ast, attr};
 
 pub use rustc::traits::types::select::*;
 
@@ -677,7 +677,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // if the regions match exactly.
             let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
             let cycle = cycle.map(|stack| {
-                ty::Predicate::Trait(stack.obligation.predicate, ast::Constness::NotConst)
+                ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst)
             });
             if self.coinductive_match(cycle) {
                 debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref);
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 0dddca98c62..1f007b970b0 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -32,6 +32,7 @@
 //! looking for, and does not need to visit anything else.
 
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
+use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 
 use rustc_data_structures::fx::FxHashSet;
@@ -150,7 +151,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     }
 }
 
-impl TypeFoldable<'tcx> for syntax::ast::Constness {
+impl TypeFoldable<'tcx> for hir::Constness {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
         *self
     }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 393d49a4e4b..2bda99e6d20 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -35,7 +35,7 @@ use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc_hir::{GlobMap, Node, TraitMap};
+use rustc_hir::{Constness, GlobMap, Node, TraitMap};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
 use rustc_serialize::{self, Encodable, Encoder};
@@ -43,7 +43,7 @@ use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 use rustc_target::abi::Align;
-use syntax::ast::{self, Constness, Ident, Name};
+use syntax::ast::{self, Ident, Name};
 use syntax::node_id::{NodeId, NodeMap, NodeSet};
 
 use std::cell::RefCell;
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 274482cba64..38442295636 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -1818,7 +1818,7 @@ define_print_and_forward_display! {
     ty::Predicate<'tcx> {
         match *self {
             ty::Predicate::Trait(ref data, constness) => {
-                if let ast::Constness::Const = constness {
+                if let hir::Constness::Const = constness {
                     p!(write("const "));
                 }
                 p!(print(data))
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index acd6c959751..59dd41e9d56 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -7,6 +7,7 @@ use crate::mir::ProjectionKind;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
+use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
 use rustc_index::vec::{Idx, IndexVec};
@@ -15,7 +16,6 @@ use smallvec::SmallVec;
 use std::fmt;
 use std::rc::Rc;
 use std::sync::Arc;
-use syntax::ast;
 
 impl fmt::Debug for ty::GenericParamDef {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -236,7 +236,7 @@ impl fmt::Debug for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             ty::Predicate::Trait(ref a, constness) => {
-                if let ast::Constness::Const = constness {
+                if let hir::Constness::Const = constness {
                     write!(f, "const ")?;
                 }
                 a.fmt(f)
diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index dd3316979f6..b51d4765583 100644
--- a/src/librustc_ast_lowering/expr.rs
+++ b/src/librustc_ast_lowering/expr.rs
@@ -106,7 +106,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ref body,
                 fn_decl_span,
             ) => {
-                if let IsAsync::Async { closure_id, .. } = asyncness {
+                if let Async::Yes { closure_id, .. } = asyncness {
                     self.lower_expr_async_closure(
                         capture_clause,
                         closure_id,
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index dab950e23f6..73a25620b5a 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -67,10 +67,12 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
             self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
                 let this = &mut ItemLowerer { lctx: this };
                 if let ItemKind::Impl { constness, ref of_trait, .. } = item.kind {
-                    if constness == Constness::Const {
+                    if let Const::Yes(span) = constness {
                         this.lctx
                             .diagnostic()
-                            .span_err(item.span, "const trait impls are not yet implemented");
+                            .struct_span_err(item.span, "const trait impls are not yet implemented")
+                            .span_label(span, "const because of this")
+                            .emit();
                     }
 
                     this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
@@ -297,7 +299,7 @@ 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 asyncness = header.asyncness;
                     let body_id =
                         this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
 
@@ -413,10 +415,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     });
 
                 hir::ItemKind::Impl {
-                    unsafety,
+                    unsafety: self.lower_unsafety(unsafety),
                     polarity,
                     defaultness: self.lower_defaultness(defaultness, true /* [1] */),
-                    constness,
+                    constness: self.lower_constness(constness),
                     generics,
                     of_trait: trait_ref,
                     self_ty: lowered_ty,
@@ -430,7 +432,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     .alloc_from_iter(items.iter().map(|item| self.lower_trait_item_ref(item)));
                 hir::ItemKind::Trait(
                     is_auto,
-                    unsafety,
+                    self.lower_unsafety(unsafety),
                     self.lower_generics(generics, ImplTraitContext::disallowed()),
                     bounds,
                     items,
@@ -834,19 +836,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             AssocItemKind::Fn(ref sig, ref body) => {
                 self.current_item = Some(i.span);
-                let body_id = self.lower_maybe_async_body(
-                    i.span,
-                    &sig.decl,
-                    sig.header.asyncness.node,
-                    body.as_deref(),
-                );
+                let asyncness = sig.header.asyncness;
+                let body_id =
+                    self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref());
                 let impl_trait_return_allow = !self.is_in_trait_impl;
                 let (generics, sig) = self.lower_method_sig(
                     &i.generics,
                     sig,
                     impl_item_def_id,
                     impl_trait_return_allow,
-                    sig.header.asyncness.node.opt_return_id(),
+                    asyncness.opt_return_id(),
                 );
 
                 (generics, hir::ImplItemKind::Method(sig, body_id))
@@ -1031,12 +1030,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
         &mut self,
         span: Span,
         decl: &FnDecl,
-        asyncness: IsAsync,
+        asyncness: Async,
         body: Option<&Block>,
     ) -> hir::BodyId {
         let closure_id = match asyncness {
-            IsAsync::Async { closure_id, .. } => closure_id,
-            IsAsync::NotAsync => return self.lower_fn_body_block(span, decl, body),
+            Async::Yes { closure_id, .. } => closure_id,
+            Async::No => return self.lower_fn_body_block(span, decl, body),
         };
 
         self.lower_body(|this| {
@@ -1245,9 +1244,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
         hir::FnHeader {
-            unsafety: h.unsafety,
-            asyncness: self.lower_asyncness(h.asyncness.node),
-            constness: h.constness.node,
+            unsafety: self.lower_unsafety(h.unsafety),
+            asyncness: self.lower_asyncness(h.asyncness),
+            constness: self.lower_constness(h.constness),
             abi: self.lower_extern(h.ext),
         }
     }
@@ -1274,10 +1273,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
             .emit();
     }
 
-    fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
+    fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync {
         match a {
-            IsAsync::Async { .. } => hir::IsAsync::Async,
-            IsAsync::NotAsync => hir::IsAsync::NotAsync,
+            Async::Yes { .. } => hir::IsAsync::Async,
+            Async::No => hir::IsAsync::NotAsync,
+        }
+    }
+
+    fn lower_constness(&mut self, c: Const) -> hir::Constness {
+        match c {
+            Const::Yes(_) => hir::Constness::Const,
+            Const::No => hir::Constness::NotConst,
+        }
+    }
+
+    pub(super) fn lower_unsafety(&mut self, u: Unsafe) -> hir::Unsafety {
+        match u {
+            Unsafe::Yes(_) => hir::Unsafety::Unsafe,
+            Unsafe::No => hir::Unsafety::Normal,
         }
     }
 
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 5816a64fca5..618b1e7964b 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -1196,7 +1196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             &NodeMap::default(),
                             ImplTraitContext::disallowed(),
                         ),
-                        unsafety: f.unsafety,
+                        unsafety: this.lower_unsafety(f.unsafety),
                         abi: this.lower_extern(f.ext),
                         decl: this.lower_fn_decl(&f.decl, None, false, None),
                         param_names: this.lower_fn_params_to_names(&f.decl),
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 057acec9598..2f0495b8b5a 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -13,7 +13,6 @@ use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
 use rustc_session::lint::LintBuffer;
 use rustc_session::Session;
-use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use std::mem;
@@ -222,27 +221,30 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
-        if asyncness.is_async() {
-            struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`")
-                .note("`async` trait functions are not currently supported")
-                .note(
-                    "consider using the `async-trait` crate: \
-                       https://crates.io/crates/async-trait",
-                )
-                .emit();
+    fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
+        if let Async::Yes { span, .. } = asyncness {
+            struct_span_err!(
+                self.session,
+                fn_span,
+                E0706,
+                "functions in traits cannot be declared `async`"
+            )
+            .span_label(span, "`async` because of this")
+            .note("`async` trait functions are not currently supported")
+            .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
+            .emit();
         }
     }
 
-    fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
-        if constness.node == Constness::Const {
+    fn check_trait_fn_not_const(&self, constness: Const) {
+        if let Const::Yes(span) = constness {
             struct_span_err!(
                 self.session,
-                constness.span,
+                span,
                 E0379,
-                "trait fns cannot be declared const"
+                "functions in traits cannot be declared const"
             )
-            .span_label(constness.span, "trait fns cannot be const")
+            .span_label(span, "functions in traits cannot be const")
             .emit();
         }
     }
@@ -487,7 +489,7 @@ impl<'a> AstValidator<'a> {
             (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 =>
+                    if matches!(header.unsafety, Unsafe::Yes(_)) =>
                 {
                     return;
                 }
@@ -514,12 +516,16 @@ impl<'a> AstValidator<'a> {
     /// 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 {
+        if let Const::Yes(const_span) = sig.header.constness {
             // 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`")
+                        .struct_span_err(
+                            span,
+                            "const parameters are not permitted in const functions",
+                        )
+                        .span_label(const_span, "`const` because of this")
                         .emit();
                 }
             }
@@ -754,13 +760,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                             .help("use `auto trait Trait {}` instead")
                             .emit();
                     }
-                    if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
+                    if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
                         struct_span_err!(
                             this.session,
                             item.span,
                             E0198,
                             "negative impls cannot be unsafe"
                         )
+                        .span_label(span, "unsafe because of this")
                         .emit();
                     }
 
@@ -782,13 +789,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     &item.vis,
                     Some("place qualifiers on individual impl items instead"),
                 );
-                if unsafety == Unsafety::Unsafe {
+                if let Unsafe::Yes(span) = unsafety {
                     struct_span_err!(
                         self.session,
                         item.span,
                         E0197,
                         "inherent impls cannot be unsafe"
                     )
+                    .span_label(span, "unsafe because of this")
                     .emit();
                 }
                 if polarity == ImplPolarity::Negative {
@@ -800,9 +808,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         .note("only trait implementations may be annotated with default")
                         .emit();
                 }
-                if constness == Constness::Const {
+                if let Const::Yes(span) = constness {
                     self.err_handler()
                         .struct_span_err(item.span, "inherent impls cannot be `const`")
+                        .span_label(span, "`const` because of this")
                         .note("only trait implementations may be annotated with `const`")
                         .emit();
                 }
@@ -1091,6 +1100,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
         self.check_c_varadic_type(fk);
 
+        // Functions cannot both be `const async`
+        if let Some(FnHeader {
+            constness: Const::Yes(cspan),
+            asyncness: Async::Yes { span: aspan, .. },
+            ..
+        }) = fk.header()
+        {
+            self.err_handler()
+                .struct_span_err(span, "functions cannot be both `const` and `async`")
+                .span_label(*cspan, "`const` because of this")
+                .span_label(*aspan, "`async` because of this")
+                .emit();
+        }
+
         // Functions without bodies cannot have patterns.
         if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
             Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
@@ -1146,7 +1169,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             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);
+                self.check_trait_fn_not_async(item.span, sig.header.asyncness);
             }
         }
 
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index a10ac94d894..0b21de4d78b 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -496,6 +496,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         if let Some(header) = fn_kind.header() {
             // Stability of const fn methods are covered in `visit_assoc_item` below.
             self.check_extern(header.ext);
+
+            if let (ast::Const::Yes(_), ast::Extern::Implicit)
+            | (ast::Const::Yes(_), ast::Extern::Explicit(_)) = (header.constness, header.ext)
+            {
+                gate_feature_post!(
+                    &self,
+                    const_extern_fn,
+                    span,
+                    "`const extern fn` definitions are unstable"
+                );
+            }
         }
 
         if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
@@ -538,8 +549,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
 
         match i.kind {
             ast::AssocItemKind::Fn(ref sig, _) => {
-                let constness = sig.header.constness.node;
-                if let (ast::Constness::Const, AssocCtxt::Trait) = (constness, ctxt) {
+                if let (ast::Const::Yes(_), AssocCtxt::Trait) = (sig.header.constness, ctxt) {
                     gate_feature_post!(&self, const_fn, i.span, "const fn is unstable");
                 }
             }
@@ -596,7 +606,6 @@ pub fn check_crate(
     gate_all!(async_closure, "async closures are unstable");
     gate_all!(generators, "yield syntax is experimental");
     gate_all!(or_patterns, "or-patterns syntax is experimental");
-    gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
     gate_all!(raw_ref_op, "raw address of syntax is experimental");
     gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
     gate_all!(const_trait_impl, "const trait impls are experimental");
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 78bf149f0e0..b1fa818d0a8 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -2449,7 +2449,7 @@ impl<'a> State<'a> {
         }
     }
 
-    crate fn print_asyncness(&mut self, asyncness: ast::IsAsync) {
+    crate fn print_asyncness(&mut self, asyncness: ast::Async) {
         if asyncness.is_async() {
             self.word_nbsp("async");
         }
@@ -2686,7 +2686,7 @@ impl<'a> State<'a> {
     crate fn print_ty_fn(
         &mut self,
         ext: ast::Extern,
-        unsafety: ast::Unsafety,
+        unsafety: ast::Unsafe,
         decl: &ast::FnDecl,
         name: Option<ast::Ident>,
         generic_params: &[ast::GenericParam],
@@ -2733,12 +2733,8 @@ impl<'a> State<'a> {
     crate fn print_fn_header_info(&mut self, header: ast::FnHeader, vis: &ast::Visibility) {
         self.s.word(visibility_qualified(vis, ""));
 
-        match header.constness.node {
-            ast::Constness::NotConst => {}
-            ast::Constness::Const => self.word_nbsp("const"),
-        }
-
-        self.print_asyncness(header.asyncness.node);
+        self.print_constness(header.constness);
+        self.print_asyncness(header.asyncness);
         self.print_unsafety(header.unsafety);
 
         match header.ext {
@@ -2756,17 +2752,17 @@ impl<'a> State<'a> {
         self.s.word("fn")
     }
 
-    crate fn print_unsafety(&mut self, s: ast::Unsafety) {
+    crate fn print_unsafety(&mut self, s: ast::Unsafe) {
         match s {
-            ast::Unsafety::Normal => {}
-            ast::Unsafety::Unsafe => self.word_nbsp("unsafe"),
+            ast::Unsafe::No => {}
+            ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
         }
     }
 
-    crate fn print_constness(&mut self, s: ast::Constness) {
+    crate fn print_constness(&mut self, s: ast::Const) {
         match s {
-            ast::Constness::Const => self.word_nbsp("const"),
-            ast::Constness::NotConst => {}
+            ast::Const::No => {}
+            ast::Const::Yes(_) => self.word_nbsp("const"),
         }
     }
 
diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs
index f99008a6d5c..5cf233e222e 100644
--- a/src/librustc_builtin_macros/deriving/generic/mod.rs
+++ b/src/librustc_builtin_macros/deriving/generic/mod.rs
@@ -700,7 +700,7 @@ impl<'a> TraitDef<'a> {
         let mut a = vec![attr, unused_qual];
         a.extend(self.attributes.iter().cloned());
 
-        let unsafety = if self.is_unsafe { ast::Unsafety::Unsafe } else { ast::Unsafety::Normal };
+        let unsafety = if self.is_unsafe { ast::Unsafe::Yes(self.span) } else { ast::Unsafe::No };
 
         cx.item(
             self.span,
@@ -710,7 +710,7 @@ impl<'a> TraitDef<'a> {
                 unsafety,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
-                constness: ast::Constness::NotConst,
+                constness: ast::Const::No,
                 generics: trait_generics,
                 of_trait: opt_trait_ref,
                 self_ty: self_type,
@@ -960,7 +960,7 @@ impl<'a> MethodDef<'a> {
         let fn_decl = cx.fn_decl(args, ast::FunctionRetTy::Ty(ret_type));
         let body_block = cx.block_expr(body);
 
-        let unsafety = if self.is_unsafe { ast::Unsafety::Unsafe } else { ast::Unsafety::Normal };
+        let unsafety = if self.is_unsafe { ast::Unsafe::Yes(trait_.span) } else { ast::Unsafe::No };
 
         let trait_lo_sp = trait_.span.shrink_to_lo();
 
diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs
index 914dcdf1969..63cd03527e1 100644
--- a/src/librustc_builtin_macros/deriving/mod.rs
+++ b/src/librustc_builtin_macros/deriving/mod.rs
@@ -157,10 +157,10 @@ fn inject_impl_of_structural_trait(
         ast::Ident::invalid(),
         attrs,
         ItemKind::Impl {
-            unsafety: ast::Unsafety::Normal,
+            unsafety: ast::Unsafe::No,
             polarity: ast::ImplPolarity::Positive,
             defaultness: ast::Defaultness::Final,
-            constness: ast::Constness::NotConst,
+            constness: ast::Const::No,
             generics,
             of_trait: Some(trait_ref),
             self_ty: self_type,
diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs
index ec0d55b38a7..52f033e8b14 100644
--- a/src/librustc_builtin_macros/global_allocator.rs
+++ b/src/librustc_builtin_macros/global_allocator.rs
@@ -4,7 +4,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
 use syntax::ast::{self, Attribute, Expr, FnHeader, FnSig, Generics, Ident, Param};
-use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety};
+use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
 use syntax::expand::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
 use syntax::ptr::P;
 
@@ -64,7 +64,7 @@ impl AllocFnFactory<'_, '_> {
         let result = self.call_allocator(method.name, args);
         let (output_ty, output_expr) = self.ret_ty(&method.output, result);
         let decl = self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty));
-        let header = FnHeader { unsafety: Unsafety::Unsafe, ..FnHeader::default() };
+        let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
         let sig = FnSig { decl, header };
         let kind = ItemKind::Fn(sig, Generics::default(), Some(self.cx.block_expr(output_expr)));
         let item = self.cx.item(
diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs
index 2d6ff81aea8..02a0bc00c11 100644
--- a/src/librustc_builtin_macros/test.rs
+++ b/src/librustc_builtin_macros/test.rs
@@ -375,12 +375,16 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
     let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
     let ref sd = cx.parse_sess.span_diagnostic;
     if let ast::ItemKind::Fn(ref sig, ref generics, _) = i.kind {
-        if sig.header.unsafety == ast::Unsafety::Unsafe {
-            sd.span_err(i.span, "unsafe functions cannot be used for tests");
+        if let ast::Unsafe::Yes(span) = sig.header.unsafety {
+            sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
+                .span_label(span, "`unsafe` because of this")
+                .emit();
             return false;
         }
-        if sig.header.asyncness.node.is_async() {
-            sd.span_err(i.span, "async functions cannot be used for tests");
+        if let ast::Async::Yes { span, .. } = sig.header.asyncness {
+            sd.struct_span_err(i.span, "async functions cannot be used for tests")
+                .span_label(span, "`async` because of this")
+                .emit();
             return false;
         }
 
diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs
index 11f94ab2e62..af22e46eb6a 100644
--- a/src/librustc_expand/build.rs
+++ b/src/librustc_expand/build.rs
@@ -507,7 +507,7 @@ impl<'a> ExtCtxt<'a> {
             span,
             ast::ExprKind::Closure(
                 ast::CaptureBy::Ref,
-                ast::IsAsync::NotAsync,
+                ast::Async::No,
                 ast::Movability::Movable,
                 fn_decl,
                 body,
@@ -530,7 +530,7 @@ impl<'a> ExtCtxt<'a> {
             span,
             ast::ExprKind::Closure(
                 ast::CaptureBy::Ref,
-                ast::IsAsync::NotAsync,
+                ast::Async::No,
                 ast::Movability::Movable,
                 fn_decl,
                 body,
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 27bca1625c1..c2ddaf7df31 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -19,7 +19,7 @@ use rustc_target::spec::abi::Abi;
 use syntax::ast::{self, AsmDialect, CrateSugar, Ident, Name, NodeId};
 use syntax::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy};
 pub use syntax::ast::{BorrowKind, ImplPolarity, IsAuto};
-pub use syntax::ast::{CaptureBy, Constness, Movability, Mutability, Unsafety};
+pub use syntax::ast::{CaptureBy, Movability, Mutability};
 use syntax::node_id::NodeMap;
 use syntax::tokenstream::TokenStream;
 use syntax::util::parser::ExprPrecedence;
@@ -2109,18 +2109,8 @@ impl ImplicitSelfKind {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    HashStable_Generic,
-    Ord,
-    RustcEncodable,
-    RustcDecodable,
-    Debug
-)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Debug)]
+#[derive(HashStable_Generic)]
 pub enum IsAsync {
     Async,
     NotAsync,
@@ -2389,6 +2379,38 @@ pub struct Item<'hir> {
     pub span: Span,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
+pub enum Unsafety {
+    Unsafe,
+    Normal,
+}
+
+impl Unsafety {
+    pub fn prefix_str(&self) -> &'static str {
+        match self {
+            Self::Unsafe => "unsafe ",
+            Self::Normal => "",
+        }
+    }
+}
+
+impl fmt::Display for Unsafety {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match *self {
+            Self::Unsafe => "unsafe",
+            Self::Normal => "normal",
+        })
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
+pub enum Constness {
+    Const,
+    NotConst,
+}
+
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
 pub struct FnHeader {
     pub unsafety: Unsafety,
diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs
index 071c3de4b1c..e49f99fb717 100644
--- a/src/librustc_hir/print.rs
+++ b/src/librustc_hir/print.rs
@@ -648,7 +648,7 @@ impl<'a> State<'a> {
                     self.s.space();
                 }
 
-                if constness == ast::Constness::Const {
+                if constness == hir::Constness::Const {
                     self.word_nbsp("const");
                 }
 
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 3052c9fc26f..659323d1c25 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -668,7 +668,7 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
     }
 
     fn is_sig_const(sig: &ast::FnSig) -> bool {
-        sig.header.constness.node == ast::Constness::Const
+        matches!(sig.header.constness, ast::Const::Yes(_))
             || ReplaceBodyWithLoop::should_ignore_fn(&sig.decl.output)
     }
 }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index c827a7f3d52..93fca43d67c 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -258,13 +258,13 @@ impl EarlyLintPass for UnsafeCode {
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         match it.kind {
-            ast::ItemKind::Trait(_, ast::Unsafety::Unsafe, ..) => {
+            ast::ItemKind::Trait(_, ast::Unsafe::Yes(_), ..) => {
                 self.report_unsafe(cx, it.span, |lint| {
                     lint.build("declaration of an `unsafe` trait").emit()
                 })
             }
 
-            ast::ItemKind::Impl { unsafety: ast::Unsafety::Unsafe, .. } => {
+            ast::ItemKind::Impl { unsafety: ast::Unsafe::Yes(_), .. } => {
                 self.report_unsafe(cx, it.span, |lint| {
                     lint.build("implementation of an `unsafe` trait").emit()
                 })
@@ -278,7 +278,7 @@ impl EarlyLintPass for UnsafeCode {
         if let FnKind::Fn(
             ctxt,
             _,
-            ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafety::Unsafe, .. }, .. },
+            ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
             _,
             body,
         ) = fk
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index 100fd7dc48d..4cbe4145589 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -32,7 +32,6 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_span::{Span, DUMMY_SP};
-use syntax::ast;
 
 use crate::dataflow::generic::ResultsCursor;
 use crate::dataflow::move_paths::MoveData;
@@ -1938,7 +1937,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                                 tcx.mk_substs_trait(ty, &[]),
                                             ),
                                         }),
-                                        ast::Constness::NotConst,
+                                        hir::Constness::NotConst,
                                     ),
                                 ),
                                 &traits::SelectionError::Unimplemented,
@@ -2579,7 +2578,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         self.prove_predicates(
             Some(ty::Predicate::Trait(
                 trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
-                ast::Constness::NotConst,
+                hir::Constness::NotConst,
             )),
             locations,
             category,
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 6a68ccdddff..b12f4ce3269 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -6,7 +6,6 @@ use rustc_hir::def_id::DefId;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use std::borrow::Cow;
-use syntax::ast;
 
 type McfResult = Result<(), (Span, Cow<'static, str>)>;
 
@@ -35,7 +34,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
                     match pred.skip_binder().self_ty().kind {
                         ty::Param(ref p) => {
                             // Allow `T: ?const Trait`
-                            if *constness == ast::Constness::NotConst
+                            if *constness == hir::Constness::NotConst
                                 && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out)
                             {
                                 continue;
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 77748d16653..5a4225ece65 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -13,7 +13,7 @@ use syntax::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Ident, Lit, DUMMY_
 use syntax::ast::{
     AnonConst, BinOp, BinOpKind, FnDecl, FunctionRetTy, Mac, Param, Ty, TyKind, UnOp,
 };
-use syntax::ast::{Arm, BlockCheckMode, Expr, ExprKind, IsAsync, Label, Movability, RangeLimits};
+use syntax::ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
 use syntax::ptr::P;
 use syntax::token::{self, Token, TokenKind};
 use syntax::util::classify;
@@ -1348,7 +1348,7 @@ impl<'a> Parser<'a> {
             if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
 
         let asyncness =
-            if self.token.span.rust_2018() { self.parse_asyncness() } else { IsAsync::NotAsync };
+            if self.token.span.rust_2018() { self.parse_asyncness() } else { Async::No };
         if asyncness.is_async() {
             // Feature-gate `async ||` closures.
             self.sess.gated_spans.gate(sym::async_closure, self.prev_span);
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 07d8bae4725..ccd55c5c08a 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -6,13 +6,13 @@ use crate::maybe_whole;
 
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey};
-use rustc_span::source_map::{self, respan, Span};
+use rustc_span::source_map::{self, Span};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::BytePos;
 use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
 use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind};
+use syntax::ast::{Async, Const, Defaultness, IsAuto, PathSegment, StrLit, Unsafe};
 use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind};
-use syntax::ast::{Constness, Defaultness, Extern, IsAsync, IsAuto, PathSegment, StrLit, Unsafety};
 use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
 use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind};
 use syntax::ptr::P;
@@ -96,59 +96,32 @@ impl<'a> Parser<'a> {
             return Ok(Some(item));
         }
 
+        if self.check_fn_front_matter() {
+            // FUNCTION ITEM
+            let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?;
+            let kind = ItemKind::Fn(sig, generics, body);
+            return self.mk_item_with_info(attrs, lo, vis, (ident, kind, None));
+        }
+
         if self.eat_keyword(kw::Extern) {
             if self.eat_keyword(kw::Crate) {
+                // EXTERN CRATE
                 return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?));
             }
-
+            // EXTERN BLOCK
             let abi = self.parse_abi();
-
-            if self.eat_keyword(kw::Fn) {
-                // EXTERN FUNCTION ITEM
-                let fn_span = self.prev_span;
-                let header = FnHeader {
-                    unsafety: Unsafety::Normal,
-                    asyncness: respan(fn_span, IsAsync::NotAsync),
-                    constness: respan(fn_span, Constness::NotConst),
-                    ext: Extern::from_abi(abi),
-                };
-                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)?));
-            }
-
-            self.unexpected()?;
+            return Ok(Some(self.parse_item_foreign_mod(lo, abi, vis, attrs)?));
         }
 
         if self.is_static_global() {
-            self.bump();
             // STATIC ITEM
+            self.bump();
             let m = self.parse_mutability();
             let info = self.parse_item_const(Some(m))?;
             return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
-        if self.eat_keyword(kw::Const) {
-            let const_span = self.prev_span;
-            if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) {
-                // CONST FUNCTION ITEM
-                let unsafety = self.parse_unsafety();
-
-                if self.check_keyword(kw::Extern) {
-                    self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span));
-                }
-                let ext = self.parse_extern()?;
-                self.expect_keyword(kw::Fn)?;
-
-                let header = FnHeader {
-                    unsafety,
-                    asyncness: respan(const_span, IsAsync::NotAsync),
-                    constness: respan(const_span, Constness::Const),
-                    ext,
-                };
-                return self.parse_item_fn(lo, vis, attrs, header);
-            }
-
+        if let Const::Yes(const_span) = self.parse_constness() {
             // CONST ITEM
             if self.eat_keyword(kw::Mut) {
                 let prev_span = self.prev_span;
@@ -167,37 +140,10 @@ impl<'a> Parser<'a> {
             return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
-        // Parses `async unsafe? fn`.
-        if self.check_keyword(kw::Async) {
-            let async_span = self.token.span;
-            if self.is_keyword_ahead(1, &[kw::Fn]) || self.is_keyword_ahead(2, &[kw::Fn]) {
-                // ASYNC FUNCTION ITEM
-                self.bump(); // `async`
-                let unsafety = self.parse_unsafety(); // `unsafe`?
-                self.expect_keyword(kw::Fn)?; // `fn`
-                let fn_span = self.prev_span;
-                let asyncness = respan(
-                    async_span,
-                    IsAsync::Async {
-                        closure_id: DUMMY_NODE_ID,
-                        return_impl_trait_id: DUMMY_NODE_ID,
-                    },
-                );
-                self.ban_async_in_2015(async_span);
-                let header = FnHeader {
-                    unsafety,
-                    asyncness,
-                    constness: respan(fn_span, Constness::NotConst),
-                    ext: Extern::None,
-                };
-                return self.parse_item_fn(lo, vis, attrs, header);
-            }
-        }
-
         if self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) {
             // UNSAFE TRAIT ITEM
-            self.bump(); // `unsafe`
-            let info = self.parse_item_trait(lo, Unsafety::Unsafe)?;
+            let unsafety = self.parse_unsafety();
+            let info = self.parse_item_trait(lo, unsafety)?;
             return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
@@ -213,38 +159,6 @@ impl<'a> Parser<'a> {
             return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
-        if self.check_keyword(kw::Fn) {
-            // FUNCTION ITEM
-            self.bump();
-            let fn_span = self.prev_span;
-            let header = FnHeader {
-                unsafety: Unsafety::Normal,
-                asyncness: respan(fn_span, IsAsync::NotAsync),
-                constness: respan(fn_span, Constness::NotConst),
-                ext: Extern::None,
-            };
-            return self.parse_item_fn(lo, vis, attrs, header);
-        }
-
-        if self.check_keyword(kw::Unsafe)
-            && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace))
-        {
-            // UNSAFE FUNCTION ITEM
-            self.bump(); // `unsafe`
-            // `{` is also expected after `unsafe`; in case of error, include it in the diagnostic.
-            self.check(&token::OpenDelim(token::Brace));
-            let ext = self.parse_extern()?;
-            self.expect_keyword(kw::Fn)?;
-            let fn_span = self.prev_span;
-            let header = FnHeader {
-                unsafety: Unsafety::Unsafe,
-                asyncness: respan(fn_span, IsAsync::NotAsync),
-                constness: respan(fn_span, Constness::NotConst),
-                ext,
-            };
-            return self.parse_item_fn(lo, vis, attrs, header);
-        }
-
         if self.eat_keyword(kw::Mod) {
             // MODULE ITEM
             let info = self.parse_item_mod(&attrs[..])?;
@@ -268,7 +182,7 @@ impl<'a> Parser<'a> {
             || (self.check_keyword(kw::Auto) && self.is_keyword_ahead(1, &[kw::Trait]))
         {
             // TRAIT ITEM
-            let info = self.parse_item_trait(lo, Unsafety::Normal)?;
+            let info = self.parse_item_trait(lo, Unsafe::No)?;
             return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
@@ -547,7 +461,7 @@ impl<'a> Parser<'a> {
     ///   `impl` GENERICS `const`? `!`? TYPE (`where` PREDICATES)? `{` BODY `}`
     fn parse_item_impl(
         &mut self,
-        unsafety: Unsafety,
+        unsafety: Unsafe,
         defaultness: Defaultness,
     ) -> PResult<'a, ItemInfo> {
         // First, parse generic parameters if necessary.
@@ -561,13 +475,10 @@ impl<'a> Parser<'a> {
             generics
         };
 
-        let constness = if self.eat_keyword(kw::Const) {
-            let span = self.prev_span;
+        let constness = self.parse_constness();
+        if let Const::Yes(span) = constness {
             self.sess.gated_spans.gate(sym::const_trait_impl, span);
-            Constness::Const
-        } else {
-            Constness::NotConst
-        };
+        }
 
         // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
         let polarity = if self.check(&token::Not) && self.look_ahead(1, |t| t.can_begin_type()) {
@@ -707,7 +618,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `auto? trait Foo { ... }` or `trait Foo = Bar;`.
-    fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
+    fn parse_item_trait(&mut self, lo: Span, unsafety: Unsafe) -> PResult<'a, ItemInfo> {
         // Parse optional `auto` prefix.
         let is_auto = if self.eat_keyword(kw::Auto) { IsAuto::Yes } else { IsAuto::No };
 
@@ -738,7 +649,7 @@ impl<'a> Parser<'a> {
                 let msg = "trait aliases cannot be `auto`";
                 self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit();
             }
-            if unsafety != Unsafety::Normal {
+            if let Unsafe::Yes(_) = unsafety {
                 let msg = "trait aliases cannot be `unsafe`";
                 self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit();
             }
@@ -803,12 +714,12 @@ impl<'a> Parser<'a> {
     fn parse_assoc_item(
         &mut self,
         at_end: &mut bool,
-        is_name_required: fn(&token::Token) -> bool,
+        req_name: fn(&token::Token) -> bool,
     ) -> PResult<'a, P<AssocItem>> {
         let attrs = self.parse_outer_attributes()?;
         let mut unclosed_delims = vec![];
         let (mut item, tokens) = self.collect_tokens(|this| {
-            let item = this.parse_assoc_item_(at_end, attrs, is_name_required);
+            let item = this.parse_assoc_item_(at_end, attrs, req_name);
             unclosed_delims.append(&mut this.unclosed_delims);
             item
         })?;
@@ -824,19 +735,20 @@ impl<'a> Parser<'a> {
         &mut self,
         at_end: &mut bool,
         mut attrs: Vec<Attribute>,
-        is_name_required: fn(&token::Token) -> bool,
+        req_name: fn(&token::Token) -> bool,
     ) -> PResult<'a, AssocItem> {
         let lo = self.token.span;
         let vis = self.parse_visibility(FollowedByType::No)?;
         let defaultness = self.parse_defaultness();
         let (name, kind, generics) = if self.eat_keyword(kw::Type) {
             self.parse_assoc_ty()?
-        } else if self.is_const_item() {
-            self.parse_assoc_const()?
+        } else if self.check_fn_front_matter() {
+            let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, req_name)?;
+            (ident, AssocItemKind::Fn(sig, body), generics)
         } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? {
             (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default())
         } else {
-            self.parse_assoc_fn(at_end, &mut attrs, is_name_required)?
+            self.parse_assoc_const()?
         };
 
         Ok(AssocItem {
@@ -852,12 +764,6 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Returns `true` if we are looking at `const ID`
-    /// (returns `false` for things like `const fn`, etc.).
-    fn is_const_item(&self) -> bool {
-        self.token.is_keyword(kw::Const) && !self.is_keyword_ahead(1, &[kw::Fn, kw::Unsafe])
-    }
-
     /// This parses the grammar:
     ///
     ///     AssocConst = "const" Ident ":" Ty "=" Expr ";"
@@ -1065,23 +971,33 @@ impl<'a> Parser<'a> {
     pub fn parse_foreign_item(&mut self) -> PResult<'a, P<ForeignItem>> {
         maybe_whole!(self, NtForeignItem, |ni| ni);
 
-        let attrs = self.parse_outer_attributes()?;
+        let mut attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
-        let visibility = self.parse_visibility(FollowedByType::No)?;
+        let vis = 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
-        if self.is_static_global() {
+            // FOREIGN TYPE ITEM
+            self.parse_item_foreign_type(vis, lo, attrs)
+        } else if self.check_fn_front_matter() {
+            // FOREIGN FUNCTION ITEM
+            let (ident, sig, generics, body) = self.parse_fn(&mut false, &mut attrs, |_| true)?;
+            let kind = ForeignItemKind::Fn(sig, generics, body);
+            let span = lo.to(self.prev_span);
+            Ok(P(ast::ForeignItem {
+                ident,
+                attrs,
+                kind,
+                id: DUMMY_NODE_ID,
+                span,
+                vis,
+                tokens: None,
+            }))
+        } else if self.is_static_global() {
+            // FOREIGN STATIC ITEM
             self.bump(); // `static`
-            return self.parse_item_foreign_static(visibility, lo, attrs);
-        }
-
-        // 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.parse_item_foreign_static(vis, lo, attrs)
+        } else if self.token.is_keyword(kw::Const) {
+            // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
             self.bump(); // `const`
             self.struct_span_err(self.prev_span, "extern items cannot be `const`")
                 .span_suggestion(
@@ -1091,32 +1007,17 @@ impl<'a> Parser<'a> {
                     Applicability::MachineApplicable,
                 )
                 .emit();
-            return self.parse_item_foreign_static(visibility, lo, attrs);
-        }
-
-        // FOREIGN FUNCTION ITEM
-        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)? {
-            Some(mac) => Ok(P(ForeignItem {
-                ident: Ident::invalid(),
-                span: lo.to(self.prev_span),
-                id: DUMMY_NODE_ID,
-                attrs,
-                vis: visibility,
-                kind: ForeignItemKind::Macro(mac),
-                tokens: None,
-            })),
-            None => {
-                if !attrs.is_empty() {
-                    self.expected_item_err(&attrs)?;
-                }
-
-                self.unexpected()
+            self.parse_item_foreign_static(vis, lo, attrs)
+        } else if let Some(mac) = self.parse_assoc_macro_invoc("extern", Some(&vis), &mut false)? {
+            let kind = ForeignItemKind::Macro(mac);
+            let span = lo.to(self.prev_span);
+            let ident = Ident::invalid();
+            Ok(P(ForeignItem { ident, span, id: DUMMY_NODE_ID, attrs, vis, kind, tokens: None }))
+        } else {
+            if !attrs.is_empty() {
+                self.expected_item_err(&attrs)?;
             }
+            self.unexpected()
         }
     }
 
@@ -1703,55 +1604,26 @@ impl<'a> Parser<'a> {
 }
 
 /// The parsing configuration used to parse a parameter list (see `parse_fn_params`).
-pub(super) struct ParamCfg {
-    /// `is_name_required` decides if, per-parameter,
-    /// the parameter must have a pattern or just a type.
-    pub is_name_required: fn(&token::Token) -> bool,
-}
+///
+/// The function decides if, per-parameter `p`, `p` must have a pattern or just a type.
+type ReqName = fn(&token::Token) -> bool;
 
 /// Parsing of functions and methods.
 impl<'a> Parser<'a> {
-    /// Parses an item-position function declaration.
-    fn parse_item_fn(
-        &mut self,
-        lo: Span,
-        vis: Visibility,
-        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 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, None))
-    }
-
-    /// Parses a function declaration from a foreign module.
-    fn parse_item_foreign_fn(
-        &mut self,
-        vis: ast::Visibility,
-        lo: Span,
-        mut attrs: Vec<Attribute>,
-    ) -> PResult<'a, P<ForeignItem>> {
-        let cfg = ParamCfg { is_name_required: |_| true };
-        let header = self.parse_fn_front_matter()?;
-        let (ident, decl, generics) = self.parse_fn_sig(&cfg)?;
-        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 }))
-    }
-
-    fn parse_assoc_fn(
+    /// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`.
+    fn parse_fn(
         &mut self,
         at_end: &mut bool,
         attrs: &mut Vec<Attribute>,
-        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 body = self.parse_fn_body(at_end, attrs)?;
-        Ok((ident, AssocItemKind::Fn(FnSig { header, decl }, body), generics))
+        req_name: ReqName,
+    ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
+        let header = self.parse_fn_front_matter()?; // `const ... fn`
+        let ident = self.parse_ident()?; // `foo`
+        let mut generics = self.parse_generics()?; // `<'a, T, ...>`
+        let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)`
+        generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
+        let body = self.parse_fn_body(at_end, attrs)?; // `;` or `{ ... }`.
+        Ok((ident, FnSig { header, decl }, generics, body))
     }
 
     /// Parse the "body" of a function.
@@ -1785,29 +1657,44 @@ impl<'a> Parser<'a> {
         Ok(body)
     }
 
-    /// Parses all the "front matter" for a `fn` declaration, up to
-    /// and including the `fn` keyword:
+    /// Is the current token the start of an `FnHeader` / not a valid parse?
+    fn check_fn_front_matter(&mut self) -> bool {
+        // We use an over-approximation here.
+        // `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
+        const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];
+        self.check_keyword(kw::Fn) // Definitely an `fn`.
+            // `$qual fn` or `$qual $qual`:
+            || QUALS.iter().any(|&kw| self.check_keyword(kw))
+                && self.look_ahead(1, |t| {
+                    // ...qualified and then `fn`, e.g. `const fn`.
+                    t.is_keyword(kw::Fn)
+                    // Two qualifiers. This is enough. Due `async` we need to check that it's reserved.
+                    || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) && i.is_reserved())
+                })
+            // `extern ABI fn`
+            || self.check_keyword(kw::Extern)
+                && self.look_ahead(1, |t| t.can_begin_literal_or_bool())
+                && self.look_ahead(2, |t| t.is_keyword(kw::Fn))
+    }
+
+    /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
+    /// up to and including the `fn` keyword. The formal grammar is:
     ///
-    /// - `const fn`
-    /// - `unsafe fn`
-    /// - `const unsafe fn`
-    /// - `extern fn`
-    /// - etc.
+    /// ```
+    /// Extern = "extern" StringLit ;
+    /// FnQual = "const"? "async"? "unsafe"? Extern? ;
+    /// FnFrontMatter = FnQual? "fn" ;
+    /// ```
     fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
-        let is_const_fn = self.eat_keyword(kw::Const);
-        let const_span = self.prev_span;
+        let constness = self.parse_constness();
         let asyncness = self.parse_asyncness();
-        if let IsAsync::Async { .. } = asyncness {
-            self.ban_async_in_2015(self.prev_span);
-        }
-        let asyncness = respan(self.prev_span, asyncness);
         let unsafety = self.parse_unsafety();
-        let (constness, unsafety, ext) = if is_const_fn {
-            (respan(const_span, Constness::Const), unsafety, Extern::None)
-        } else {
-            let ext = self.parse_extern()?;
-            (respan(self.prev_span, Constness::NotConst), unsafety, ext)
-        };
+        let ext = self.parse_extern()?;
+
+        if let Async::Yes { span, .. } = asyncness {
+            self.ban_async_in_2015(span);
+        }
+
         if !self.eat_keyword(kw::Fn) {
             // It is possible for `expect_one_of` to recover given the contents of
             // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
@@ -1816,36 +1703,40 @@ impl<'a> Parser<'a> {
                 unreachable!()
             }
         }
+
         Ok(FnHeader { constness, unsafety, asyncness, ext })
     }
 
-    /// Parse the "signature", including the identifier, parameters, and generics of a function.
-    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, AllowPlus::Yes)?;
-        generics.where_clause = self.parse_where_clause()?;
-        Ok((ident, decl, generics))
+    /// We are parsing `async fn`. If we are on Rust 2015, emit an error.
+    fn ban_async_in_2015(&self, span: Span) {
+        if span.rust_2015() {
+            let diag = self.diagnostic();
+            struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition")
+                .note("to use `async fn`, switch to Rust 2018")
+                .help("set `edition = \"2018\"` in `Cargo.toml`")
+                .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
+                .emit();
+        }
     }
 
     /// Parses the parameter list and result type of a function declaration.
     pub(super) fn parse_fn_decl(
         &mut self,
-        cfg: &ParamCfg,
+        req_name: ReqName,
         ret_allow_plus: AllowPlus,
     ) -> PResult<'a, P<FnDecl>> {
         Ok(P(FnDecl {
-            inputs: self.parse_fn_params(cfg)?,
+            inputs: self.parse_fn_params(req_name)?,
             output: self.parse_ret_ty(ret_allow_plus, RecoverQPath::Yes)?,
         }))
     }
 
     /// Parses the parameter list of a function, including the `(` and `)` delimiters.
-    fn parse_fn_params(&mut self, cfg: &ParamCfg) -> PResult<'a, Vec<Param>> {
+    fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, Vec<Param>> {
         let mut first_param = true;
         // Parse the arguments, starting out with `self` being allowed...
         let (mut params, _) = self.parse_paren_comma_seq(|p| {
-            let param = p.parse_param_general(&cfg, first_param).or_else(|mut e| {
+            let param = p.parse_param_general(req_name, first_param).or_else(|mut e| {
                 e.emit();
                 let lo = p.prev_span;
                 // Skip every token until next possible arg or end.
@@ -1865,7 +1756,7 @@ impl<'a> Parser<'a> {
     /// Parses a single function parameter.
     ///
     /// - `self` is syntactically allowed when `first_param` holds.
-    fn parse_param_general(&mut self, cfg: &ParamCfg, first_param: bool) -> PResult<'a, Param> {
+    fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
 
@@ -1877,7 +1768,7 @@ impl<'a> Parser<'a> {
 
         let is_name_required = match self.token.kind {
             token::DotDotDot => false,
-            _ => (cfg.is_name_required)(&self.token),
+            _ => req_name(&self.token),
         };
         let (pat, ty) = if is_name_required || self.is_named_param() {
             debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index e1461dbb8e7..4716d722778 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -22,8 +22,9 @@ use rustc_session::parse::ParseSess;
 use rustc_span::source_map::respan;
 use rustc_span::symbol::{kw, sym, Symbol};
 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::ast::DUMMY_NODE_ID;
+use syntax::ast::{self, AttrStyle, AttrVec, Const, CrateSugar, Extern, Ident, Unsafe};
+use syntax::ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind};
 use syntax::ptr::P;
 use syntax::token::{self, DelimToken, Token, TokenKind};
 use syntax::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint};
@@ -953,17 +954,23 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses asyncness: `async` or nothing.
-    fn parse_asyncness(&mut self) -> IsAsync {
+    fn parse_asyncness(&mut self) -> Async {
         if self.eat_keyword(kw::Async) {
-            IsAsync::Async { closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
+            let span = self.prev_span;
+            Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
         } else {
-            IsAsync::NotAsync
+            Async::No
         }
     }
 
     /// Parses unsafety: `unsafe` or nothing.
-    fn parse_unsafety(&mut self) -> Unsafety {
-        if self.eat_keyword(kw::Unsafe) { Unsafety::Unsafe } else { Unsafety::Normal }
+    fn parse_unsafety(&mut self) -> Unsafe {
+        if self.eat_keyword(kw::Unsafe) { Unsafe::Yes(self.prev_span) } else { Unsafe::No }
+    }
+
+    /// Parses constness: `const` or nothing.
+    fn parse_constness(&mut self) -> Const {
+        if self.eat_keyword(kw::Const) { Const::Yes(self.prev_span) } else { Const::No }
     }
 
     /// Parses mutability (`mut` or nothing).
@@ -1266,19 +1273,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// We are parsing `async fn`. If we are on Rust 2015, emit an error.
-    fn ban_async_in_2015(&self, async_span: Span) {
-        if async_span.rust_2015() {
-            struct_span_err!(
-                self.diagnostic(),
-                async_span,
-                E0670,
-                "`async fn` is not permitted in the 2015 edition",
-            )
-            .emit();
-        }
-    }
-
     fn collect_tokens<R>(
         &mut self,
         f: impl FnOnce(&mut Self) -> PResult<'a, R>,
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index e11cdd5dadb..e97af0dc00c 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -199,7 +199,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub(super) fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
+    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 e74ce622947..f56ae65a03d 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -1,4 +1,3 @@
-use super::item::ParamCfg;
 use super::{Parser, PathStyle, TokenType};
 
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -311,8 +310,7 @@ impl<'a> Parser<'a> {
         let unsafety = self.parse_unsafety();
         let ext = self.parse_extern()?;
         self.expect_keyword(kw::Fn)?;
-        let cfg = ParamCfg { is_name_required: |_| false };
-        let decl = self.parse_fn_decl(&cfg, AllowPlus::No)?;
+        let decl = self.parse_fn_decl(|_| false, AllowPlus::No)?;
         Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params, decl })))
     }
 
diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs
index 3a26197c160..fe80dec513c 100644
--- a/src/librustc_resolve/def_collector.rs
+++ b/src/librustc_resolve/def_collector.rs
@@ -48,8 +48,8 @@ impl<'a> DefCollector<'a> {
         decl: &'a FnDecl,
         body: Option<&'a Block>,
     ) {
-        let (closure_id, return_impl_trait_id) = match header.asyncness.node {
-            IsAsync::Async { closure_id, return_impl_trait_id } => {
+        let (closure_id, return_impl_trait_id) = match header.asyncness {
+            Async::Yes { span: _, closure_id, return_impl_trait_id } => {
                 (closure_id, return_impl_trait_id)
             }
             _ => unreachable!(),
@@ -117,7 +117,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
             | ItemKind::ExternCrate(..)
             | ItemKind::ForeignMod(..)
             | ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name),
-            ItemKind::Fn(sig, generics, body) if sig.header.asyncness.node.is_async() => {
+            ItemKind::Fn(sig, generics, body) if sig.header.asyncness.is_async() => {
                 return self.visit_async_fn(
                     i.id,
                     i.ident.name,
@@ -215,7 +215,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
 
     fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) {
         let def_data = match &i.kind {
-            AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.node.is_async() => {
+            AssocItemKind::Fn(FnSig { header, decl }, body) if header.asyncness.is_async() => {
                 return self.visit_async_fn(
                     i.id,
                     i.ident.name,
@@ -255,10 +255,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
                 // we must create two defs.
                 let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span);
                 match asyncness {
-                    IsAsync::Async { closure_id, .. } => {
+                    Async::Yes { closure_id, .. } => {
                         self.create_def(closure_id, DefPathData::ClosureExpr, expr.span)
                     }
-                    IsAsync::NotAsync => closure_def,
+                    Async::No => closure_def,
                 }
             }
             ExprKind::Async(_, async_id, _) => {
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 01a0e568137..58ff7f44789 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -2030,7 +2030,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
             // resolve the arguments within the proper scopes so that usages of them inside the
             // closure are detected as upvars rather than normal closure arg usages.
-            ExprKind::Closure(_, IsAsync::Async { .. }, _, ref fn_decl, ref body, _span) => {
+            ExprKind::Closure(_, Async::Yes { .. }, _, ref fn_decl, ref body, _span) => {
                 self.with_rib(ValueNS, NormalRibKind, |this| {
                     // Resolve arguments:
                     this.resolve_params(&fn_decl.inputs);
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 5ce81c104e1..01e3e3f3685 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -290,8 +290,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                 // as an `impl Trait` existential type. Because of this, to match
                 // the definition paths when resolving nested types we need to
                 // start walking from the newly-created definition.
-                match sig.header.asyncness.node {
-                    ast::IsAsync::Async { return_impl_trait_id, .. } => {
+                match sig.header.asyncness {
+                    ast::Async::Yes { return_impl_trait_id, .. } => {
                         v.nest_tables(return_impl_trait_id, |v| v.visit_ty(ret_ty))
                     }
                     _ => v.visit_ty(ret_ty),
@@ -383,8 +383,8 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> {
                     // as an `impl Trait` existential type. Because of this, to match
                     // the definition paths when resolving nested types we need to
                     // start walking from the newly-created definition.
-                    match header.asyncness.node {
-                        ast::IsAsync::Async { return_impl_trait_id, .. } => {
+                    match header.asyncness {
+                        ast::Async::Yes { return_impl_trait_id, .. } => {
                             v.nest_tables(return_impl_trait_id, |v| v.visit_ty(ret_ty))
                         }
                         _ => v.visit_ty(ret_ty),
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 6401cabdcd5..d3c4d6d5723 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -225,7 +225,7 @@ impl Sig for ast::Ty {
                     text.push('>');
                 }
 
-                if f.unsafety == ast::Unsafety::Unsafe {
+                if let ast::Unsafe::Yes(_) = f.unsafety {
                     text.push_str("unsafe ");
                 }
                 push_extern(&mut text, f.ext);
@@ -365,13 +365,13 @@ impl Sig for ast::Item {
             }
             ast::ItemKind::Fn(ast::FnSig { ref decl, header }, ref generics, _) => {
                 let mut text = String::new();
-                if header.constness.node == ast::Constness::Const {
+                if let ast::Const::Yes(_) = header.constness {
                     text.push_str("const ");
                 }
-                if header.asyncness.node.is_async() {
+                if header.asyncness.is_async() {
                     text.push_str("async ");
                 }
-                if header.unsafety == ast::Unsafety::Unsafe {
+                if let ast::Unsafe::Yes(_) = header.unsafety {
                     text.push_str("unsafe ");
                 }
                 push_extern(&mut text, header.ext);
@@ -453,7 +453,7 @@ impl Sig for ast::Item {
                     text.push_str("auto ");
                 }
 
-                if unsafety == ast::Unsafety::Unsafe {
+                if let ast::Unsafe::Yes(_) = unsafety {
                     text.push_str("unsafe ");
                 }
                 text.push_str("trait ");
@@ -496,11 +496,11 @@ impl Sig for ast::Item {
                 if let ast::Defaultness::Default = defaultness {
                     text.push_str("default ");
                 }
-                if unsafety == ast::Unsafety::Unsafe {
+                if let ast::Unsafe::Yes(_) = unsafety {
                     text.push_str("unsafe ");
                 }
                 text.push_str("impl");
-                if constness == ast::Constness::Const {
+                if let ast::Const::Yes(_) = constness {
                     text.push_str(" const");
                 }
 
@@ -884,13 +884,13 @@ fn make_method_signature(
 ) -> Result {
     // FIXME code dup with function signature
     let mut text = String::new();
-    if m.header.constness.node == ast::Constness::Const {
+    if let ast::Const::Yes(_) = m.header.constness {
         text.push_str("const ");
     }
-    if m.header.asyncness.node.is_async() {
+    if m.header.asyncness.is_async() {
         text.push_str("async ");
     }
-    if m.header.unsafety == ast::Unsafety::Unsafe {
+    if let ast::Unsafe::Yes(_) = m.header.unsafety {
         text.push_str("unsafe ");
     }
     push_extern(&mut text, m.header.ext);
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index c26b47c3130..0e7c10541ca 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -28,12 +28,12 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::print;
-use rustc_hir::{ExprKind, GenericArg, GenericArgs};
+use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs};
 use rustc_span::symbol::sym;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use smallvec::SmallVec;
-use syntax::ast::{self, Constness};
+use syntax::ast;
 use syntax::util::lev_distance::find_best_match_for_name;
 
 use std::collections::BTreeSet;
@@ -1502,7 +1502,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
         for (base_trait_ref, span, constness) in regular_traits_refs_spans {
-            assert_eq!(constness, ast::Constness::NotConst);
+            assert_eq!(constness, Constness::NotConst);
 
             for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) {
                 debug!(
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index fd0c994a6ea..a825856e38a 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2693,13 +2693,13 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         None
     }
 
-    fn default_constness_for_trait_bounds(&self) -> ast::Constness {
+    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
         // FIXME: refactor this into a method
         let node = self.tcx.hir().get(self.body_id);
         if let Some(fn_like) = FnLikeNode::from_node(node) {
             fn_like.constness()
         } else {
-            ast::Constness::NotConst
+            hir::Constness::NotConst
         }
     }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f3a1f412d0d..5349c324ad8 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -300,11 +300,11 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
         Some(self.item_def_id)
     }
 
-    fn default_constness_for_trait_bounds(&self) -> ast::Constness {
+    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
         if let Some(fn_like) = FnLikeNode::from_node(self.node()) {
             fn_like.constness()
         } else {
-            ast::Constness::NotConst
+            hir::Constness::NotConst
         }
     }
 
@@ -2429,7 +2429,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
                     match bound {
                         &hir::GenericBound::Trait(ref poly_trait_ref, modifier) => {
                             let constness = match modifier {
-                                hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
+                                hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
                                 hir::TraitBoundModifier::None => constness,
                                 hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"),
                             };
@@ -2617,13 +2617,13 @@ fn predicates_from_bound<'tcx>(
     astconv: &dyn AstConv<'tcx>,
     param_ty: Ty<'tcx>,
     bound: &'tcx hir::GenericBound<'tcx>,
-    constness: ast::Constness,
+    constness: hir::Constness,
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
     match *bound {
         hir::GenericBound::Trait(ref tr, modifier) => {
             let constness = match modifier {
                 hir::TraitBoundModifier::Maybe => return vec![],
-                hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
+                hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
                 hir::TraitBoundModifier::None => constness,
             };
 
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 474868f0dd6..067b33c1447 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -377,7 +377,7 @@ pub fn hir_trait_to_predicates<'tcx>(
         &item_cx,
         hir_trait,
         DUMMY_SP,
-        syntax::ast::Constness::NotConst,
+        hir::Constness::NotConst,
         tcx.types.err,
         &mut bounds,
         true,
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 218674b757f..744201a0050 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -203,7 +203,7 @@ pub struct Impl<'hir> {
     pub unsafety: hir::Unsafety,
     pub polarity: hir::ImplPolarity,
     pub defaultness: hir::Defaultness,
-    pub constness: ast::Constness,
+    pub constness: hir::Constness,
     pub generics: &'hir hir::Generics<'hir>,
     pub trait_: &'hir Option<hir::TraitRef<'hir>>,
     pub for_: &'hir hir::Ty<'hir>,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index b22406124e0..72430fa9c17 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -34,7 +34,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable_Generic;
 use rustc_serialize::{self, Decoder, Encoder};
-use rustc_span::source_map::{dummy_spanned, respan, Spanned};
+use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -1198,14 +1198,14 @@ pub enum ExprKind {
     /// A closure (e.g., `move |a, b, c| a + b + c`).
     ///
     /// The final span is the span of the argument block `|...|`.
-    Closure(CaptureBy, IsAsync, Movability, P<FnDecl>, P<Expr>, Span),
+    Closure(CaptureBy, Async, Movability, P<FnDecl>, P<Expr>, Span),
     /// A block (`'label: { ... }`).
     Block(P<Block>, Option<Label>),
     /// An async block (`async move { ... }`).
     ///
     /// The `NodeId` is the `NodeId` for the closure that results from
     /// desugaring an async block, just like the NodeId field in the
-    /// `IsAsync` enum. This is necessary in order to create a def for the
+    /// `Async::Yes` variant. This is necessary in order to create a def for the
     /// closure which can be used as a parent of any child defs. Defs
     /// created during lowering cannot be made the parent of any other
     /// preexisting defs.
@@ -1863,7 +1863,7 @@ pub struct Ty {
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct BareFnTy {
-    pub unsafety: Unsafety,
+    pub unsafety: Unsafe,
     pub ext: Extern,
     pub generic_params: Vec<GenericParam>,
     pub decl: P<FnDecl>,
@@ -2101,70 +2101,38 @@ pub enum IsAuto {
     No,
 }
 
-#[derive(
-    Copy,
-    Clone,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    Ord,
-    Hash,
-    RustcEncodable,
-    RustcDecodable,
-    Debug,
-    HashStable_Generic
-)]
-pub enum Unsafety {
-    Unsafe,
-    Normal,
-}
-
-impl Unsafety {
-    pub fn prefix_str(&self) -> &'static str {
-        match self {
-            Unsafety::Unsafe => "unsafe ",
-            Unsafety::Normal => "",
-        }
-    }
-}
-
-impl fmt::Display for Unsafety {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(
-            match *self {
-                Unsafety::Normal => "normal",
-                Unsafety::Unsafe => "unsafe",
-            },
-            f,
-        )
-    }
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)]
+#[derive(HashStable_Generic)]
+pub enum Unsafe {
+    Yes(Span),
+    No,
 }
 
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum IsAsync {
-    Async { closure_id: NodeId, return_impl_trait_id: NodeId },
-    NotAsync,
+pub enum Async {
+    Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId },
+    No,
 }
 
-impl IsAsync {
+impl Async {
     pub fn is_async(self) -> bool {
-        if let IsAsync::Async { .. } = self { true } else { false }
+        if let Async::Yes { .. } = self { true } else { false }
     }
 
     /// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
     pub fn opt_return_id(self) -> Option<NodeId> {
         match self {
-            IsAsync::Async { return_impl_trait_id, .. } => Some(return_impl_trait_id),
-            IsAsync::NotAsync => None,
+            Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id),
+            Async::No => None,
         }
     }
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 #[derive(HashStable_Generic)]
-pub enum Constness {
-    Const,
-    NotConst,
+pub enum Const {
+    Yes(Span),
+    No,
 }
 
 /// Item defaultness.
@@ -2527,9 +2495,9 @@ impl Extern {
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
 #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
 pub struct FnHeader {
-    pub unsafety: Unsafety,
-    pub asyncness: Spanned<IsAsync>,
-    pub constness: Spanned<Constness>,
+    pub unsafety: Unsafe,
+    pub asyncness: Async,
+    pub constness: Const,
     pub ext: Extern,
 }
 
@@ -2537,9 +2505,9 @@ 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!(unsafety, Unsafe::Yes(_))
+            || asyncness.is_async()
+            || matches!(constness, Const::Yes(_))
             || !matches!(ext, Extern::None)
     }
 }
@@ -2547,9 +2515,9 @@ impl FnHeader {
 impl Default for FnHeader {
     fn default() -> FnHeader {
         FnHeader {
-            unsafety: Unsafety::Normal,
-            asyncness: dummy_spanned(IsAsync::NotAsync),
-            constness: dummy_spanned(Constness::NotConst),
+            unsafety: Unsafe::No,
+            asyncness: Async::No,
+            constness: Const::No,
             ext: Extern::None,
         }
     }
@@ -2606,7 +2574,7 @@ pub enum ItemKind {
     /// A trait declaration (`trait`).
     ///
     /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
-    Trait(IsAuto, Unsafety, Generics, GenericBounds, Vec<P<AssocItem>>),
+    Trait(IsAuto, Unsafe, Generics, GenericBounds, Vec<P<AssocItem>>),
     /// Trait alias
     ///
     /// E.g., `trait Foo = Bar + Quux;`.
@@ -2615,10 +2583,10 @@ pub enum ItemKind {
     ///
     /// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
     Impl {
-        unsafety: Unsafety,
+        unsafety: Unsafe,
         polarity: ImplPolarity,
         defaultness: Defaultness,
-        constness: Constness,
+        constness: Const,
         generics: Generics,
 
         /// The trait being implemented, if any.
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 8517f223f92..e0180d45193 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -114,7 +114,7 @@ pub trait MutVisitor: Sized {
         noop_visit_fn_decl(d, self);
     }
 
-    fn visit_asyncness(&mut self, a: &mut IsAsync) {
+    fn visit_asyncness(&mut self, a: &mut Async) {
         noop_visit_asyncness(a, self);
     }
 
@@ -728,13 +728,13 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
     }
 }
 
-pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut IsAsync, vis: &mut T) {
+pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
     match asyncness {
-        IsAsync::Async { closure_id, return_impl_trait_id } => {
+        Async::Yes { span: _, closure_id, return_impl_trait_id } => {
             vis.visit_id(closure_id);
             vis.visit_id(return_impl_trait_id);
         }
-        IsAsync::NotAsync => {}
+        Async::No => {}
     }
 }
 
@@ -980,7 +980,7 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
 
 pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
     let FnHeader { unsafety: _, asyncness, constness: _, ext: _ } = header;
-    vis.visit_asyncness(&mut asyncness.node);
+    vis.visit_asyncness(asyncness);
 }
 
 pub fn noop_visit_mod<T: MutVisitor>(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) {
diff --git a/src/libsyntax/token.rs b/src/libsyntax/token.rs
index 3045f147698..862934300e0 100644
--- a/src/libsyntax/token.rs
+++ b/src/libsyntax/token.rs
@@ -402,12 +402,14 @@ impl Token {
 
     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
     /// for example a '-42', or one of the boolean idents).
+    ///
+    /// Keep this in sync with `Lit::from_token`.
     pub fn can_begin_literal_or_bool(&self) -> bool {
         match self.kind {
             Literal(..) | BinOp(Minus) => true,
             Ident(name, false) if name.is_bool_lit() => true,
-            Interpolated(ref nt) => match **nt {
-                NtLiteral(..) => true,
+            Interpolated(ref nt) => match &**nt {
+                NtExpr(e) | NtLiteral(e) => matches!(e.kind, ast::ExprKind::Lit(_)),
                 _ => false,
             },
             _ => false,
@@ -530,7 +532,7 @@ impl Token {
     }
 
     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
-    fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool {
+    pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool {
         match self.ident() {
             Some((id, false)) => pred(id),
             _ => false,
diff --git a/src/libsyntax/util/literal.rs b/src/libsyntax/util/literal.rs
index dd06c25b4de..0c611adc06b 100644
--- a/src/libsyntax/util/literal.rs
+++ b/src/libsyntax/util/literal.rs
@@ -188,6 +188,8 @@ impl Lit {
     }
 
     /// Converts arbitrary token into an AST literal.
+    ///
+    /// Keep this in sync with `Token::can_begin_literal_or_bool`.
     pub fn from_token(token: &Token) -> Result<Lit, LitError> {
         let lit = match token.kind {
             token::Ident(name, false) if name.is_bool_lit() => {
diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index 0f6a88b2691..7ac75c605f2 100644
--- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -121,7 +121,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
                 });
                 iter_exprs(depth - 1, &mut |e| g(
                         ExprKind::Closure(CaptureBy::Value,
-                                          IsAsync::NotAsync,
+                                          Async::No,
                                           Movability::Movable,
                                           decl.clone(),
                                           e,
diff --git a/src/test/ui/async-await/async-trait-fn.rs b/src/test/ui/async-await/async-trait-fn.rs
index 786100e916d..f0403b76620 100644
--- a/src/test/ui/async-await/async-trait-fn.rs
+++ b/src/test/ui/async-await/async-trait-fn.rs
@@ -1,7 +1,7 @@
 // edition:2018
 trait T {
-    async fn foo() {} //~ ERROR trait fns cannot be declared `async`
-    async fn bar(&self) {} //~ ERROR trait fns cannot be declared `async`
+    async fn foo() {} //~ ERROR functions in traits cannot be declared `async`
+    async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async`
 }
 
 fn main() {}
diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr
index 9acfa2cc069..6080b2815ee 100644
--- a/src/test/ui/async-await/async-trait-fn.stderr
+++ b/src/test/ui/async-await/async-trait-fn.stderr
@@ -1,17 +1,21 @@
-error[E0706]: trait fns cannot be declared `async`
+error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/async-trait-fn.rs:3:5
    |
 LL |     async fn foo() {}
-   |     ^^^^^^^^^^^^^^^^^
+   |     -----^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
    |
    = 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`
+error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/async-trait-fn.rs:4:5
    |
 LL |     async fn bar(&self) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     -----^^^^^^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs
index c85896150c2..5d2d186137e 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.rs
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs
@@ -16,7 +16,7 @@ impl Foo {
 
 trait Bar {
     async fn foo() {} //~ ERROR `async fn` is not permitted in the 2015 edition
-                      //~^ ERROR trait fns cannot be declared `async`
+                      //~^ ERROR functions in traits cannot be declared `async`
 }
 
 fn main() {
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
index bb09ee9a932..f3d982801bb 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
@@ -3,60 +3,98 @@ error[E0670]: `async fn` is not permitted in the 2015 edition
    |
 LL | async fn foo() {}
    | ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:5:12
    |
 LL | fn baz() { async fn foo() {} }
    |            ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:7:1
    |
 LL | async fn async_baz() {
    | ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:8:5
    |
 LL |     async fn bar() {}
    |     ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:14:5
    |
 LL |     async fn foo() {}
    |     ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:18:5
    |
 LL |     async fn foo() {}
    |     ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:36:9
    |
 LL |         async fn bar() {}
    |         ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:26:9
    |
 LL |         async fn foo() {}
    |         ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in the 2015 edition
   --> $DIR/edition-deny-async-fns-2015.rs:31:13
    |
 LL |             async fn bar() {}
    |             ^^^^^
+   |
+   = note: to use `async fn`, switch to Rust 2018
+   = help: set `edition = "2018"` in `Cargo.toml`
+   = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0706]: trait fns cannot be declared `async`
+error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/edition-deny-async-fns-2015.rs:18:5
    |
 LL |     async fn foo() {}
-   |     ^^^^^^^^^^^^^^^^^
+   |     -----^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
diff --git a/src/test/ui/async-await/no-async-const.rs b/src/test/ui/async-await/no-async-const.rs
index 64322990d0a..963460c1182 100644
--- a/src/test/ui/async-await/no-async-const.rs
+++ b/src/test/ui/async-await/no-async-const.rs
@@ -2,4 +2,4 @@
 // compile-flags: --crate-type lib
 
 pub async const fn x() {}
-//~^ ERROR expected one of `fn` or `unsafe`, found keyword `const`
+//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const`
diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr
index d5b8b344abe..e324a77187a 100644
--- a/src/test/ui/async-await/no-async-const.stderr
+++ b/src/test/ui/async-await/no-async-const.stderr
@@ -1,8 +1,8 @@
-error: expected one of `fn` or `unsafe`, found keyword `const`
+error: expected one of `extern`, `fn`, or `unsafe`, found keyword `const`
   --> $DIR/no-async-const.rs:4:11
    |
 LL | pub async const fn x() {}
-   |           ^^^^^ expected one of `fn` or `unsafe`
+   |           ^^^^^ expected one of `extern`, `fn`, or `unsafe`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs
index 55b27bd3fa1..b3c59734e03 100644
--- a/src/test/ui/async-await/no-const-async.rs
+++ b/src/test/ui/async-await/no-const-async.rs
@@ -2,5 +2,4 @@
 // compile-flags: --crate-type lib
 
 pub const async fn x() {}
-//~^ ERROR expected identifier, found keyword `async`
-//~^^ expected `:`, found keyword `fn`
+//~^ ERROR functions cannot be both `const` and `async`
diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr
index 62cd5c45d19..f6ae0f1447c 100644
--- a/src/test/ui/async-await/no-const-async.stderr
+++ b/src/test/ui/async-await/no-const-async.stderr
@@ -1,14 +1,11 @@
-error: expected identifier, found keyword `async`
-  --> $DIR/no-const-async.rs:4:11
+error: functions cannot be both `const` and `async`
+  --> $DIR/no-const-async.rs:4:1
    |
 LL | pub const async fn x() {}
-   |           ^^^^^ expected identifier, found keyword
+   | ^^^^-----^-----^^^^^^^^^^
+   |     |     |
+   |     |     `async` because of this
+   |     `const` because of this
 
-error: expected `:`, found keyword `fn`
-  --> $DIR/no-const-async.rs:4:17
-   |
-LL | pub const async fn x() {}
-   |                 ^^ expected `:`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/no-unsafe-async.rs b/src/test/ui/async-await/no-unsafe-async.rs
index 1ac1bdffda9..f40154e16f3 100644
--- a/src/test/ui/async-await/no-unsafe-async.rs
+++ b/src/test/ui/async-await/no-unsafe-async.rs
@@ -8,4 +8,4 @@ impl S {
 }
 
 #[cfg(FALSE)]
-unsafe async fn f() {} //~ ERROR expected one of `extern`, `fn`, or `{`, found keyword `async`
+unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async`
diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr
index bbeb3427849..2651588d597 100644
--- a/src/test/ui/async-await/no-unsafe-async.stderr
+++ b/src/test/ui/async-await/no-unsafe-async.stderr
@@ -4,11 +4,11 @@ error: expected one of `extern` or `fn`, found keyword `async`
 LL |     unsafe async fn g() {}
    |            ^^^^^ expected one of `extern` or `fn`
 
-error: expected one of `extern`, `fn`, or `{`, found keyword `async`
+error: expected one of `extern` or `fn`, found keyword `async`
   --> $DIR/no-unsafe-async.rs:11:8
    |
 LL | unsafe async fn f() {}
-   |        ^^^^^ expected one of `extern`, `fn`, or `{`
+   |        ^^^^^ expected one of `extern` or `fn`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/coherence/coherence-negative-impls-safe.stderr b/src/test/ui/coherence/coherence-negative-impls-safe.stderr
index c47c9d25e36..4db66af6783 100644
--- a/src/test/ui/coherence/coherence-negative-impls-safe.stderr
+++ b/src/test/ui/coherence/coherence-negative-impls-safe.stderr
@@ -2,7 +2,9 @@ error[E0198]: negative impls cannot be unsafe
   --> $DIR/coherence-negative-impls-safe.rs:7:1
    |
 LL | unsafe impl !Send for TestType {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | unsafe because of this
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const-fn-with-const-param.rs b/src/test/ui/const-generics/const-fn-with-const-param.rs
index f36bf3875c3..e9e236be556 100644
--- a/src/test/ui/const-generics/const-fn-with-const-param.rs
+++ b/src/test/ui/const-generics/const-fn-with-const-param.rs
@@ -2,7 +2,7 @@
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
 const fn const_u32_identity<const X: u32>() -> u32 {
-    //~^ ERROR const parameters are not permitted in `const fn`
+    //~^ ERROR const parameters are not permitted in const functions
     X
 }
 
diff --git a/src/test/ui/const-generics/const-fn-with-const-param.stderr b/src/test/ui/const-generics/const-fn-with-const-param.stderr
index 3437ed33d0c..ca31d695361 100644
--- a/src/test/ui/const-generics/const-fn-with-const-param.stderr
+++ b/src/test/ui/const-generics/const-fn-with-const-param.stderr
@@ -1,7 +1,11 @@
-error: const parameters are not permitted in `const fn`
+error: const parameters are not permitted in const functions
   --> $DIR/const-fn-with-const-param.rs:4:1
    |
-LL | / const fn const_u32_identity<const X: u32>() -> u32 {
+LL |   const fn const_u32_identity<const X: u32>() -> u32 {
+   |   ^----
+   |   |
+   |  _`const` because of this
+   | |
 LL | |
 LL | |     X
 LL | | }
diff --git a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs
index d39f2c1fe27..5667d553527 100644
--- a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs
+++ b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.rs
@@ -1,12 +1,10 @@
 // Check that `const extern fn` and `const unsafe extern fn` are feature-gated.
 
-#[cfg(FALSE)] const extern fn foo1() {} //~ ERROR `const extern fn` definitions are unstable
-#[cfg(FALSE)] const extern "C" fn foo2() {} //~ ERROR `const extern fn` definitions are unstable
-#[cfg(FALSE)] const extern "Rust" fn foo3() {} //~ ERROR `const extern fn` definitions are unstable
-#[cfg(FALSE)] const unsafe extern fn bar1() {} //~ ERROR `const extern fn` definitions are unstable
-#[cfg(FALSE)] const unsafe extern "C" fn bar2() {}
-//~^ ERROR `const extern fn` definitions are unstable
-#[cfg(FALSE)] const unsafe extern "Rust" fn bar3() {}
-//~^ ERROR `const extern fn` definitions are unstable
+const extern fn foo1() {} //~ ERROR `const extern fn` definitions are unstable
+const extern "C" fn foo2() {} //~ ERROR `const extern fn` definitions are unstable
+const extern "Rust" fn foo3() {} //~ ERROR `const extern fn` definitions are unstable
+const unsafe extern fn bar1() {} //~ ERROR `const extern fn` definitions are unstable
+const unsafe extern "C" fn bar2() {} //~ ERROR `const extern fn` definitions are unstable
+const unsafe extern "Rust" fn bar3() {} //~ ERROR `const extern fn` definitions are unstable
 
 fn main() {}
diff --git a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr
index ed5e0c84a16..bd5940a3fd6 100644
--- a/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr
+++ b/src/test/ui/consts/const-extern-fn/feature-gate-const_extern_fn.stderr
@@ -1,53 +1,53 @@
 error[E0658]: `const extern fn` definitions are unstable
-  --> $DIR/feature-gate-const_extern_fn.rs:3:15
+  --> $DIR/feature-gate-const_extern_fn.rs:3:1
    |
-LL | #[cfg(FALSE)] const extern fn foo1() {}
-   |               ^^^^^^^^^^^^
+LL | const extern fn foo1() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information
    = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
 
 error[E0658]: `const extern fn` definitions are unstable
-  --> $DIR/feature-gate-const_extern_fn.rs:4:15
+  --> $DIR/feature-gate-const_extern_fn.rs:4:1
    |
-LL | #[cfg(FALSE)] const extern "C" fn foo2() {}
-   |               ^^^^^^^^^^^^
+LL | const extern "C" fn foo2() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information
    = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
 
 error[E0658]: `const extern fn` definitions are unstable
-  --> $DIR/feature-gate-const_extern_fn.rs:5:15
+  --> $DIR/feature-gate-const_extern_fn.rs:5:1
    |
-LL | #[cfg(FALSE)] const extern "Rust" fn foo3() {}
-   |               ^^^^^^^^^^^^
+LL | const extern "Rust" fn foo3() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information
    = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
 
 error[E0658]: `const extern fn` definitions are unstable
-  --> $DIR/feature-gate-const_extern_fn.rs:6:15
+  --> $DIR/feature-gate-const_extern_fn.rs:6:1
    |
-LL | #[cfg(FALSE)] const unsafe extern fn bar1() {}
-   |               ^^^^^^^^^^^^^^^^^^^
+LL | const unsafe extern fn bar1() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information
    = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
 
 error[E0658]: `const extern fn` definitions are unstable
-  --> $DIR/feature-gate-const_extern_fn.rs:7:15
+  --> $DIR/feature-gate-const_extern_fn.rs:7:1
    |
-LL | #[cfg(FALSE)] const unsafe extern "C" fn bar2() {}
-   |               ^^^^^^^^^^^^^^^^^^^
+LL | const unsafe extern "C" fn bar2() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information
    = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
 
 error[E0658]: `const extern fn` definitions are unstable
-  --> $DIR/feature-gate-const_extern_fn.rs:9:15
+  --> $DIR/feature-gate-const_extern_fn.rs:8:1
    |
-LL | #[cfg(FALSE)] const unsafe extern "Rust" fn bar3() {}
-   |               ^^^^^^^^^^^^^^^^^^^
+LL | const unsafe extern "Rust" fn bar3() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information
    = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs
index 1886bfccb4e..6f575d055a2 100644
--- a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs
+++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs
@@ -4,5 +4,4 @@ fn main() {}
 fn container() {
     const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
     //~^ ERROR expected `fn`
-    //~| ERROR `const extern fn` definitions are unstable
 }
diff --git a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr
index d36b781d292..ec415ec9d02 100644
--- a/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr
+++ b/src/test/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.stderr
@@ -4,15 +4,5 @@ error: expected `fn`, found `PUT_ANYTHING_YOU_WANT_HERE`
 LL |     const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `fn`
 
-error[E0658]: `const extern fn` definitions are unstable
-  --> $DIR/issue-68062-const-extern-fns-dont-need-fn-specifier.rs:5:5
-   |
-LL |     const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
-   |     ^^^^^^^^^^^^
-   |
-   = note: see issue #64926 <https://github.com/rust-lang/rust/issues/64926> for more information
-   = help: add `#![feature(const_extern_fn)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/const-fn-mismatch.rs b/src/test/ui/consts/const-fn-mismatch.rs
index 5bd274fe66b..d4cfba6460c 100644
--- a/src/test/ui/consts/const-fn-mismatch.rs
+++ b/src/test/ui/consts/const-fn-mismatch.rs
@@ -10,8 +10,10 @@ trait Foo {
 }
 
 impl Foo for u32 {
-    const fn f() -> u32 { 22 }
-    //~^ ERROR trait fns cannot be declared const
+    const fn f() -> u32 {
+        //~^ ERROR functions in traits cannot be declared const
+        22
+    }
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/consts/const-fn-mismatch.stderr b/src/test/ui/consts/const-fn-mismatch.stderr
index 03bb7c6e8d6..0f4ce010fee 100644
--- a/src/test/ui/consts/const-fn-mismatch.stderr
+++ b/src/test/ui/consts/const-fn-mismatch.stderr
@@ -1,8 +1,8 @@
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/const-fn-mismatch.rs:13:5
    |
-LL |     const fn f() -> u32 { 22 }
-   |     ^^^^^ trait fns cannot be const
+LL |     const fn f() -> u32 {
+   |     ^^^^^ functions in traits cannot be const
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-fn-not-in-trait.rs b/src/test/ui/consts/const-fn-not-in-trait.rs
index 3975c22c56e..1006d854688 100644
--- a/src/test/ui/consts/const-fn-not-in-trait.rs
+++ b/src/test/ui/consts/const-fn-not-in-trait.rs
@@ -5,9 +5,11 @@
 
 trait Foo {
     const fn f() -> u32;
-    //~^ ERROR trait fns cannot be declared const
-    const fn g() -> u32 { 0 }
-    //~^ ERROR trait fns cannot be declared const
+    //~^ ERROR functions in traits cannot be declared const
+    const fn g() -> u32 {
+        //~^ ERROR functions in traits cannot be declared const
+        0
+    }
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/consts/const-fn-not-in-trait.stderr b/src/test/ui/consts/const-fn-not-in-trait.stderr
index 6821a6c2bc6..12ce3066037 100644
--- a/src/test/ui/consts/const-fn-not-in-trait.stderr
+++ b/src/test/ui/consts/const-fn-not-in-trait.stderr
@@ -1,14 +1,14 @@
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/const-fn-not-in-trait.rs:7:5
    |
 LL |     const fn f() -> u32;
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/const-fn-not-in-trait.rs:9:5
    |
-LL |     const fn g() -> u32 { 0 }
-   |     ^^^^^ trait fns cannot be const
+LL |     const fn g() -> u32 {
+   |     ^^^^^ functions in traits cannot be const
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0197.stderr b/src/test/ui/error-codes/E0197.stderr
index bb7b6474d3e..51ed9c83bc9 100644
--- a/src/test/ui/error-codes/E0197.stderr
+++ b/src/test/ui/error-codes/E0197.stderr
@@ -2,7 +2,9 @@ error[E0197]: inherent impls cannot be unsafe
   --> $DIR/E0197.rs:3:1
    |
 LL | unsafe impl Foo { }
-   | ^^^^^^^^^^^^^^^^^^^
+   | ------^^^^^^^^^^^^^
+   | |
+   | unsafe because of this
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0198.stderr b/src/test/ui/error-codes/E0198.stderr
index 0d3706336a9..90e8b4abd12 100644
--- a/src/test/ui/error-codes/E0198.stderr
+++ b/src/test/ui/error-codes/E0198.stderr
@@ -2,7 +2,9 @@ error[E0198]: negative impls cannot be unsafe
   --> $DIR/E0198.rs:5:1
    |
 LL | unsafe impl !Send for Foo { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ------^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | unsafe because of this
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/feature-gates/feature-gate-const_fn.rs b/src/test/ui/feature-gates/feature-gate-const_fn.rs
index f46d1dc13d3..691c367aeb8 100644
--- a/src/test/ui/feature-gates/feature-gate-const_fn.rs
+++ b/src/test/ui/feature-gates/feature-gate-const_fn.rs
@@ -4,13 +4,13 @@ const fn foo() -> usize { 0 } // ok
 
 trait Foo {
     const fn foo() -> u32; //~ ERROR const fn is unstable
-                           //~| ERROR trait fns cannot be declared const
+                           //~| ERROR functions in traits cannot be declared const
     const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
-                                //~| ERROR trait fns cannot be declared const
+                                //~| ERROR functions in traits cannot be declared const
 }
 
 impl Foo for u32 {
-    const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
+    const fn foo() -> u32 { 0 } //~ ERROR functions in traits cannot be declared const
 }
 
 trait Bar {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_fn.stderr b/src/test/ui/feature-gates/feature-gate-const_fn.stderr
index 6a44f079bfb..843e5630137 100644
--- a/src/test/ui/feature-gates/feature-gate-const_fn.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_fn.stderr
@@ -1,20 +1,20 @@
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/feature-gate-const_fn.rs:6:5
    |
 LL |     const fn foo() -> u32;
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/feature-gate-const_fn.rs:8:5
    |
 LL |     const fn bar() -> u32 { 0 }
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/feature-gate-const_fn.rs:13:5
    |
 LL |     const fn foo() -> u32 { 0 }
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
 error[E0658]: const fn is unstable
   --> $DIR/feature-gate-const_fn.rs:6:5
diff --git a/src/test/ui/feature-gates/feature-gate-min_const_fn.rs b/src/test/ui/feature-gates/feature-gate-min_const_fn.rs
index 669631df2ad..5a01e053ed0 100644
--- a/src/test/ui/feature-gates/feature-gate-min_const_fn.rs
+++ b/src/test/ui/feature-gates/feature-gate-min_const_fn.rs
@@ -4,13 +4,13 @@ const fn foo() -> usize { 0 } // stabilized
 
 trait Foo {
     const fn foo() -> u32; //~ ERROR const fn is unstable
-                           //~| ERROR trait fns cannot be declared const
+                           //~| ERROR functions in traits cannot be declared const
     const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
-                                //~| ERROR trait fns cannot be declared const
+                                //~| ERROR functions in traits cannot be declared const
 }
 
 impl Foo for u32 {
-    const fn foo() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
+    const fn foo() -> u32 { 0 } //~ ERROR functions in traits cannot be declared const
 }
 
 trait Bar {}
diff --git a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr
index 7ab9d748b31..56a882e30fc 100644
--- a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr
+++ b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr
@@ -1,20 +1,20 @@
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/feature-gate-min_const_fn.rs:6:5
    |
 LL |     const fn foo() -> u32;
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/feature-gate-min_const_fn.rs:8:5
    |
 LL |     const fn bar() -> u32 { 0 }
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/feature-gate-min_const_fn.rs:13:5
    |
 LL |     const fn foo() -> u32 { 0 }
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
 error[E0658]: const fn is unstable
   --> $DIR/feature-gate-min_const_fn.rs:6:5
diff --git a/src/test/ui/issues/issue-54954.rs b/src/test/ui/issues/issue-54954.rs
index 9e9f92ed9ac..3d6355f5c59 100644
--- a/src/test/ui/issues/issue-54954.rs
+++ b/src/test/ui/issues/issue-54954.rs
@@ -5,7 +5,7 @@ const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
 
 trait Tt {
     const fn const_val<T: Sized>() -> usize {
-    //~^ ERROR trait fns cannot be declared const
+        //~^ ERROR functions in traits cannot be declared const
         core::mem::size_of::<T>()
     }
 }
diff --git a/src/test/ui/issues/issue-54954.stderr b/src/test/ui/issues/issue-54954.stderr
index d99a5772e8a..4967b82216e 100644
--- a/src/test/ui/issues/issue-54954.stderr
+++ b/src/test/ui/issues/issue-54954.stderr
@@ -1,8 +1,8 @@
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/issue-54954.rs:7:5
    |
 LL |     const fn const_val<T: Sized>() -> usize {
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
 error[E0283]: type annotations needed
   --> $DIR/issue-54954.rs:3:24
diff --git a/src/test/ui/issues/issue-60075.rs b/src/test/ui/issues/issue-60075.rs
index 7d3fc83786e..1323f646be8 100644
--- a/src/test/ui/issues/issue-60075.rs
+++ b/src/test/ui/issues/issue-60075.rs
@@ -6,6 +6,5 @@ trait T {
         });
 //~^ ERROR expected one of `async`
 //~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}`
-//~| ERROR expected identifier, found `;`
         Some(4)
     }
diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr
index e8ef981f515..60eb99b46b7 100644
--- a/src/test/ui/issues/issue-60075.stderr
+++ b/src/test/ui/issues/issue-60075.stderr
@@ -13,11 +13,5 @@ LL |         let _ = if true {
 LL |         });
    |           ^ help: `}` may belong here
 
-error: expected identifier, found `;`
-  --> $DIR/issue-60075.rs:6:11
-   |
-LL |         });
-   |           ^ expected identifier
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/label/label_break_value_illegal_uses.rs b/src/test/ui/label/label_break_value_illegal_uses.rs
index 81cb1774380..9d4c72410a6 100644
--- a/src/test/ui/label/label_break_value_illegal_uses.rs
+++ b/src/test/ui/label/label_break_value_illegal_uses.rs
@@ -3,7 +3,7 @@
 // These are forbidden occurrences of label-break-value
 
 fn labeled_unsafe() {
-    unsafe 'b: {} //~ ERROR expected one of `extern`, `fn`, or `{`
+    unsafe 'b: {} //~ ERROR expected `{`, found `'b`
 }
 
 fn labeled_if() {
diff --git a/src/test/ui/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr
index 46b53c65b48..fd8850dd8da 100644
--- a/src/test/ui/label/label_break_value_illegal_uses.stderr
+++ b/src/test/ui/label/label_break_value_illegal_uses.stderr
@@ -1,8 +1,8 @@
-error: expected one of `extern`, `fn`, or `{`, found `'b`
+error: expected `{`, found `'b`
   --> $DIR/label_break_value_illegal_uses.rs:6:12
    |
 LL |     unsafe 'b: {}
-   |            ^^ expected one of `extern`, `fn`, or `{`
+   |            ^^ expected `{`
 
 error: expected `{`, found `'b`
   --> $DIR/label_break_value_illegal_uses.rs:10:13
diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.stderr b/src/test/ui/mismatched_types/const-fn-in-trait.stderr
index ec1f36bf087..817582df27d 100644
--- a/src/test/ui/mismatched_types/const-fn-in-trait.stderr
+++ b/src/test/ui/mismatched_types/const-fn-in-trait.stderr
@@ -1,14 +1,14 @@
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/const-fn-in-trait.rs:7:5
    |
 LL |     const fn g();
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
-error[E0379]: trait fns cannot be declared const
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/const-fn-in-trait.rs:11:5
    |
 LL |     const fn f() -> u32 { 22 }
-   |     ^^^^^ trait fns cannot be const
+   |     ^^^^^ functions in traits cannot be const
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/parser/extern-crate-async.rs b/src/test/ui/parser/extern-crate-async.rs
new file mode 100644
index 00000000000..6a54ac7f4a5
--- /dev/null
+++ b/src/test/ui/parser/extern-crate-async.rs
@@ -0,0 +1,12 @@
+// Make sure that we don't parse `extern crate async`
+// the front matter of a function leading us astray.
+
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+extern crate async;
+
+#[cfg(FALSE)]
+extern crate async as something_else;
diff --git a/src/test/ui/parser/extern-crate-unexpected-token.rs b/src/test/ui/parser/extern-crate-unexpected-token.rs
index 58b2fa1afdf..7687f5e6409 100644
--- a/src/test/ui/parser/extern-crate-unexpected-token.rs
+++ b/src/test/ui/parser/extern-crate-unexpected-token.rs
@@ -1 +1 @@
-extern crte foo; //~ ERROR expected one of `crate`, `fn`, or `{`, found `crte`
+extern crte foo; //~ ERROR expected one of `crate` or `{`, found `crte`
diff --git a/src/test/ui/parser/extern-crate-unexpected-token.stderr b/src/test/ui/parser/extern-crate-unexpected-token.stderr
index 0e745dc582f..e9d287ac0e9 100644
--- a/src/test/ui/parser/extern-crate-unexpected-token.stderr
+++ b/src/test/ui/parser/extern-crate-unexpected-token.stderr
@@ -1,8 +1,8 @@
-error: expected one of `crate`, `fn`, or `{`, found `crte`
+error: expected one of `crate` or `{`, found `crte`
   --> $DIR/extern-crate-unexpected-token.rs:1:8
    |
 LL | extern crte foo;
-   |        ^^^^ expected one of `crate`, `fn`, or `{`
+   |        ^^^^ expected one of `crate` or `{`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/extern-expected-fn-or-brace.rs b/src/test/ui/parser/extern-expected-fn-or-brace.rs
index 907de0d8f91..1dcea17445e 100644
--- a/src/test/ui/parser/extern-expected-fn-or-brace.rs
+++ b/src/test/ui/parser/extern-expected-fn-or-brace.rs
@@ -1,4 +1,3 @@
-// Verifies that the expected token errors for `extern crate` are
-// raised
+// Verifies that the expected token errors for `extern crate` are raised.
 
-extern "C" mod foo; //~ERROR expected one of `fn` or `{`, found keyword `mod`
+extern "C" mod foo; //~ERROR expected `{`, found keyword `mod`
diff --git a/src/test/ui/parser/extern-expected-fn-or-brace.stderr b/src/test/ui/parser/extern-expected-fn-or-brace.stderr
index 0ebe9a0d3ea..258a2c2680a 100644
--- a/src/test/ui/parser/extern-expected-fn-or-brace.stderr
+++ b/src/test/ui/parser/extern-expected-fn-or-brace.stderr
@@ -1,8 +1,8 @@
-error: expected one of `fn` or `{`, found keyword `mod`
-  --> $DIR/extern-expected-fn-or-brace.rs:4:12
+error: expected `{`, found keyword `mod`
+  --> $DIR/extern-expected-fn-or-brace.rs:3:12
    |
 LL | extern "C" mod foo;
-   |            ^^^ expected one of `fn` or `{`
+   |            ^^^ expected `{`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index c2b7e69c80d..c327667f4cd 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -10,30 +10,32 @@ fn main() {
     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.
+    const async unsafe extern "C" fn ff5() {} // OK.
+    //~^ ERROR functions cannot be both `const` and `async`
 
     trait X {
-        async fn ft1(); //~ ERROR trait fns cannot be declared `async`
+        async fn ft1(); //~ ERROR functions in traits cannot be declared `async`
         unsafe fn ft2(); // OK.
-        const fn ft3(); //~ ERROR trait fns cannot be declared const
+        const fn ft3(); //~ ERROR functions in traits 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.
+        const async unsafe extern "C" fn ft5();
+        //~^ ERROR functions in traits cannot be declared `async`
+        //~| ERROR functions in traits cannot be declared const
+        //~| ERROR functions cannot be both `const` and `async`
     }
 
     struct Y;
     impl X for Y {
-        async fn ft1() {} //~ ERROR trait fns cannot be declared `async`
+        async fn ft1() {} //~ ERROR functions in traits 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
+        const fn ft3() {} //~ ERROR functions in traits cannot be declared const
         extern "C" fn ft4() {}
-        /* const */ async unsafe extern "C" fn ft5() {}
-        //~^ ERROR trait fns cannot be declared `async`
+        const async unsafe extern "C" fn ft5() {}
+        //~^ ERROR functions in traits cannot be declared `async`
+        //~| ERROR functions in traits cannot be declared const
         //~| ERROR method `ft5` has an incompatible type for trait
-        //^ FIXME(Centril): `const` should be legal syntactically, ensure it's illegal semantically.
+        //~| ERROR functions cannot be both `const` and `async`
     }
 
     impl Y {
@@ -41,8 +43,8 @@ fn main() {
         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.
+        const async unsafe extern "C" fn fi5() {}
+        //~^ ERROR functions cannot be both `const` and `async`
     }
 
     extern {
@@ -50,8 +52,7 @@ fn main() {
         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.
+        const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks
+        //~^ ERROR functions cannot be both `const` and `async`
     }
 }
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 41d2d9b7faa..1142cee9851 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -1,53 +1,109 @@
-error[E0706]: trait fns cannot be declared `async`
+error: functions cannot be both `const` and `async`
+  --> $DIR/fn-header-semantic-fail.rs:13:5
+   |
+LL |     const async unsafe extern "C" fn ff5() {} // OK.
+   |     -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |     |
+   |     |     `async` because of this
+   |     `const` because of this
+
+error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/fn-header-semantic-fail.rs:17:9
    |
 LL |         async fn ft1();
-   |         ^^^^^^^^^^^^^^^
+   |         -----^^^^^^^^^^
+   |         |
+   |         `async` because of this
    |
    = 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
+error[E0379]: functions in traits cannot be declared const
   --> $DIR/fn-header-semantic-fail.rs:19:9
    |
 LL |         const fn ft3();
-   |         ^^^^^ trait fns cannot be const
+   |         ^^^^^ functions in traits cannot be const
+
+error[E0379]: functions in traits cannot be declared const
+  --> $DIR/fn-header-semantic-fail.rs:21:9
+   |
+LL |         const async unsafe extern "C" fn ft5();
+   |         ^^^^^ functions in traits cannot be const
 
-error[E0706]: trait fns cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:21:21
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:21:9
    |
-LL |         /* const */ async unsafe extern "C" fn ft5();
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         const async unsafe extern "C" fn ft5();
+   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |               |
+   |               `async` because of this
    |
    = 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
+error: functions cannot be both `const` and `async`
+  --> $DIR/fn-header-semantic-fail.rs:21:9
+   |
+LL |         const async unsafe extern "C" fn ft5();
+   |         -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |     |
+   |         |     `async` because of this
+   |         `const` because of this
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:29:9
    |
 LL |         async fn ft1() {}
-   |         ^^^^^^^^^^^^^^^^^
+   |         -----^^^^^^^^^^^^
+   |         |
+   |         `async` because of this
    |
    = 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
+error[E0379]: functions in traits cannot be declared const
+  --> $DIR/fn-header-semantic-fail.rs:32:9
    |
 LL |         const fn ft3() {}
-   |         ^^^^^ trait fns cannot be const
+   |         ^^^^^ functions in traits cannot be const
+
+error[E0379]: functions in traits cannot be declared const
+  --> $DIR/fn-header-semantic-fail.rs:34:9
+   |
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^ functions in traits cannot be const
 
-error[E0706]: trait fns cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:33:21
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
-LL |         /* const */ async unsafe extern "C" fn ft5() {}
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |               |
+   |               `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
+error: functions cannot be both `const` and `async`
+  --> $DIR/fn-header-semantic-fail.rs:34:9
+   |
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |     |
+   |         |     `async` because of this
+   |         `const` because of this
+
+error: functions cannot be both `const` and `async`
+  --> $DIR/fn-header-semantic-fail.rs:46:9
+   |
+LL |         const async unsafe extern "C" fn fi5() {}
+   |         -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |     |
+   |         |     `async` because of this
+   |         `const` because of this
+
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:49:18
+  --> $DIR/fn-header-semantic-fail.rs:51:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -57,7 +113,7 @@ 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
+  --> $DIR/fn-header-semantic-fail.rs:52:19
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -68,7 +124,7 @@ 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
+  --> $DIR/fn-header-semantic-fail.rs:53:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -79,7 +135,7 @@ 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
+  --> $DIR/fn-header-semantic-fail.rs:54:23
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -90,18 +146,27 @@ 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
+  --> $DIR/fn-header-semantic-fail.rs:55:42
    |
 LL |     extern {
    |     ------ in this `extern` block
 ...
-LL |         /* const */ async unsafe extern "C" fn fe5();
-   |                     ---------------------------^^^
-   |                     |
-   |                     help: remove the qualifiers: `fn`
+LL |         const async unsafe extern "C" fn fe5();
+   |         ---------------------------------^^^
+   |         |
+   |         help: remove the qualifiers: `fn`
+
+error: functions cannot be both `const` and `async`
+  --> $DIR/fn-header-semantic-fail.rs:55:9
+   |
+LL |         const async unsafe extern "C" fn fe5();
+   |         -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |     |
+   |         |     `async` because of this
+   |         `const` because of this
 
 error[E0053]: method `ft1` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:28:24
+  --> $DIR/fn-header-semantic-fail.rs:29:24
    |
 LL |         async fn ft1();
    |                       - type in trait
@@ -116,21 +181,21 @@ LL |         async fn ft1() {}
               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
+  --> $DIR/fn-header-semantic-fail.rs:34:48
    |
-LL |         /* const */ async unsafe extern "C" fn ft5();
-   |                                                     - type in trait
+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
+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
+error: aborting due to 20 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
index 145a208cb24..9e44541993d 100644
--- a/src/test/ui/parser/fn-header-syntactic-pass.rs
+++ b/src/test/ui/parser/fn-header-syntactic-pass.rs
@@ -3,9 +3,6 @@
 // check-pass
 // edition:2018
 
-#![feature(const_extern_fn)]
-//^ FIXME(Centril): move check to ast_validation.
-
 fn main() {}
 
 #[cfg(FALSE)]
@@ -14,16 +11,14 @@ fn syntax() {
     unsafe fn f();
     const fn f();
     extern "C" fn f();
-    const /* async */ unsafe extern "C" fn f();
-    //^ FIXME(Centril): `async` should be legal syntactically.
+    const async unsafe extern "C" fn f();
 
     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.
+        const async unsafe extern "C" fn f();
     }
 
     impl X for Y {
@@ -31,8 +26,7 @@ fn syntax() {
         unsafe fn f();
         const fn f();
         extern "C" fn f();
-        /* const */ async unsafe extern "C" fn f();
-        //^ FIXME(Centril): `const` should be legal syntactically.
+        const async unsafe extern "C" fn f();
     }
 
     impl Y {
@@ -40,8 +34,7 @@ fn syntax() {
         unsafe fn f();
         const fn f();
         extern "C" fn f();
-        /* const */ async unsafe extern "C" fn f();
-        //^ FIXME(Centril): `const` should be legal syntactically.
+        const async unsafe extern "C" fn f();
     }
 
     extern {
@@ -49,7 +42,6 @@ fn syntax() {
         unsafe fn f();
         const fn f();
         extern "C" fn f();
-        /* const */ async unsafe extern "C" fn f();
-        //^ FIXME(Centril): `const` should be legal syntactically.
+        const async unsafe extern "C" fn f();
     }
 }
diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs
index 90221039b41..2158a2fd6c1 100644
--- a/src/test/ui/parser/issue-19398.rs
+++ b/src/test/ui/parser/issue-19398.rs
@@ -1,5 +1,5 @@
 trait T {
-    extern "Rust" unsafe fn foo(); //~ ERROR expected `fn`, found keyword `unsafe`
+    extern "Rust" unsafe fn foo(); //~ ERROR expected one of `async`, `const`
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr
index 41ec4f3ced4..201a6b2d66a 100644
--- a/src/test/ui/parser/issue-19398.stderr
+++ b/src/test/ui/parser/issue-19398.stderr
@@ -1,8 +1,10 @@
-error: expected `fn`, found keyword `unsafe`
-  --> $DIR/issue-19398.rs:2:19
+error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `extern`
+  --> $DIR/issue-19398.rs:2:5
    |
+LL | trait T {
+   |          - expected one of 10 possible tokens
 LL |     extern "Rust" unsafe fn foo();
-   |                   ^^^^^^ expected `fn`
+   |     ^^^^^^ unexpected token
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr
index b196f9ef573..061af3c94b4 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr
@@ -2,7 +2,9 @@ error: const trait impls are not yet implemented
   --> $DIR/feature-gate.rs:9:1
    |
 LL | impl const T for S {}
-   | ^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^-----^^^^^^^^^^^
+   |      |
+   |      const because of this
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr
index 6e1cdde0843..cfe226ea7a7 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr
@@ -11,7 +11,9 @@ error: const trait impls are not yet implemented
   --> $DIR/feature-gate.rs:9:1
    |
 LL | impl const T for S {}
-   | ^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^-----^^^^^^^^^^^
+   |      |
+   |      const because of this
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
index 508c6f4c747..bdc95ff2a57 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
@@ -2,7 +2,9 @@ error: inherent impls cannot be `const`
   --> $DIR/inherent-impl.rs:9:1
    |
 LL | impl const S {}
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^-----^^^^^
+   |      |
+   |      `const` because of this
    |
    = note: only trait implementations may be annotated with `const`
 
@@ -10,7 +12,9 @@ error: inherent impls cannot be `const`
   --> $DIR/inherent-impl.rs:13:1
    |
 LL | impl const T {}
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^-----^^^^^
+   |      |
+   |      `const` because of this
    |
    = note: only trait implementations may be annotated with `const`
 
@@ -18,13 +22,17 @@ error: const trait impls are not yet implemented
   --> $DIR/inherent-impl.rs:9:1
    |
 LL | impl const S {}
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^-----^^^^^
+   |      |
+   |      const because of this
 
 error: const trait impls are not yet implemented
   --> $DIR/inherent-impl.rs:13:1
    |
 LL | impl const T {}
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^-----^^^^^
+   |      |
+   |      const because of this
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/syntax-trait-polarity.stderr b/src/test/ui/syntax-trait-polarity.stderr
index b66db9feedb..fef3a650888 100644
--- a/src/test/ui/syntax-trait-polarity.stderr
+++ b/src/test/ui/syntax-trait-polarity.stderr
@@ -8,7 +8,9 @@ error[E0198]: negative impls cannot be unsafe
   --> $DIR/syntax-trait-polarity.rs:12:1
    |
 LL | unsafe impl !Send for TestType {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | unsafe because of this
 
 error: inherent impls cannot be negative
   --> $DIR/syntax-trait-polarity.rs:19:1
@@ -20,7 +22,9 @@ error[E0198]: negative impls cannot be unsafe
   --> $DIR/syntax-trait-polarity.rs:22:1
    |
 LL | unsafe impl<T> !Send for TestType2<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |
+   | unsafe because of this
 
 error[E0192]: negative impls are only allowed for auto traits (e.g., `Send` and `Sync`)
   --> $DIR/syntax-trait-polarity.rs:14:1
diff --git a/src/test/ui/traits/trait-safety-inherent-impl.stderr b/src/test/ui/traits/trait-safety-inherent-impl.stderr
index 3911261083e..c398785d394 100644
--- a/src/test/ui/traits/trait-safety-inherent-impl.stderr
+++ b/src/test/ui/traits/trait-safety-inherent-impl.stderr
@@ -1,7 +1,11 @@
 error[E0197]: inherent impls cannot be unsafe
   --> $DIR/trait-safety-inherent-impl.rs:5:1
    |
-LL | / unsafe impl SomeStruct {
+LL |   unsafe impl SomeStruct {
+   |   ^-----
+   |   |
+   |  _unsafe because of this
+   | |
 LL | |     fn foo(self) { }
 LL | | }
    | |_^
diff --git a/src/test/ui/unsafe/unsafe-block-without-braces.rs b/src/test/ui/unsafe/unsafe-block-without-braces.rs
index a291eb2eed7..4e461161854 100644
--- a/src/test/ui/unsafe/unsafe-block-without-braces.rs
+++ b/src/test/ui/unsafe/unsafe-block-without-braces.rs
@@ -3,4 +3,4 @@ fn main() {
         std::mem::transmute::<f32, u32>(1.0);
     //}
 }
-//~^^^ ERROR expected one of `extern`, `fn`, or `{`, found `std`
+//~^^^ ERROR expected `{`, found `std`
diff --git a/src/test/ui/unsafe/unsafe-block-without-braces.stderr b/src/test/ui/unsafe/unsafe-block-without-braces.stderr
index 637fdeead36..13e0c3681fa 100644
--- a/src/test/ui/unsafe/unsafe-block-without-braces.stderr
+++ b/src/test/ui/unsafe/unsafe-block-without-braces.stderr
@@ -1,8 +1,8 @@
-error: expected one of `extern`, `fn`, or `{`, found `std`
+error: expected `{`, found `std`
   --> $DIR/unsafe-block-without-braces.rs:3:9
    |
 LL |     unsafe //{
-   |           - expected one of `extern`, `fn`, or `{`
+   |           - expected `{`
 LL |         std::mem::transmute::<f32, u32>(1.0);
    |         ^^^ unexpected token