@@ -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, FrontMatterParsingMode :: Function ) ?; // `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,37 @@ 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 `parsing_mode` is `FrontMatterParsingMode::FunctionPtrType`, 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+ parsing_mode : FrontMatterParsingMode ,
26652669 ) -> PResult < ' a , FnHeader > {
26662670 let sp_start = self . token . span ;
26672671 let constness = self . parse_constness ( case) ;
2672+ if parsing_mode == FrontMatterParsingMode :: FunctionPtrType
2673+ && let Const :: Yes ( const_span) = constness
2674+ {
2675+ self . dcx ( ) . emit_err ( FnPointerCannotBeConst {
2676+ span : const_span,
2677+ suggestion : const_span. until ( self . token . span ) ,
2678+ } ) ;
2679+ }
26682680
26692681 let async_start_sp = self . token . span ;
26702682 let coroutine_kind = self . parse_coroutine_kind ( case) ;
2683+ if parsing_mode == FrontMatterParsingMode :: FunctionPtrType
2684+ && let Some ( ast:: CoroutineKind :: Async { span : async_span, .. } ) = coroutine_kind
2685+ {
2686+ self . dcx ( ) . emit_err ( FnPointerCannotBeAsync {
2687+ span : async_span,
2688+ suggestion : async_span. until ( self . token . span ) ,
2689+ } ) ;
2690+ }
2691+ // FIXME(gen_blocks): emit a similar error for `gen fn()`
26712692
26722693 let unsafe_start_sp = self . token . span ;
26732694 let safety = self . parse_safety ( case) ;
@@ -2703,6 +2724,11 @@ impl<'a> Parser<'a> {
27032724 enum WrongKw {
27042725 Duplicated ( Span ) ,
27052726 Misplaced ( Span ) ,
2727+ /// `MisplacedDisallowedQualifier` is only used instead of `Misplaced`,
2728+ /// when the misplaced keyword is disallowed by the current `FrontMatterParsingMode`.
2729+ /// In this case, we avoid generating the suggestion to swap around the keywords,
2730+ /// as we already generated a suggestion to remove the keyword earlier.
2731+ MisplacedDisallowedQualifier ,
27062732 }
27072733
27082734 // We may be able to recover
@@ -2716,7 +2742,21 @@ impl<'a> Parser<'a> {
27162742 Const :: Yes ( sp) => Some ( WrongKw :: Duplicated ( sp) ) ,
27172743 Const :: No => {
27182744 recover_constness = Const :: Yes ( self . token . span ) ;
2719- Some ( WrongKw :: Misplaced ( async_start_sp) )
2745+ match parsing_mode {
2746+ FrontMatterParsingMode :: Function => {
2747+ Some ( WrongKw :: Misplaced ( async_start_sp) )
2748+ }
2749+ FrontMatterParsingMode :: FunctionPtrType => {
2750+ self . dcx ( ) . emit_err ( FnPointerCannotBeConst {
2751+ span : self . token . span ,
2752+ suggestion : self
2753+ . token
2754+ . span
2755+ . with_lo ( self . prev_token . span . hi ( ) ) ,
2756+ } ) ;
2757+ Some ( WrongKw :: MisplacedDisallowedQualifier )
2758+ }
2759+ }
27202760 }
27212761 }
27222762 } else if self . check_keyword ( exp ! ( Async ) ) {
@@ -2742,7 +2782,21 @@ impl<'a> Parser<'a> {
27422782 closure_id : DUMMY_NODE_ID ,
27432783 return_impl_trait_id : DUMMY_NODE_ID ,
27442784 } ) ;
2745- Some ( WrongKw :: Misplaced ( unsafe_start_sp) )
2785+ match parsing_mode {
2786+ FrontMatterParsingMode :: Function => {
2787+ Some ( WrongKw :: Misplaced ( async_start_sp) )
2788+ }
2789+ FrontMatterParsingMode :: FunctionPtrType => {
2790+ self . dcx ( ) . emit_err ( FnPointerCannotBeAsync {
2791+ span : self . token . span ,
2792+ suggestion : self
2793+ . token
2794+ . span
2795+ . with_lo ( self . prev_token . span . hi ( ) ) ,
2796+ } ) ;
2797+ Some ( WrongKw :: MisplacedDisallowedQualifier )
2798+ }
2799+ }
27462800 }
27472801 }
27482802 } else if self . check_keyword ( exp ! ( Unsafe ) ) {
@@ -2840,14 +2894,20 @@ impl<'a> Parser<'a> {
28402894
28412895 // FIXME(gen_blocks): add keyword recovery logic for genness
28422896
2843- if wrong_kw . is_some ( )
2897+ if let Some ( wrong_kw ) = wrong_kw
28442898 && self . may_recover ( )
28452899 && self . look_ahead ( 1 , |tok| tok. is_keyword_case ( kw:: Fn , case) )
28462900 {
28472901 // Advance past the misplaced keyword and `fn`
28482902 self . bump ( ) ;
28492903 self . bump ( ) ;
2850- err. emit ( ) ;
2904+ // When we recover from a `MisplacedDisallowedQualifier`, we already emitted an error for the disallowed qualifier
2905+ // So we don't emit another error that the qualifier is unexpected.
2906+ if matches ! ( wrong_kw, WrongKw :: MisplacedDisallowedQualifier ) {
2907+ err. cancel ( ) ;
2908+ } else {
2909+ err. emit ( ) ;
2910+ }
28512911 return Ok ( FnHeader {
28522912 constness : recover_constness,
28532913 safety : recover_safety,
@@ -3194,3 +3254,12 @@ enum IsMacroRulesItem {
31943254 Yes { has_bang : bool } ,
31953255 No ,
31963256}
3257+
3258+ #[ derive( Copy , Clone , PartialEq , Eq ) ]
3259+ pub ( super ) enum FrontMatterParsingMode {
3260+ /// Parse the front matter of a function declaration
3261+ Function ,
3262+ /// Parse the front matter of a function pointet type.
3263+ /// For function pointer types, the `const` and `async` keywords are not permitted.
3264+ FunctionPtrType ,
3265+ }
0 commit comments