From e839b2ec849246ec5efe5069c8d874dbef289462 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Thu, 30 Jan 2020 02:42:33 +0100
Subject: [PATCH 01/13] Constness -> enum Const { Yes(Span), No } Same idea for
 `Unsafety` & use new span for better diagnostics.

---
 src/librustc/traits/auto_trait.rs             |  3 +-
 src/librustc/traits/error_reporting/mod.rs    |  2 +-
 src/librustc/traits/select.rs                 |  8 +-
 src/librustc/ty/fold.rs                       |  3 +-
 src/librustc/ty/mod.rs                        |  4 +-
 src/librustc/ty/print/pretty.rs               |  2 +-
 src/librustc/ty/structural_impls.rs           |  4 +-
 src/librustc_ast_lowering/item.rs             | 30 ++++++--
 src/librustc_ast_lowering/lib.rs              |  2 +-
 src/librustc_ast_passes/ast_validation.rs     | 30 ++++----
 src/librustc_ast_passes/feature_gate.rs       |  3 +-
 src/librustc_ast_pretty/pprust.rs             | 20 ++---
 .../deriving/generic/mod.rs                   |  6 +-
 src/librustc_builtin_macros/deriving/mod.rs   |  4 +-
 .../global_allocator.rs                       |  4 +-
 src/librustc_builtin_macros/test.rs           |  6 +-
 src/librustc_hir/hir.rs                       | 48 ++++++++----
 src/librustc_hir/print.rs                     |  2 +-
 src/librustc_interface/util.rs                |  2 +-
 src/librustc_lint/builtin.rs                  |  6 +-
 .../borrow_check/type_check/mod.rs            |  5 +-
 .../transform/qualify_min_const_fn.rs         |  3 +-
 src/librustc_parse/parser/item.rs             | 77 ++++++++-----------
 src/librustc_parse/parser/mod.rs              | 12 ++-
 src/librustc_save_analysis/sig.rs             | 16 ++--
 src/librustc_typeck/astconv.rs                |  6 +-
 src/librustc_typeck/check/mod.rs              |  4 +-
 src/librustc_typeck/collect.rs                | 10 +--
 src/librustc_typeck/lib.rs                    |  2 +-
 src/librustdoc/doctree.rs                     |  2 +-
 src/libsyntax/ast.rs                          | 68 +++++-----------
 .../coherence-negative-impls-safe.stderr      |  4 +-
 .../const-fn-with-const-param.stderr          |  6 +-
 src/test/ui/error-codes/E0197.stderr          |  4 +-
 src/test/ui/error-codes/E0198.stderr          |  4 +-
 .../feature-gate.gated.stderr                 |  4 +-
 .../feature-gate.stock.stderr                 |  4 +-
 .../inherent-impl.stderr                      | 16 +++-
 src/test/ui/syntax-trait-polarity.stderr      |  8 +-
 .../traits/trait-safety-inherent-impl.stderr  |  6 +-
 40 files changed, 238 insertions(+), 212 deletions(-)

diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index 1255728de37b1..3ab87ce8eb4a3 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 a7a2b578b82da..c25b392ec239a 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 bf82d743c2b04..1fe8ab58d152c 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 0dddca98c6257..1f007b970b0ca 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 393d49a4e4b05..2bda99e6d20fc 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 274482cba64cc..384422956367a 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 acd6c9597518d..59dd41e9d56c9 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/item.rs b/src/librustc_ast_lowering/item.rs
index dab950e23f618..8cc3479dd1ba3 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));
@@ -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,
@@ -1245,9 +1247,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
         hir::FnHeader {
-            unsafety: h.unsafety,
+            unsafety: self.lower_unsafety(h.unsafety),
             asyncness: self.lower_asyncness(h.asyncness.node),
-            constness: h.constness.node,
+            constness: self.lower_constness(h.constness),
             abi: self.lower_extern(h.ext),
         }
     }
