@@ -23,7 +23,7 @@ use super::{
2323 AttrWrapper , ExpKeywordPair , ExpTokenPair , FollowedByType , ForceCollect , Parser , PathStyle ,
2424 Recovered , Trailing , UsePreAttrPos ,
2525} ;
26- use crate :: errors:: { self , MacroExpandsToAdtField } ;
26+ use crate :: errors:: { self , FnPointerCannotBeAsync , FnPointerCannotBeConst , MacroExpandsToAdtField } ;
2727use crate :: { exp, fluent_generated as fluent} ;
2828
2929impl < ' a > Parser < ' a > {
@@ -2402,7 +2402,7 @@ impl<'a> Parser<'a> {
24022402 case : Case ,
24032403 ) -> PResult < ' a , ( Ident , FnSig , Generics , Option < P < FnContract > > , Option < P < Block > > ) > {
24042404 let fn_span = self . token . span ;
2405- let header = self . parse_fn_front_matter ( vis, case) ?; // `const ... fn`
2405+ let header = self . parse_fn_front_matter ( vis, case, false ) ?; // `const ... fn`
24062406 let ident = self . parse_ident ( ) ?; // `foo`
24072407 let mut generics = self . parse_generics ( ) ?; // `<'a, T, ...>`
24082408 let decl = match self . parse_fn_decl (
@@ -2658,16 +2658,35 @@ impl<'a> Parser<'a> {
26582658 ///
26592659 /// `vis` represents the visibility that was already parsed, if any. Use
26602660 /// `Visibility::Inherited` when no visibility is known.
2661+ ///
2662+ /// If `is_fn_pointer_type`, we error on `const` and `async` qualifiers,
2663+ /// which are not allowed in function pointer types.
26612664 pub ( super ) fn parse_fn_front_matter (
26622665 & mut self ,
26632666 orig_vis : & Visibility ,
26642667 case : Case ,
2668+ is_fn_pointer_type : bool ,
26652669 ) -> PResult < ' a , FnHeader > {
26662670 let sp_start = self . token . span ;
26672671 let constness = self . parse_constness ( case) ;
2672+ if is_fn_pointer_type && let Const :: Yes ( const_span) = constness {
2673+ self . dcx ( ) . emit_err ( FnPointerCannotBeConst {
2674+ span : const_span,
2675+ suggestion : const_span. until ( self . token . span ) ,
2676+ } ) ;
2677+ }
26682678
26692679 let async_start_sp = self . token . span ;
26702680 let coroutine_kind = self . parse_coroutine_kind ( case) ;
2681+ if is_fn_pointer_type
2682+ && let Some ( ast:: CoroutineKind :: Async { span : async_span, .. } ) = coroutine_kind
2683+ {
2684+ self . dcx ( ) . emit_err ( FnPointerCannotBeAsync {
2685+ span : async_span,
2686+ suggestion : async_span. until ( self . token . span ) ,
2687+ } ) ;
2688+ }
2689+ // FIXME(gen_blocks): emit a similar error for `gen fn()`
26712690
26722691 let unsafe_start_sp = self . token . span ;
26732692 let safety = self . parse_safety ( case) ;
@@ -2703,6 +2722,11 @@ impl<'a> Parser<'a> {
27032722 enum WrongKw {
27042723 Duplicated ( Span ) ,
27052724 Misplaced ( Span ) ,
2725+ /// `MisplacedDisallowedQualifier` is only used instead of `Misplaced`,
2726+ /// when the misplaced keyword is disallowed by `is_fn_pointer_type`.
2727+ /// In this case, we avoid generating the suggestion to swap around the keywords,
2728+ /// as we already generated a suggestion to remove the keyword earlier.
2729+ MisplacedDisallowedQualifier ,
27062730 }
27072731
27082732 // We may be able to recover
@@ -2716,7 +2740,18 @@ impl<'a> Parser<'a> {
27162740 Const :: Yes ( sp) => Some ( WrongKw :: Duplicated ( sp) ) ,
27172741 Const :: No => {
27182742 recover_constness = Const :: Yes ( self . token . span ) ;
2719- Some ( WrongKw :: Misplaced ( async_start_sp) )
2743+ if is_fn_pointer_type {
2744+ self . dcx ( ) . emit_err ( FnPointerCannotBeConst {
2745+ span : self . token . span ,
2746+ suggestion : self
2747+ . token
2748+ . span
2749+ . with_lo ( self . prev_token . span . hi ( ) ) ,
2750+ } ) ;
2751+ Some ( WrongKw :: MisplacedDisallowedQualifier )
2752+ } else {
2753+ Some ( WrongKw :: Misplaced ( async_start_sp) )
2754+ }
27202755 }
27212756 }
27222757 } else if self . check_keyword ( exp ! ( Async ) ) {
@@ -2742,7 +2777,18 @@ impl<'a> Parser<'a> {
27422777 closure_id : DUMMY_NODE_ID ,
27432778 return_impl_trait_id : DUMMY_NODE_ID ,
27442779 } ) ;
2745- Some ( WrongKw :: Misplaced ( unsafe_start_sp) )
2780+ if is_fn_pointer_type {
2781+ self . dcx ( ) . emit_err ( FnPointerCannotBeAsync {
2782+ span : self . token . span ,
2783+ suggestion : self
2784+ . token
2785+ . span
2786+ . with_lo ( self . prev_token . span . hi ( ) ) ,
2787+ } ) ;
2788+ Some ( WrongKw :: MisplacedDisallowedQualifier )
2789+ } else {
2790+ Some ( WrongKw :: Misplaced ( unsafe_start_sp) )
2791+ }
27462792 }
27472793 }
27482794 } else if self . check_keyword ( exp ! ( Unsafe ) ) {
0 commit comments