@@ -798,12 +798,12 @@ impl<'a> Parser<'a> {
798798 let defaultness = self . parse_defaultness ( ) ;
799799 let ( name, kind, generics) = if self . eat_keyword ( kw:: Type ) {
800800 self . parse_assoc_ty ( ) ?
801- } else if self . is_const_item ( ) {
802- self . parse_assoc_const ( ) ?
801+ } else if self . is_fn_front_matter ( ) {
802+ self . parse_assoc_fn ( at_end , & mut attrs , is_name_required ) ?
803803 } else if let Some ( mac) = self . parse_assoc_macro_invoc ( "associated" , Some ( & vis) , at_end) ? {
804804 ( Ident :: invalid ( ) , AssocItemKind :: Macro ( mac) , Generics :: default ( ) )
805805 } else {
806- self . parse_assoc_fn ( at_end , & mut attrs , is_name_required ) ?
806+ self . parse_assoc_const ( ) ?
807807 } ;
808808
809809 Ok ( AssocItem {
@@ -819,12 +819,6 @@ impl<'a> Parser<'a> {
819819 } )
820820 }
821821
822- /// Returns `true` if we are looking at `const ID`
823- /// (returns `false` for things like `const fn`, etc.).
824- fn is_const_item ( & self ) -> bool {
825- self . token . is_keyword ( kw:: Const ) && !self . is_keyword_ahead ( 1 , & [ kw:: Fn , kw:: Unsafe ] )
826- }
827-
828822 /// This parses the grammar:
829823 ///
830824 /// AssocConst = "const" Ident ":" Ty "=" Expr ";"
@@ -1034,21 +1028,20 @@ impl<'a> Parser<'a> {
10341028
10351029 let attrs = self . parse_outer_attributes ( ) ?;
10361030 let lo = self . token . span ;
1037- let visibility = self . parse_visibility ( FollowedByType :: No ) ?;
1031+ let vis = self . parse_visibility ( FollowedByType :: No ) ?;
10381032
1039- // FOREIGN TYPE ITEM
10401033 if self . check_keyword ( kw:: Type ) {
1041- return self . parse_item_foreign_type ( visibility, lo, attrs) ;
1042- }
1043-
1044- // FOREIGN STATIC ITEM
1045- if self . is_static_global ( ) {
1034+ // FOREIGN TYPE ITEM
1035+ self . parse_item_foreign_type ( vis, lo, attrs)
1036+ } else if self . is_fn_front_matter ( ) {
1037+ // FOREIGN FUNCTION ITEM
1038+ self . parse_item_foreign_fn ( vis, lo, attrs)
1039+ } else if self . is_static_global ( ) {
1040+ // FOREIGN STATIC ITEM
10461041 self . bump ( ) ; // `static`
1047- return self . parse_item_foreign_static ( visibility, lo, attrs) ;
1048- }
1049-
1050- // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
1051- if self . is_kw_followed_by_ident ( kw:: Const ) {
1042+ self . parse_item_foreign_static ( vis, lo, attrs)
1043+ } else if self . token . is_keyword ( kw:: Const ) {
1044+ // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
10521045 self . bump ( ) ; // `const`
10531046 self . struct_span_err ( self . prev_span , "extern items cannot be `const`" )
10541047 . span_suggestion (
@@ -1058,32 +1051,17 @@ impl<'a> Parser<'a> {
10581051 Applicability :: MachineApplicable ,
10591052 )
10601053 . emit ( ) ;
1061- return self . parse_item_foreign_static ( visibility, lo, attrs) ;
1062- }
1063-
1064- // FOREIGN FUNCTION ITEM
1065- const MAY_INTRODUCE_FN : & [ Symbol ] = & [ kw:: Const , kw:: Async , kw:: Unsafe , kw:: Extern , kw:: Fn ] ;
1066- if MAY_INTRODUCE_FN . iter ( ) . any ( |& kw| self . check_keyword ( kw) ) {
1067- return self . parse_item_foreign_fn ( visibility, lo, attrs) ;
1068- }
1069-
1070- match self . parse_assoc_macro_invoc ( "extern" , Some ( & visibility) , & mut false ) ? {
1071- Some ( mac) => Ok ( P ( ForeignItem {
1072- ident : Ident :: invalid ( ) ,
1073- span : lo. to ( self . prev_span ) ,
1074- id : DUMMY_NODE_ID ,
1075- attrs,
1076- vis : visibility,
1077- kind : ForeignItemKind :: Macro ( mac) ,
1078- tokens : None ,
1079- } ) ) ,
1080- None => {
1081- if !attrs. is_empty ( ) {
1082- self . expected_item_err ( & attrs) ?;
1083- }
1084-
1085- self . unexpected ( )
1054+ self . parse_item_foreign_static ( vis, lo, attrs)
1055+ } else if let Some ( mac) = self . parse_assoc_macro_invoc ( "extern" , Some ( & vis) , & mut false ) ? {
1056+ let kind = ForeignItemKind :: Macro ( mac) ;
1057+ let span = lo. to ( self . prev_span ) ;
1058+ let ident = Ident :: invalid ( ) ;
1059+ Ok ( P ( ForeignItem { ident, span, id : DUMMY_NODE_ID , attrs, vis, kind, tokens : None } ) )
1060+ } else {
1061+ if !attrs. is_empty ( ) {
1062+ self . expected_item_err ( & attrs) ?;
10861063 }
1064+ self . unexpected ( )
10871065 }
10881066 }
10891067
@@ -1752,6 +1730,29 @@ impl<'a> Parser<'a> {
17521730 Ok ( body)
17531731 }
17541732
1733+ /// Is the current token unambiguously the start of an `FnHeader`?
1734+ fn is_fn_front_matter ( & mut self ) -> bool {
1735+ // We use an over-approximation here.
1736+ // `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
1737+ // This works for `async fn` and similar as `async async` is an invalid
1738+ // parse and `async fn` is never a valid parse on previous editions.
1739+ const QUALIFIER : [ Symbol ; 4 ] = [ kw:: Const , kw:: Async , kw:: Unsafe , kw:: Extern ] ;
1740+
1741+ let check_qual_follow = |this : & mut Self , dist| {
1742+ this. look_ahead ( dist, |t| {
1743+ // ...qualified and then `fn`, e.g. `const fn`.
1744+ t. is_keyword ( kw:: Fn )
1745+ // Two qualifiers. This is enough.
1746+ || QUALIFIER . iter ( ) . any ( |& kw| t. is_keyword ( kw) )
1747+ } )
1748+ } ;
1749+ self . check_keyword ( kw:: Fn ) // Definitely an `fn`.
1750+ // `$qual fn` or `$qual $qual`:
1751+ || QUALIFIER . iter ( ) . any ( |& kw| self . check_keyword ( kw) ) && check_qual_follow ( self , 1 )
1752+ // `extern ABI fn` or `extern ABI $qual`; skip 1 for the ABI.
1753+ || self . check_keyword ( kw:: Extern ) && check_qual_follow ( self , 2 )
1754+ }
1755+
17551756 /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
17561757 /// up to and including the `fn` keyword. The formal grammar is:
17571758 ///
@@ -1763,16 +1764,13 @@ impl<'a> Parser<'a> {
17631764 fn parse_fn_front_matter ( & mut self ) -> PResult < ' a , FnHeader > {
17641765 let constness = self . parse_constness ( ) ;
17651766 let asyncness = self . parse_asyncness ( ) ;
1767+ let unsafety = self . parse_unsafety ( ) ;
1768+ let ext = self . parse_extern ( ) ?;
1769+
17661770 if let Async :: Yes { span, .. } = asyncness {
17671771 self . ban_async_in_2015 ( span) ;
17681772 }
1769- let unsafety = self . parse_unsafety ( ) ;
1770- let ( constness, unsafety, ext) = if let Const :: Yes ( _) = constness {
1771- ( constness, unsafety, Extern :: None )
1772- } else {
1773- let ext = self . parse_extern ( ) ?;
1774- ( Const :: No , unsafety, ext)
1775- } ;
1773+
17761774 if !self . eat_keyword ( kw:: Fn ) {
17771775 // It is possible for `expect_one_of` to recover given the contents of
17781776 // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
@@ -1781,6 +1779,7 @@ impl<'a> Parser<'a> {
17811779 unreachable ! ( )
17821780 }
17831781 }
1782+
17841783 Ok ( FnHeader { constness, unsafety, asyncness, ext } )
17851784 }
17861785
0 commit comments