@@ -1281,6 +1283,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
+    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,
+        }
+    }
+
     pub(super) fn lower_generics_mut(
         &mut self,
         generics: &Generics,
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 5816a64fca52c..618b1e7964b95 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 057acec959801..de4f092dbf011 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;
@@ -234,16 +233,11 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
-        if constness.node == Constness::Const {
-            struct_span_err!(
-                self.session,
-                constness.span,
-                E0379,
-                "trait fns cannot be declared const"
-            )
-            .span_label(constness.span, "trait fns cannot be const")
-            .emit();
+    fn check_trait_fn_not_const(&self, constness: Const) {
+        if let Const::Yes(span) = constness {
+            struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const")
+                .span_label(span, "trait fns cannot be const")
+                .emit();
         }
     }
 
@@ -487,7 +481,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 +508,13 @@ 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`")
+                        .span_label(const_span, "`const fn` because of this")
                         .emit();
                 }
             }
@@ -754,13 +749,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 +778,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 +797,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();
                 }
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index a10ac94d8942b..cfab54925b161 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -538,8 +538,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");
                 }
             }
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 78bf149f0e01a..633964683dcc6 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -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,11 +2733,7 @@ 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_constness(header.constness);
         self.print_asyncness(header.asyncness.node);
         self.print_unsafety(header.unsafety);
 
@@ -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 f99008a6d5c14..5cf233e222e7c 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 914dcdf196921..63cd03527e15c 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 ec0d55b38a73d..52f033e8b1404 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 2d6ff81aea8b8..dd93596b3cfce 100644
--- a/src/librustc_builtin_macros/test.rs
+++ b/src/librustc_builtin_macros/test.rs
@@ -375,8 +375,10 @@ 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() {
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 27bca1625c1c1..c2ddaf7df316a 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 071c3de4b1c2c..b31b814d67be6 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 let hir::Constness::Const = constness {
                     self.word_nbsp("const");
                 }
 
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 3052c9fc26f08..659323d1c2555 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 c827a7f3d5283..93fca43d67c1f 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 100fd7dc48d0e..4cbe41455894b 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 6a68ccdddffdc..b12f4ce32698f 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/item.rs b/src/librustc_parse/parser/item.rs
index 07d8bae4725bd..a66a85b2b830f 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -12,7 +12,7 @@ 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::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind};
-use syntax::ast::{Constness, Defaultness, Extern, IsAsync, IsAuto, PathSegment, StrLit, Unsafety};
+use syntax::ast::{Const, Defaultness, Extern, IsAsync, IsAuto, PathSegment, StrLit, Unsafe};
 use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
 use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind};
 use syntax::ptr::P;
@@ -107,9 +107,9 @@ impl<'a> Parser<'a> {
                 // EXTERN FUNCTION ITEM
                 let fn_span = self.prev_span;
                 let header = FnHeader {
-                    unsafety: Unsafety::Normal,
+                    unsafety: Unsafe::No,
                     asyncness: respan(fn_span, IsAsync::NotAsync),
-                    constness: respan(fn_span, Constness::NotConst),
+                    constness: Const::No,
                     ext: Extern::from_abi(abi),
                 };
                 return self.parse_item_fn(lo, vis, attrs, header);
@@ -128,8 +128,8 @@ impl<'a> Parser<'a> {
             return self.mk_item_with_info(attrs, lo, vis, info);
         }
 
-        if self.eat_keyword(kw::Const) {
-            let const_span = self.prev_span;
+        let constness = self.parse_constness();
+        if let Const::Yes(const_span) = constness {
             if [kw::Fn, kw::Unsafe, kw::Extern].iter().any(|k| self.check_keyword(*k)) {
                 // CONST FUNCTION ITEM
                 let unsafety = self.parse_unsafety();
@@ -143,7 +143,7 @@ impl<'a> Parser<'a> {
                 let header = FnHeader {
                     unsafety,
                     asyncness: respan(const_span, IsAsync::NotAsync),
-                    constness: respan(const_span, Constness::Const),
+                    constness,
                     ext,
                 };
                 return self.parse_item_fn(lo, vis, attrs, header);
@@ -175,7 +175,6 @@ impl<'a> Parser<'a> {
                 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 {
@@ -184,20 +183,16 @@ impl<'a> Parser<'a> {
                     },
                 );
                 self.ban_async_in_2015(async_span);
-                let header = FnHeader {
-                    unsafety,
-                    asyncness,
-                    constness: respan(fn_span, Constness::NotConst),
-                    ext: Extern::None,
-                };
+                let header =
+                    FnHeader { unsafety, asyncness, constness: Const::No, 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);
         }
 
@@ -218,9 +213,9 @@ impl<'a> Parser<'a> {
             self.bump();
             let fn_span = self.prev_span;
             let header = FnHeader {
-                unsafety: Unsafety::Normal,
+                unsafety: Unsafe::No,
                 asyncness: respan(fn_span, IsAsync::NotAsync),
-                constness: respan(fn_span, Constness::NotConst),
+                constness: Const::No,
                 ext: Extern::None,
             };
             return self.parse_item_fn(lo, vis, attrs, header);
@@ -230,16 +225,16 @@ impl<'a> Parser<'a> {
             && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace))
         {
             // UNSAFE FUNCTION ITEM
-            self.bump(); // `unsafe`
+            let unsafety = self.parse_unsafety();
             // `{` 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,
+                unsafety,
                 asyncness: respan(fn_span, IsAsync::NotAsync),
-                constness: respan(fn_span, Constness::NotConst),
+                constness: Const::No,
                 ext,
             };
             return self.parse_item_fn(lo, vis, attrs, header);
@@ -268,7 +263,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 +542,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 +556,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 +699,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 };
 
@@ -734,11 +726,11 @@ impl<'a> Parser<'a> {
             self.expect_semi()?;
 
             let whole_span = lo.to(self.prev_span);
-            if is_auto == IsAuto::Yes {
+            if let IsAuto::Yes = is_auto {
                 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();
             }
@@ -1785,28 +1777,27 @@ impl<'a> Parser<'a> {
         Ok(body)
     }
 
-    /// Parses all the "front matter" for a `fn` declaration, up to
-    /// and including the `fn` keyword:
+    /// 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)
+        let (constness, unsafety, ext) = if let Const::Yes(_) = constness {
+            (constness, unsafety, Extern::None)
         } else {
             let ext = self.parse_extern()?;
-            (respan(self.prev_span, Constness::NotConst), unsafety, ext)
+            (Const::No, unsafety, ext)
         };
         if !self.eat_keyword(kw::Fn) {
             // It is possible for `expect_one_of` to recover given the contents of
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index e1461dbb8e763..bccf5968118b4 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -22,7 +22,8 @@ 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::DUMMY_NODE_ID;
+use syntax::ast::{self, AttrStyle, AttrVec, Const, CrateSugar, Extern, Ident, Unsafe};
 use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind};
 use syntax::ptr::P;
 use syntax::token::{self, DelimToken, Token, TokenKind};
@@ -962,8 +963,13 @@ impl<'a> Parser<'a> {
     }
 
     /// 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).
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 6401cabdcd5c1..820202c85ab87 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() {
                     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() {
         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 c26b47c313023..0e7c10541cad7 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 fd0c994a6eadf..a825856e38aa0 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 f3a1f412d0d59..5349c324ad8a7 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 474868f0dd6c4..067b33c144742 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 218674b757f39..744201a00500b 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 b22406124e098..a7142dfda8593 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -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,43 +2101,11 @@ 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)]
@@ -2162,9 +2130,9 @@ impl IsAsync {
 
 #[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 unsafety: Unsafe,
     pub asyncness: Spanned<IsAsync>,
-    pub constness: Spanned<Constness>,
+    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)
+        matches!(unsafety, Unsafe::Yes(_))
             || asyncness.node.is_async()
-            || matches!(constness.node, Constness::Const)
+            || 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,
+            unsafety: Unsafe::No,
             asyncness: dummy_spanned(IsAsync::NotAsync),
-            constness: dummy_spanned(Constness::NotConst),
+            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/test/ui/coherence/coherence-negative-impls-safe.stderr b/src/test/ui/coherence/coherence-negative-impls-safe.stderr
index c47c9d25e3614..4db66af6783ca 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.stderr b/src/test/ui/const-generics/const-fn-with-const-param.stderr
index 3437ed33d0c6f..68670963f8e5e 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`
   --> $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 fn` because of this
+   | |
 LL | |
 LL | |     X
 LL | | }
diff --git a/src/test/ui/error-codes/E0197.stderr b/src/test/ui/error-codes/E0197.stderr
index bb7b6474d3e38..51ed9c83bc999 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 0d3706336a9ca..90e8b4abd1296 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/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr
index b196f9ef57380..061af3c94b44d 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 6e1cdde084396..cfe226ea7a7ce 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 508c6f4c747e1..bdc95ff2a57b5 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 b66db9feedbdc..fef3a65088855 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 3911261083ecc..c398785d3949e 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 | | }
    | |_^

From c30f068dc8b2ef58678b9846ba834dd6dea3fe44 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Thu, 30 Jan 2020 05:31:04 +0100
Subject: [PATCH 02/13] IsAsync -> enum Async { Yes { span: Span, .. }, No }
 use new span for better diagnostics.

---
 src/librustc_ast_lowering/expr.rs             |  2 +-
 src/librustc_ast_lowering/item.rs             | 27 +++++-------
 src/librustc_ast_passes/ast_validation.rs     | 12 ++---
 src/librustc_ast_pretty/pprust.rs             |  4 +-
 src/librustc_builtin_macros/test.rs           |  6 ++-
 src/librustc_expand/build.rs                  |  4 +-
 src/librustc_parse/parser/expr.rs             |  4 +-
 src/librustc_parse/parser/item.rs             | 44 ++++---------------
 src/librustc_parse/parser/mod.rs              |  9 ++--
 src/librustc_resolve/def_collector.rs         | 12 ++---
 src/librustc_resolve/late.rs                  |  2 +-
 src/librustc_save_analysis/dump_visitor.rs    |  8 ++--
 src/librustc_save_analysis/sig.rs             |  4 +-
 src/libsyntax/ast.rs                          | 26 +++++------
 src/libsyntax/mut_visit.rs                    | 10 ++---
 src/test/ui-fulldeps/pprust-expr-roundtrip.rs |  2 +-
 src/test/ui/async-await/async-trait-fn.stderr |  8 +++-
 .../edition-deny-async-fns-2015.stderr        |  4 +-
 .../ui/parser/fn-header-semantic-fail.stderr  | 16 +++++--
 19 files changed, 96 insertions(+), 108 deletions(-)

diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs
index dd3316979f6a2..b51d476558312 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 8cc3479dd1ba3..73a25620b5a04 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -299,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());
 
@@ -836,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))
@@ -1033,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| {
@@ -1248,7 +1245,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
         hir::FnHeader {
             unsafety: self.lower_unsafety(h.unsafety),
-            asyncness: self.lower_asyncness(h.asyncness.node),
+            asyncness: self.lower_asyncness(h.asyncness),
             constness: self.lower_constness(h.constness),
             abi: self.lower_extern(h.ext),
         }
@@ -1276,10 +1273,10 @@ 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,
         }
     }
 
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index de4f092dbf011..e0217de1d3b8d 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -221,13 +221,13 @@ 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`")
+    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, "trait fns 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",
+                    "consider using the `async-trait` crate: https://crates.io/crates/async-trait",
                 )
                 .emit();
         }
@@ -1144,7 +1144,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_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index 633964683dcc6..b1fa818d0a8cf 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");
         }
@@ -2734,7 +2734,7 @@ impl<'a> State<'a> {
         self.s.word(visibility_qualified(vis, ""));
 
         self.print_constness(header.constness);
-        self.print_asyncness(header.asyncness.node);
+        self.print_asyncness(header.asyncness);
         self.print_unsafety(header.unsafety);
 
         match header.ext {
diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs
index dd93596b3cfce..a246e11495345 100644
--- a/src/librustc_builtin_macros/test.rs
+++ b/src/librustc_builtin_macros/test.rs
@@ -381,8 +381,10 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
                 .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 11f94ab2e6279..af22e46eb6afa 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_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index 77748d16653a7..5a4225ece65aa 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 a66a85b2b830f..aa43c15e286ed 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, Extern, IsAuto, PathSegment, StrLit, Unsafe};
 use syntax::ast::{BindingMode, Block, FnDecl, FnSig, Mac, MacArgs, MacDelimiter, Param, SelfKind};
-use syntax::ast::{Const, Defaultness, Extern, IsAsync, IsAuto, PathSegment, StrLit, Unsafe};
 use syntax::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
 use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind};
 use syntax::ptr::P;
@@ -105,10 +105,9 @@ impl<'a> Parser<'a> {
 
             if self.eat_keyword(kw::Fn) {
                 // EXTERN FUNCTION ITEM
-                let fn_span = self.prev_span;
                 let header = FnHeader {
                     unsafety: Unsafe::No,
-                    asyncness: respan(fn_span, IsAsync::NotAsync),
+                    asyncness: Async::No,
                     constness: Const::No,
                     ext: Extern::from_abi(abi),
                 };
@@ -140,12 +139,7 @@ impl<'a> Parser<'a> {
                 let ext = self.parse_extern()?;
                 self.expect_keyword(kw::Fn)?;
 
-                let header = FnHeader {
-                    unsafety,
-                    asyncness: respan(const_span, IsAsync::NotAsync),
-                    constness,
-                    ext,
-                };
+                let header = FnHeader { unsafety, asyncness: Async::No, constness, ext };
                 return self.parse_item_fn(lo, vis, attrs, header);
             }
 
@@ -172,16 +166,9 @@ impl<'a> Parser<'a> {
             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 asyncness = self.parse_asyncness(); // `async`
                 let unsafety = self.parse_unsafety(); // `unsafe`?
                 self.expect_keyword(kw::Fn)?; // `fn`
-                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: Const::No, ext: Extern::None };
@@ -211,13 +198,7 @@ impl<'a> Parser<'a> {
         if self.check_keyword(kw::Fn) {
             // FUNCTION ITEM
             self.bump();
-            let fn_span = self.prev_span;
-            let header = FnHeader {
-                unsafety: Unsafe::No,
-                asyncness: respan(fn_span, IsAsync::NotAsync),
-                constness: Const::No,
-                ext: Extern::None,
-            };
+            let header = FnHeader::default();
             return self.parse_item_fn(lo, vis, attrs, header);
         }
 
@@ -230,13 +211,7 @@ impl<'a> Parser<'a> {
             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,
-                asyncness: respan(fn_span, IsAsync::NotAsync),
-                constness: Const::No,
-                ext,
-            };
+            let header = FnHeader { unsafety, asyncness: Async::No, constness: Const::No, ext };
             return self.parse_item_fn(lo, vis, attrs, header);
         }
 
@@ -1788,10 +1763,9 @@ impl<'a> Parser<'a> {
     fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
         let constness = self.parse_constness();
         let asyncness = self.parse_asyncness();
-        if let IsAsync::Async { .. } = asyncness {
-            self.ban_async_in_2015(self.prev_span);
+        if let Async::Yes { span, .. } = asyncness {
+            self.ban_async_in_2015(span);
         }
-        let asyncness = respan(self.prev_span, asyncness);
         let unsafety = self.parse_unsafety();
         let (constness, unsafety, ext) = if let Const::Yes(_) = constness {
             (constness, unsafety, Extern::None)
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index bccf5968118b4..2f2f2f8f176e5 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -24,7 +24,7 @@ use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{FileName, Span, DUMMY_SP};
 use syntax::ast::DUMMY_NODE_ID;
 use syntax::ast::{self, AttrStyle, AttrVec, Const, CrateSugar, Extern, Ident, Unsafe};
-use syntax::ast::{IsAsync, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind};
+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};
@@ -954,11 +954,12 @@ 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
         }
     }
 
diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs
index 3a26197c1607a..fe80dec513cfe 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 01a0e568137b2..58ff7f447890c 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 5ce81c104e17c..01e3e3f368529 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 820202c85ab87..d3c4d6d5723b9 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -368,7 +368,7 @@ impl Sig for ast::Item {
                 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 let ast::Unsafe::Yes(_) = header.unsafety {
@@ -887,7 +887,7 @@ fn make_method_signature(
     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 let ast::Unsafe::Yes(_) = m.header.unsafety {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a7142dfda8593..72430fa9c17e4 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.
@@ -2109,21 +2109,21 @@ pub enum Unsafe {
 }
 
 #[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,
         }
     }
 }
@@ -2496,7 +2496,7 @@ impl Extern {
 #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
 pub struct FnHeader {
     pub unsafety: Unsafe,
-    pub asyncness: Spanned<IsAsync>,
+    pub asyncness: Async,
     pub constness: Const,
     pub ext: Extern,
 }
@@ -2506,7 +2506,7 @@ impl FnHeader {
     pub fn has_qualifiers(&self) -> bool {
         let Self { unsafety, asyncness, constness, ext } = self;
         matches!(unsafety, Unsafe::Yes(_))
-            || asyncness.node.is_async()
+            || asyncness.is_async()
             || matches!(constness, Const::Yes(_))
             || !matches!(ext, Extern::None)
     }
@@ -2516,7 +2516,7 @@ impl Default for FnHeader {
     fn default() -> FnHeader {
         FnHeader {
             unsafety: Unsafe::No,
-            asyncness: dummy_spanned(IsAsync::NotAsync),
+            asyncness: Async::No,
             constness: Const::No,
             ext: Extern::None,
         }
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 8517f223f92e3..e0180d451936f 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/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index 0f6a88b2691a8..7ac75c605f2e4 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.stderr b/src/test/ui/async-await/async-trait-fn.stderr
index 9acfa2cc06912..04f72fb645e28 100644
--- a/src/test/ui/async-await/async-trait-fn.stderr
+++ b/src/test/ui/async-await/async-trait-fn.stderr
@@ -2,7 +2,9 @@ error[E0706]: trait fns 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
@@ -11,7 +13,9 @@ error[E0706]: trait fns 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.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
index bb09ee9a93296..e6859a3cd93a0 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
@@ -56,7 +56,9 @@ error[E0706]: trait fns 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/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 41d2d9b7faaf1..689bbdd8bab88 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -2,7 +2,9 @@ error[E0706]: trait fns 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
@@ -17,7 +19,9 @@ error[E0706]: trait fns cannot be declared `async`
   --> $DIR/fn-header-semantic-fail.rs:21:21
    |
 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
@@ -26,7 +30,9 @@ error[E0706]: trait fns cannot be declared `async`
   --> $DIR/fn-header-semantic-fail.rs:28: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
@@ -41,7 +47,9 @@ error[E0706]: trait fns cannot be declared `async`
   --> $DIR/fn-header-semantic-fail.rs:33:21
    |
 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

From 36a17e4067d2e67223cd9a172476ee5503d6b44b Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Thu, 30 Jan 2020 08:31:31 +0100
Subject: [PATCH 03/13] parser_fn_front_matter: allow `const .. extern`

---
 src/librustc_parse/parser/item.rs             | 105 +++++++++---------
 src/librustc_parse/parser/stmt.rs             |   2 +-
 src/test/ui/issues/issue-60075.rs             |   1 -
 src/test/ui/issues/issue-60075.stderr         |   8 +-
 src/test/ui/parser/fn-header-semantic-fail.rs |  15 +--
 .../ui/parser/fn-header-semantic-fail.stderr  |  68 +++++++-----
 .../ui/parser/fn-header-syntactic-pass.rs     |  12 +-
 7 files changed, 104 insertions(+), 107 deletions(-)

diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index aa43c15e286ed..d2bcf31cb0551 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -798,12 +798,12 @@ impl<'a> Parser<'a> {
         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.is_fn_front_matter() {
+            self.parse_assoc_fn(at_end, &mut attrs, is_name_required)?
         } 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 {
@@ -819,12 +819,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 ";"
@@ -1034,21 +1028,20 @@ impl<'a> Parser<'a> {
 
         let 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.is_fn_front_matter() {
+            // FOREIGN FUNCTION ITEM
+            self.parse_item_foreign_fn(vis, lo, attrs)
+        } 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(
@@ -1058,32 +1051,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()
         }
     }
 
@@ -1752,6 +1730,29 @@ impl<'a> Parser<'a> {
         Ok(body)
     }
 
+    /// Is the current token unambiguously the start of an `FnHeader`?
+    fn is_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.
+        // This works for `async fn` and similar as `async async` is an invalid
+        // parse and `async fn` is never a valid parse on previous editions.
+        const QUALIFIER: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];
+
+        let check_qual_follow = |this: &mut Self, dist| {
+            this.look_ahead(dist, |t| {
+                // ...qualified and then `fn`, e.g. `const fn`.
+                t.is_keyword(kw::Fn)
+                // Two qualifiers. This is enough.
+                || QUALIFIER.iter().any(|&kw| t.is_keyword(kw))
+            })
+        };
+        self.check_keyword(kw::Fn) // Definitely an `fn`.
+            // `$qual fn` or `$qual $qual`:
+            || QUALIFIER.iter().any(|&kw| self.check_keyword(kw)) && check_qual_follow(self, 1)
+            // `extern ABI fn` or `extern ABI $qual`; skip 1 for the ABI.
+            || self.check_keyword(kw::Extern) && check_qual_follow(self, 2)
+    }
+
     /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
     /// up to and including the `fn` keyword. The formal grammar is:
     ///
@@ -1763,16 +1764,13 @@ impl<'a> Parser<'a> {
     fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
         let constness = self.parse_constness();
         let asyncness = self.parse_asyncness();
+        let unsafety = self.parse_unsafety();
+        let ext = self.parse_extern()?;
+
         if let Async::Yes { span, .. } = asyncness {
             self.ban_async_in_2015(span);
         }
-        let unsafety = self.parse_unsafety();
-        let (constness, unsafety, ext) = if let Const::Yes(_) = constness {
-            (constness, unsafety, Extern::None)
-        } else {
-            let ext = self.parse_extern()?;
-            (Const::No, unsafety, ext)
-        };
+
         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
@@ -1781,6 +1779,7 @@ impl<'a> Parser<'a> {
                 unreachable!()
             }
         }
+
         Ok(FnHeader { constness, unsafety, asyncness, ext })
     }
 
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index e11cdd5dadb72..e97af0dc00c69 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/test/ui/issues/issue-60075.rs b/src/test/ui/issues/issue-60075.rs
index 7d3fc83786e9d..1323f646be893 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 e8ef981f515fc..60eb99b46b79f 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/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index c2b7e69c80d8e..98ff2b6d2e8b3 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -18,9 +18,9 @@ fn main() {
         unsafe fn ft2(); // OK.
         const fn ft3(); //~ ERROR trait fns cannot be declared const
         extern "C" fn ft4(); // OK.
-        /* const */ async unsafe extern "C" fn ft5();
+        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.
+        //~| ERROR trait fns cannot be declared const
     }
 
     struct Y;
@@ -30,10 +30,10 @@ fn main() {
         unsafe fn ft2() {} // OK.
         const fn ft3() {} //~ ERROR trait fns cannot be declared const
         extern "C" fn ft4() {}
-        /* const */ async unsafe extern "C" fn ft5() {}
+        const async unsafe extern "C" fn ft5() {}
         //~^ ERROR trait fns cannot be declared `async`
+        //~| ERROR trait fns 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.
     }
 
     impl Y {
@@ -41,8 +41,7 @@ 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() {} // OK.
     }
 
     extern {
@@ -50,8 +49,6 @@ 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
     }
 }
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index 689bbdd8bab88..1860106b255ab 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -15,13 +15,19 @@ error[E0379]: trait fns cannot be declared const
 LL |         const fn ft3();
    |         ^^^^^ trait fns cannot be const
 
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/fn-header-semantic-fail.rs:21:9
+   |
+LL |         const async unsafe extern "C" fn ft5();
+   |         ^^^^^ trait fns cannot be const
+
 error[E0706]: trait fns cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:21:21
+  --> $DIR/fn-header-semantic-fail.rs:21:9
    |
-LL |         /* const */ async unsafe extern "C" fn ft5();
-   |                     -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     `async` because of this
+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
@@ -43,19 +49,25 @@ error[E0379]: trait fns cannot be declared const
 LL |         const fn ft3() {}
    |         ^^^^^ trait fns cannot be const
 
+error[E0379]: trait fns cannot be declared const
+  --> $DIR/fn-header-semantic-fail.rs:33:9
+   |
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^ trait fns cannot be const
+
 error[E0706]: trait fns cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:33:21
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
-LL |         /* const */ async unsafe extern "C" fn ft5() {}
-   |                     -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     `async` because of this
+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 in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:49:18
+  --> $DIR/fn-header-semantic-fail.rs:48:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -65,7 +77,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:49:19
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -76,7 +88,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:50:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -87,7 +99,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:51:23
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -98,15 +110,15 @@ 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:52: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[E0053]: method `ft1` has an incompatible type for trait
   --> $DIR/fn-header-semantic-fail.rs:28:24
@@ -124,21 +136,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:33: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 15 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 145a208cb249d..0557b9ef6ca23 100644
--- a/src/test/ui/parser/fn-header-syntactic-pass.rs
+++ b/src/test/ui/parser/fn-header-syntactic-pass.rs
@@ -22,8 +22,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 X for Y {
@@ -31,8 +30,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 +38,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 +46,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();
     }
 }

From a833be21626890de406e12f2561d2ffbda4aadb4 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Thu, 30 Jan 2020 13:02:06 +0100
Subject: [PATCH 04/13] parser: fuse free `fn` parsing together.

---
 src/librustc_ast_passes/ast_validation.rs     |  14 +++
 src/librustc_ast_passes/feature_gate.rs       |  12 +-
 src/librustc_parse/parser/item.rs             | 111 ++++--------------
 src/libsyntax/token.rs                        |   8 +-
 src/libsyntax/util/literal.rs                 |   2 +
 src/test/ui/async-await/no-async-const.rs     |   2 +-
 src/test/ui/async-await/no-async-const.stderr |   4 +-
 src/test/ui/async-await/no-const-async.rs     |   3 +-
 src/test/ui/async-await/no-const-async.stderr |  17 ++-
 src/test/ui/async-await/no-unsafe-async.rs    |   2 +-
 .../ui/async-await/no-unsafe-async.stderr     |   4 +-
 .../feature-gate-const_extern_fn.rs           |  14 +--
 .../feature-gate-const_extern_fn.stderr       |  36 +++---
 ...const-extern-fns-dont-need-fn-specifier.rs |   1 -
 ...t-extern-fns-dont-need-fn-specifier.stderr |  12 +-
 .../label/label_break_value_illegal_uses.rs   |   2 +-
 .../label_break_value_illegal_uses.stderr     |   4 +-
 .../parser/extern-crate-unexpected-token.rs   |   2 +-
 .../extern-crate-unexpected-token.stderr      |   4 +-
 .../ui/parser/extern-expected-fn-or-brace.rs  |   5 +-
 .../parser/extern-expected-fn-or-brace.stderr |   6 +-
 src/test/ui/parser/fn-header-semantic-fail.rs |  10 +-
 .../ui/parser/fn-header-semantic-fail.stderr  |  69 +++++++++--
 .../ui/parser/fn-header-syntactic-pass.rs     |   6 +-
 src/test/ui/parser/issue-19398.rs             |   2 +-
 src/test/ui/parser/issue-19398.stderr         |   8 +-
 .../ui/unsafe/unsafe-block-without-braces.rs  |   2 +-
 .../unsafe/unsafe-block-without-braces.stderr |   4 +-
 28 files changed, 181 insertions(+), 185 deletions(-)

diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index e0217de1d3b8d..0bc6179dabf5b 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -1089,6 +1089,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| {
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index cfab54925b161..0b21de4d78b41 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() {
@@ -595,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_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index d2bcf31cb0551..906b82f746b24 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -11,7 +11,7 @@ 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, Extern, IsAuto, PathSegment, StrLit, Unsafe};
+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::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
 use syntax::ast::{FnHeader, ForeignItem, ForeignItemKind, Mutability, Visibility, VisibilityKind};
@@ -96,53 +96,30 @@ impl<'a> Parser<'a> {
             return Ok(Some(item));
         }
 
+        if self.is_fn_front_matter() {
+            // FUNCTION ITEM
+            return self.parse_item_fn(lo, vis, attrs);
+        }
+
         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 header = FnHeader {
-                    unsafety: Unsafe::No,
-                    asyncness: Async::No,
-                    constness: Const::No,
-                    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);
         }
 
-        let constness = self.parse_constness();
-        if let Const::Yes(const_span) = constness {
-            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: Async::No, constness, 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;
@@ -161,21 +138,6 @@ 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
-                let asyncness = self.parse_asyncness(); // `async`
-                let unsafety = self.parse_unsafety(); // `unsafe`?
-                self.expect_keyword(kw::Fn)?; // `fn`
-                self.ban_async_in_2015(async_span);
-                let header =
-                    FnHeader { unsafety, asyncness, constness: Const::No, 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
             let unsafety = self.parse_unsafety();
@@ -195,26 +157,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 header = FnHeader::default();
-            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
-            let unsafety = self.parse_unsafety();
-            // `{` 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 header = FnHeader { unsafety, asyncness: Async::No, constness: Const::No, 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[..])?;
@@ -1662,9 +1604,9 @@ impl<'a> Parser<'a> {
         lo: Span,
         vis: Visibility,
         mut attrs: Vec<Attribute>,
-        header: FnHeader,
     ) -> PResult<'a, Option<P<Item>>> {
         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 = ItemKind::Fn(FnSig { decl, header }, generics, body);
@@ -1730,27 +1672,24 @@ impl<'a> Parser<'a> {
         Ok(body)
     }
 
-    /// Is the current token unambiguously the start of an `FnHeader`?
+    /// Is the current token the start of an `FnHeader` / not a valid parse?
     fn is_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.
-        // This works for `async fn` and similar as `async async` is an invalid
-        // parse and `async fn` is never a valid parse on previous editions.
-        const QUALIFIER: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];
-
-        let check_qual_follow = |this: &mut Self, dist| {
-            this.look_ahead(dist, |t| {
-                // ...qualified and then `fn`, e.g. `const fn`.
-                t.is_keyword(kw::Fn)
-                // Two qualifiers. This is enough.
-                || QUALIFIER.iter().any(|&kw| t.is_keyword(kw))
-            })
-        };
+        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`:
-            || QUALIFIER.iter().any(|&kw| self.check_keyword(kw)) && check_qual_follow(self, 1)
-            // `extern ABI fn` or `extern ABI $qual`; skip 1 for the ABI.
-            || self.check_keyword(kw::Extern) && check_qual_follow(self, 2)
+            || 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,
diff --git a/src/libsyntax/token.rs b/src/libsyntax/token.rs
index 3045f147698a5..862934300e085 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 dd06c25b4de0f..0c611adc06bcf 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/async-await/no-async-const.rs b/src/test/ui/async-await/no-async-const.rs
index 64322990d0a93..963460c118249 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 d5b8b344abe62..e324a77187ab6 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 55b27bd3fa1ac..b3c59734e036f 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 62cd5c45d1950..f6ae0f1447ced 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 1ac1bdffda947..f40154e16f34e 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 bbeb34278490b..2651588d59710 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/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 d39f2c1fe277e..5667d5535274d 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 ed5e0c84a16ae..bd5940a3fd60c 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 1886bfccb4e3e..6f575d055a29b 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 d36b781d292d2..ec415ec9d0211 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/label/label_break_value_illegal_uses.rs b/src/test/ui/label/label_break_value_illegal_uses.rs
index 81cb17743809a..9d4c72410a6d1 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 46b53c65b4817..fd8850dd8dab2 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/parser/extern-crate-unexpected-token.rs b/src/test/ui/parser/extern-crate-unexpected-token.rs
index 58b2fa1afdf31..7687f5e64094b 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 0e745dc582f4b..e9d287ac0e927 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 907de0d8f91d8..1dcea17445e7a 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 0ebe9a0d3ead5..258a2c2680aaf 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 98ff2b6d2e8b3..a05ea277eec20 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -10,8 +10,8 @@ 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`
@@ -21,6 +21,7 @@ fn main() {
         const async unsafe extern "C" fn ft5();
         //~^ ERROR trait fns cannot be declared `async`
         //~| ERROR trait fns cannot be declared const
+        //~| ERROR functions cannot be both `const` and `async`
     }
 
     struct Y;
@@ -34,6 +35,7 @@ fn main() {
         //~^ ERROR trait fns cannot be declared `async`
         //~| ERROR trait fns cannot be declared const
         //~| ERROR method `ft5` has an incompatible type for trait
+        //~| ERROR functions cannot be both `const` and `async`
     }
 
     impl Y {
@@ -41,7 +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.
+        const async unsafe extern "C" fn fi5() {}
+        //~^ ERROR functions cannot be both `const` and `async`
     }
 
     extern {
@@ -50,5 +53,6 @@ fn main() {
         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
+        //~^ 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 1860106b255ab..a9e4a18334767 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -1,3 +1,12 @@
+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]: trait fns cannot be declared `async`
   --> $DIR/fn-header-semantic-fail.rs:17:9
    |
@@ -32,8 +41,17 @@ LL |         const async unsafe extern "C" fn ft5();
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
+error: functions 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]: trait fns cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:28:9
+  --> $DIR/fn-header-semantic-fail.rs:29:9
    |
 LL |         async fn ft1() {}
    |         -----^^^^^^^^^^^^
@@ -44,19 +62,19 @@ LL |         async fn ft1() {}
    = 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
+  --> $DIR/fn-header-semantic-fail.rs:32:9
    |
 LL |         const fn ft3() {}
    |         ^^^^^ trait fns cannot be const
 
 error[E0379]: trait fns cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^ trait fns cannot be const
 
 error[E0706]: trait fns cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:33:9
+  --> $DIR/fn-header-semantic-fail.rs:34:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -66,8 +84,26 @@ LL |         const async unsafe extern "C" fn ft5() {}
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
+error: functions 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:48:18
+  --> $DIR/fn-header-semantic-fail.rs:51:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -77,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:49:19
+  --> $DIR/fn-header-semantic-fail.rs:52:19
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -88,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:50:18
+  --> $DIR/fn-header-semantic-fail.rs:53:18
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -99,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:51:23
+  --> $DIR/fn-header-semantic-fail.rs:54:23
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -110,7 +146,7 @@ LL |         extern "C" fn fe4();
    |         help: remove the qualifiers: `fn`
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:52:42
+  --> $DIR/fn-header-semantic-fail.rs:55:42
    |
 LL |     extern {
    |     ------ in this `extern` block
@@ -120,8 +156,17 @@ 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
@@ -136,7 +181,7 @@ 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:48
+  --> $DIR/fn-header-semantic-fail.rs:34:48
    |
 LL |         const async unsafe extern "C" fn ft5();
    |                                               - type in trait
@@ -150,7 +195,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    = note: expected fn pointer `unsafe extern "C" fn()`
               found fn pointer `unsafe extern "C" fn() -> impl std::future::Future`
 
-error: aborting due to 15 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 0557b9ef6ca23..9e44541993d92 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,8 +11,7 @@ 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();
diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs
index 90221039b4148..2158a2fd6c11c 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 41ec4f3ced4e9..201a6b2d66a7c 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/unsafe/unsafe-block-without-braces.rs b/src/test/ui/unsafe/unsafe-block-without-braces.rs
index a291eb2eed764..4e461161854e6 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 637fdeead362d..13e0c3681fa00 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
 

From b05e9d2b4d8692a9f0932e9098727762bfad6efe Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Fri, 31 Jan 2020 03:20:46 +0100
Subject: [PATCH 05/13] parser: solidify `fn` parsing with `parse_fn`.

---
 src/librustc_parse/parser/item.rs | 53 +++++++++++++++++--------------
 1 file changed, 30 insertions(+), 23 deletions(-)

diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 906b82f746b24..d7ffda28bb767 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1596,6 +1596,11 @@ pub(super) struct ParamCfg {
     pub is_name_required: fn(&token::Token) -> bool,
 }
 
+impl ParamCfg {
+    /// Configuration for a free function in the sense that it is not associated.
+    const FREE: Self = ParamCfg { is_name_required: |_| true };
+}
+
 /// Parsing of functions and methods.
 impl<'a> Parser<'a> {
     /// Parses an item-position function declaration.
@@ -1605,11 +1610,9 @@ impl<'a> Parser<'a> {
         vis: Visibility,
         mut attrs: Vec<Attribute>,
     ) -> PResult<'a, Option<P<Item>>> {
-        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 = ItemKind::Fn(FnSig { decl, header }, generics, body);
+        let (ident, sig, generics, body) =
+            self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
+        let kind = ItemKind::Fn(sig, generics, body);
         self.mk_item_with_info(attrs, lo, vis, (ident, kind, None))
     }
 
@@ -1620,11 +1623,9 @@ impl<'a> Parser<'a> {
         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 (ident, sig, generics, body) =
+            self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
+        let kind = ForeignItemKind::Fn(sig, generics, body);
         let span = lo.to(self.prev_span);
         Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None }))
     }
@@ -1635,10 +1636,25 @@ impl<'a> Parser<'a> {
         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))
+        let cfg = ParamCfg { is_name_required };
+        let (ident, sig, generics, body) = self.parse_fn(at_end, attrs, &cfg)?;
+        Ok((ident, AssocItemKind::Fn(sig, body), generics))
+    }
+
+    /// 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>,
+        cfg: &ParamCfg,
+    ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
+        let header = self.parse_fn_front_matter()?; // `const ... fn`
+        let ident = self.parse_ident()?; // `foo`
+        let mut generics = self.parse_generics()?; // `<'a, T, ...>`
+        let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?; // `(p: u8, ...)`
+        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.
@@ -1722,15 +1738,6 @@ impl<'a> Parser<'a> {
         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))
-    }
-
     /// Parses the parameter list and result type of a function declaration.
     pub(super) fn parse_fn_decl(
         &mut self,

From 04253791952d85a4da5d19d228cbac92e37ee2b9 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Fri, 31 Jan 2020 03:31:12 +0100
Subject: [PATCH 06/13] parser: inline `parse_assoc_fn` and friends.

---
 src/librustc_parse/parser/item.rs | 63 +++++++++++--------------------
 1 file changed, 21 insertions(+), 42 deletions(-)

diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index d7ffda28bb767..8ba957c6b3b52 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -98,7 +98,10 @@ impl<'a> Parser<'a> {
 
         if self.is_fn_front_matter() {
             // FUNCTION ITEM
-            return self.parse_item_fn(lo, vis, attrs);
+            let (ident, sig, generics, body) =
+                self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
+            let kind = ItemKind::Fn(sig, generics, body);
+            return self.mk_item_with_info(attrs, lo, vis, (ident, kind, None));
         }
 
         if self.eat_keyword(kw::Extern) {
@@ -741,7 +744,9 @@ impl<'a> Parser<'a> {
         let (name, kind, generics) = if self.eat_keyword(kw::Type) {
             self.parse_assoc_ty()?
         } else if self.is_fn_front_matter() {
-            self.parse_assoc_fn(at_end, &mut attrs, is_name_required)?
+            let cfg = ParamCfg { is_name_required };
+            let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, &cfg)?;
+            (ident, AssocItemKind::Fn(sig, body), generics)
         } else if let Some(mac) = self.parse_assoc_macro_invoc("associated", Some(&vis), at_end)? {
             (Ident::invalid(), AssocItemKind::Macro(mac), Generics::default())
         } else {
@@ -968,7 +973,7 @@ 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 vis = self.parse_visibility(FollowedByType::No)?;
 
@@ -977,7 +982,19 @@ impl<'a> Parser<'a> {
             self.parse_item_foreign_type(vis, lo, attrs)
         } else if self.is_fn_front_matter() {
             // FOREIGN FUNCTION ITEM
-            self.parse_item_foreign_fn(vis, lo, attrs)
+            let (ident, sig, generics, body) =
+                self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
+            let kind = ForeignItemKind::Fn(sig, generics, body);
+            let span = lo.to(self.prev_span);
+            Ok(P(ast::ForeignItem {
+                ident,
+                attrs,
+                kind,
+                id: DUMMY_NODE_ID,
+                span,
+                vis,
+                tokens: None,
+            }))
         } else if self.is_static_global() {
             // FOREIGN STATIC ITEM
             self.bump(); // `static`
@@ -1603,44 +1620,6 @@ impl ParamCfg {
 
 /// 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>,
-    ) -> PResult<'a, Option<P<Item>>> {
-        let (ident, sig, generics, body) =
-            self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
-        let kind = ItemKind::Fn(sig, 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 (ident, sig, generics, body) =
-            self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
-        let kind = ForeignItemKind::Fn(sig, generics, body);
-        let span = lo.to(self.prev_span);
-        Ok(P(ast::ForeignItem { ident, attrs, kind, id: DUMMY_NODE_ID, span, vis, tokens: None }))
-    }
-
-    fn parse_assoc_fn(
-        &mut self,
-        at_end: &mut bool,
-        attrs: &mut Vec<Attribute>,
-        is_name_required: fn(&token::Token) -> bool,
-    ) -> PResult<'a, (Ident, AssocItemKind, Generics)> {
-        let cfg = ParamCfg { is_name_required };
-        let (ident, sig, generics, body) = self.parse_fn(at_end, attrs, &cfg)?;
-        Ok((ident, AssocItemKind::Fn(sig, body), generics))
-    }
-
     /// Parse a function starting from the front matter (`const ...`) to the body `{ ... }` or `;`.
     fn parse_fn(
         &mut self,

From cdbbc25cc31080e189a98c010a0b39a9074d0c50 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Sat, 1 Feb 2020 10:36:29 +0100
Subject: [PATCH 07/13] parser: move `ban_async_in_2015` to `fn` parsing &
 improve it.

---
 src/librustc_parse/parser/item.rs             | 12 +++++++
 src/librustc_parse/parser/mod.rs              | 13 -------
 .../edition-deny-async-fns-2015.stderr        | 36 +++++++++++++++++++
 3 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 8ba957c6b3b52..a851ec2124f97 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -1717,6 +1717,18 @@ impl<'a> Parser<'a> {
         Ok(FnHeader { constness, unsafety, asyncness, ext })
     }
 
+    /// We are parsing `async fn`. If we are on Rust 2015, emit an error.
+    fn ban_async_in_2015(&self, span: Span) {
+        if span.rust_2015() {
+            let diag = self.diagnostic();
+            struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition")
+                .note("to use `async fn`, switch to Rust 2018")
+                .help("set `edition = \"2018\"` in `Cargo.toml`")
+                .note("for more on editions, read https://doc.rust-lang.org/edition-guide")
+                .emit();
+        }
+    }
+
     /// Parses the parameter list and result type of a function declaration.
     pub(super) fn parse_fn_decl(
         &mut self,
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index 2f2f2f8f176e5..4716d722778a6 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -1273,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/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
index e6859a3cd93a0..4afb0430a7274 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,54 +3,90 @@ 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`
   --> $DIR/edition-deny-async-fns-2015.rs:18:5

From 05e5530577bf43749186fd56195cffb686f0311e Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Mon, 10 Feb 2020 15:24:53 +0100
Subject: [PATCH 08/13] parser: address review comments

---
 src/librustc_hir/print.rs         | 2 +-
 src/librustc_parse/parser/item.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs
index b31b814d67be6..e49f99fb717a3 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 let hir::Constness::Const = constness {
+                if constness == hir::Constness::Const {
                     self.word_nbsp("const");
                 }
 
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index a851ec2124f97..2bae86d1179a1 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -646,7 +646,7 @@ impl<'a> Parser<'a> {
             self.expect_semi()?;
 
             let whole_span = lo.to(self.prev_span);
-            if let IsAuto::Yes = is_auto {
+            if is_auto == IsAuto::Yes {
                 let msg = "trait aliases cannot be `auto`";
                 self.struct_span_err(whole_span, msg).span_label(whole_span, msg).emit();
             }

From 79d139ac7056d0102db605715f354689b0214705 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Mon, 10 Feb 2020 15:35:05 +0100
Subject: [PATCH 09/13] parser: simplify ParamCfg -> ReqName

---
 src/librustc_parse/parser/item.rs | 44 ++++++++++++-------------------
 src/librustc_parse/parser/ty.rs   |  4 +--
 2 files changed, 18 insertions(+), 30 deletions(-)

diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 2bae86d1179a1..d16eb770951e1 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -98,8 +98,7 @@ impl<'a> Parser<'a> {
 
         if self.is_fn_front_matter() {
             // FUNCTION ITEM
-            let (ident, sig, generics, body) =
-                self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
+            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));
         }
@@ -715,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
         })?;
@@ -736,7 +735,7 @@ 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)?;
@@ -744,8 +743,7 @@ impl<'a> Parser<'a> {
         let (name, kind, generics) = if self.eat_keyword(kw::Type) {
             self.parse_assoc_ty()?
         } else if self.is_fn_front_matter() {
-            let cfg = ParamCfg { is_name_required };
-            let (ident, sig, generics, body) = self.parse_fn(at_end, &mut attrs, &cfg)?;
+            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())
@@ -982,8 +980,7 @@ impl<'a> Parser<'a> {
             self.parse_item_foreign_type(vis, lo, attrs)
         } else if self.is_fn_front_matter() {
             // FOREIGN FUNCTION ITEM
-            let (ident, sig, generics, body) =
-                self.parse_fn(&mut false, &mut attrs, &ParamCfg::FREE)?;
+            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 {
@@ -1607,16 +1604,9 @@ 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,
-}
-
-impl ParamCfg {
-    /// Configuration for a free function in the sense that it is not associated.
-    const FREE: Self = ParamCfg { is_name_required: |_| true };
-}
+///
+/// The function decides if, per-parameter `p`, `p` must have a pattern or just a type.
+type ReqName = fn(&token::Token) -> bool;
 
 /// Parsing of functions and methods.
 impl<'a> Parser<'a> {
@@ -1625,12 +1615,12 @@ impl<'a> Parser<'a> {
         &mut self,
         at_end: &mut bool,
         attrs: &mut Vec<Attribute>,
-        cfg: &ParamCfg,
+        req_name: ReqName,
     ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
         let header = self.parse_fn_front_matter()?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
         let mut generics = self.parse_generics()?; // `<'a, T, ...>`
-        let decl = self.parse_fn_decl(cfg, AllowPlus::Yes)?; // `(p: u8, ...)`
+        let decl = self.parse_fn_decl(req_name, AllowPlus::Yes)?; // `(p: u8, ...)`
         generics.where_clause = self.parse_where_clause()?; // `where T: Ord`
         let body = self.parse_fn_body(at_end, attrs)?; // `;` or `{ ... }`.
         Ok((ident, FnSig { header, decl }, generics, body))
@@ -1732,21 +1722,21 @@ impl<'a> Parser<'a> {
     /// 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.
@@ -1766,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()?;
 
@@ -1778,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/ty.rs b/src/librustc_parse/parser/ty.rs
index e74ce622947bf..f56ae65a03d02 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 })))
     }
 

From 3341c940068d60ade54ea343301a810c0bb51153 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 11 Feb 2020 08:19:21 +0100
Subject: [PATCH 10/13] ast_validation: tweak diagnostic output

---
 src/librustc_ast_passes/ast_validation.rs     | 35 ++++++++++++-------
 src/test/ui/async-await/async-trait-fn.rs     |  4 +--
 src/test/ui/async-await/async-trait-fn.stderr |  4 +--
 .../edition-deny-async-fns-2015.rs            |  2 +-
 .../edition-deny-async-fns-2015.stderr        |  2 +-
 .../const-fn-with-const-param.rs              |  2 +-
 .../const-fn-with-const-param.stderr          |  4 +--
 src/test/ui/consts/const-fn-mismatch.rs       |  8 +++--
 src/test/ui/consts/const-fn-mismatch.stderr   |  6 ++--
 src/test/ui/consts/const-fn-not-in-trait.rs   | 10 +++---
 .../ui/consts/const-fn-not-in-trait.stderr    | 10 +++---
 .../ui/feature-gates/feature-gate-const_fn.rs |  6 ++--
 .../feature-gate-const_fn.stderr              | 12 +++----
 .../feature-gate-min_const_fn.rs              |  6 ++--
 .../feature-gate-min_const_fn.stderr          | 12 +++----
 src/test/ui/issues/issue-54954.rs             |  2 +-
 src/test/ui/issues/issue-54954.stderr         |  4 +--
 .../mismatched_types/const-fn-in-trait.stderr |  8 ++---
 src/test/ui/parser/fn-header-semantic-fail.rs | 16 ++++-----
 .../ui/parser/fn-header-semantic-fail.stderr  | 24 ++++++-------
 20 files changed, 96 insertions(+), 81 deletions(-)

diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 0bc6179dabf5b..2f0495b8b5a48 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -223,21 +223,29 @@ impl<'a> AstValidator<'a> {
 
     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, "trait fns 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();
+            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: Const) {
         if let Const::Yes(span) = constness {
-            struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const")
-                .span_label(span, "trait fns cannot be const")
-                .emit();
+            struct_span_err!(
+                self.session,
+                span,
+                E0379,
+                "functions in traits cannot be declared const"
+            )
+            .span_label(span, "functions in traits cannot be const")
+            .emit();
         }
     }
 
@@ -513,8 +521,11 @@ impl<'a> AstValidator<'a> {
             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`")
-                        .span_label(const_span, "`const fn` because of this")
+                        .struct_span_err(
+                            span,
+                            "const parameters are not permitted in const functions",
+                        )
+                        .span_label(const_span, "`const` because of this")
                         .emit();
                 }
             }
diff --git a/src/test/ui/async-await/async-trait-fn.rs b/src/test/ui/async-await/async-trait-fn.rs
index 786100e916da0..f0403b76620c1 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 04f72fb645e28..6080b2815eeb8 100644
--- a/src/test/ui/async-await/async-trait-fn.stderr
+++ b/src/test/ui/async-await/async-trait-fn.stderr
@@ -1,4 +1,4 @@
-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() {}
@@ -9,7 +9,7 @@ LL |     async fn foo() {}
    = 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) {}
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 c85896150c29f..5d2d186137e16 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 4afb0430a7274..f3d982801bb99 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
@@ -88,7 +88,7 @@ LL |             async fn bar() {}
    = 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() {}
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 f36bf3875c349..e9e236be55630 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 68670963f8e5e..ca31d695361f4 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,10 +1,10 @@
-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 {
    |   ^----
    |   |
-   |  _`const fn` because of this
+   |  _`const` because of this
    | |
 LL | |
 LL | |     X
diff --git a/src/test/ui/consts/const-fn-mismatch.rs b/src/test/ui/consts/const-fn-mismatch.rs
index 5bd274fe66b64..d4cfba6460c45 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 03bb7c6e8d6d8..0f4ce010fee00 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 3975c22c56e91..1006d854688a4 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 6821a6c2bc690..12ce3066037d1 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/feature-gates/feature-gate-const_fn.rs b/src/test/ui/feature-gates/feature-gate-const_fn.rs
index f46d1dc13d3f0..691c367aeb859 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 6a44f079bfbb4..843e56301375a 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 669631df2ad17..5a01e053ed038 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 7ab9d748b31f7..56a882e30fc4a 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 9e9f92ed9ace5..3d6355f5c5978 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 d99a5772e8a4c..4967b82216e46 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/mismatched_types/const-fn-in-trait.stderr b/src/test/ui/mismatched_types/const-fn-in-trait.stderr
index ec1f36bf08774..817582df27db1 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/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index a05ea277eec20..c327667f4cdc7 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -14,26 +14,26 @@ fn main() {
     //~^ 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`
-        //~| ERROR trait fns cannot be declared const
+        //~^ 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`
-        //~| ERROR trait fns cannot be declared const
+        //~^ 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
         //~| 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 a9e4a18334767..1142cee9851b0 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -7,7 +7,7 @@ LL |     const async unsafe extern "C" fn ff5() {} // OK.
    |     |     `async` because of this
    |     `const` because of this
 
-error[E0706]: trait fns cannot be declared `async`
+error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/fn-header-semantic-fail.rs:17:9
    |
 LL |         async fn ft1();
@@ -18,19 +18,19 @@ LL |         async fn ft1();
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
-error[E0379]: trait fns cannot be declared const
+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]: trait fns cannot be declared 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();
-   |         ^^^^^ trait fns cannot be const
+   |         ^^^^^ functions in traits cannot be const
 
-error[E0706]: trait fns cannot be declared `async`
+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();
@@ -50,7 +50,7 @@ LL |         const async unsafe extern "C" fn ft5();
    |         |     `async` because of this
    |         `const` because of this
 
-error[E0706]: trait fns cannot be declared `async`
+error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/fn-header-semantic-fail.rs:29:9
    |
 LL |         async fn ft1() {}
@@ -61,19 +61,19 @@ LL |         async fn ft1() {}
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
 
-error[E0379]: trait fns cannot be declared const
+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]: trait fns cannot be declared 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() {}
-   |         ^^^^^ trait fns cannot be const
+   |         ^^^^^ functions in traits cannot be const
 
-error[E0706]: trait fns cannot be declared `async`
+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() {}

From 27f60906aa400aa42bca5346701b7a02fbc1a872 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 11 Feb 2020 08:24:05 +0100
Subject: [PATCH 11/13] rustc_bulltin_macros: tweak span_labels

---
 src/librustc_builtin_macros/test.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs
index a246e11495345..02a0bc00c1169 100644
--- a/src/librustc_builtin_macros/test.rs
+++ b/src/librustc_builtin_macros/test.rs
@@ -377,13 +377,13 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
     if let ast::ItemKind::Fn(ref sig, ref generics, _) = i.kind {
         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")
+                .span_label(span, "`unsafe` because of this")
                 .emit();
             return false;
         }
         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")
+                .span_label(span, "`async` because of this")
                 .emit();
             return false;
         }

From 4ca3bbf0b21c82d50d14aca9b74a4dd919d9087f Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 11 Feb 2020 08:27:50 +0100
Subject: [PATCH 12/13] parser: add test for 'extern crate async'

---
 src/test/ui/parser/extern-crate-async.rs | 12 ++++++++++++
 1 file changed, 12 insertions(+)
 create mode 100644 src/test/ui/parser/extern-crate-async.rs

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 0000000000000..6a54ac7f4a520
--- /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;

From 9828559aad8672bb320517bd0fa1992ce144b848 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 11 Feb 2020 08:40:16 +0100
Subject: [PATCH 13/13] parser: is_fn_front_matter -> check_fn_front_matter

---
 src/librustc_parse/parser/item.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index d16eb770951e1..ccd55c5c08a70 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -96,7 +96,7 @@ impl<'a> Parser<'a> {
             return Ok(Some(item));
         }
 
-        if self.is_fn_front_matter() {
+        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);
@@ -742,7 +742,7 @@ impl<'a> Parser<'a> {
         let defaultness = self.parse_defaultness();
         let (name, kind, generics) = if self.eat_keyword(kw::Type) {
             self.parse_assoc_ty()?
-        } else if self.is_fn_front_matter() {
+        } 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)? {
@@ -978,7 +978,7 @@ impl<'a> Parser<'a> {
         if self.check_keyword(kw::Type) {
             // FOREIGN TYPE ITEM
             self.parse_item_foreign_type(vis, lo, attrs)
-        } else if self.is_fn_front_matter() {
+        } 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);
@@ -1658,7 +1658,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Is the current token the start of an `FnHeader` / not a valid parse?
-    fn is_fn_front_matter(&mut self) -> bool {
+    fn check_fn_front_matter(&mut self) -> bool {
         // We use an over-approximation here.
         // `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
         const QUALS: [Symbol; 4] = [kw::Const, kw::Async, kw::Unsafe, kw::Extern];