@@ -204,6 +204,7 @@ impl<'a> Parser<'a> {
204204 def : & mut Defaultness ,
205205 req_name : ReqName ,
206206 ) -> PResult < ' a , Option < ItemInfo > > {
207+ let def_final = def == & Defaultness :: Final ;
207208 let mut def = || mem:: replace ( def, Defaultness :: Final ) ;
208209
209210 let info = if self . eat_keyword ( kw:: Use ) {
@@ -226,7 +227,7 @@ impl<'a> Parser<'a> {
226227 }
227228
228229 ( Ident :: invalid ( ) , ItemKind :: Use ( tree) )
229- } else if self . check_fn_front_matter ( ) {
230+ } else if self . check_fn_front_matter ( def_final ) {
230231 // FUNCTION ITEM
231232 let ( ident, sig, generics, body) = self . parse_fn ( attrs, req_name, lo) ?;
232233 ( ident, ItemKind :: Fn ( box FnKind ( def ( ) , sig, generics, body) ) )
@@ -1634,18 +1635,27 @@ impl<'a> Parser<'a> {
16341635 }
16351636
16361637 /// Is the current token the start of an `FnHeader` / not a valid parse?
1637- pub ( super ) fn check_fn_front_matter ( & mut self ) -> bool {
1638+ ///
1639+ /// `check_pub` adds additional `pub` to the checks in case users place it
1640+ /// wrongly, can be used to ensure `pub` never comes after `default`.
1641+ pub ( super ) fn check_fn_front_matter ( & mut self , check_pub : bool ) -> bool {
16381642 // We use an over-approximation here.
16391643 // `const const`, `fn const` won't parse, but we're not stepping over other syntax either.
1640- const QUALS : [ Symbol ; 4 ] = [ kw:: Const , kw:: Async , kw:: Unsafe , kw:: Extern ] ;
1644+ // `pub` is added in case users got confused with the ordering like `async pub fn`,
1645+ // only if it wasn't preceeded by `default` as `default pub` is invalid.
1646+ let quals: & [ Symbol ] = if check_pub {
1647+ & [ kw:: Pub , kw:: Const , kw:: Async , kw:: Unsafe , kw:: Extern ]
1648+ } else {
1649+ & [ kw:: Const , kw:: Async , kw:: Unsafe , kw:: Extern ]
1650+ } ;
16411651 self . check_keyword ( kw:: Fn ) // Definitely an `fn`.
16421652 // `$qual fn` or `$qual $qual`:
1643- || QUALS . iter ( ) . any ( |& kw| self . check_keyword ( kw) )
1653+ || quals . iter ( ) . any ( |& kw| self . check_keyword ( kw) )
16441654 && self . look_ahead ( 1 , |t| {
16451655 // `$qual fn`, e.g. `const fn` or `async fn`.
16461656 t. is_keyword ( kw:: Fn )
16471657 // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`.
1648- || t. is_non_raw_ident_where ( |i| QUALS . contains ( & i. name )
1658+ || t. is_non_raw_ident_where ( |i| quals . contains ( & i. name )
16491659 // Rule out 2015 `const async: T = val`.
16501660 && i. is_reserved ( )
16511661 // Rule out unsafe extern block.
@@ -1666,6 +1676,7 @@ impl<'a> Parser<'a> {
16661676 /// FnFrontMatter = FnQual "fn" ;
16671677 /// ```
16681678 pub ( super ) fn parse_fn_front_matter ( & mut self ) -> PResult < ' a , FnHeader > {
1679+ let sp_start = self . token . span ;
16691680 let constness = self . parse_constness ( ) ;
16701681 let asyncness = self . parse_asyncness ( ) ;
16711682 let unsafety = self . parse_unsafety ( ) ;
@@ -1679,8 +1690,27 @@ impl<'a> Parser<'a> {
16791690 // It is possible for `expect_one_of` to recover given the contents of
16801691 // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
16811692 // account for this.
1682- if !self . expect_one_of ( & [ ] , & [ ] ) ? {
1683- unreachable ! ( )
1693+ match self . expect_one_of ( & [ ] , & [ ] ) {
1694+ Ok ( true ) => { }
1695+ Ok ( false ) => unreachable ! ( ) ,
1696+ Err ( mut err) => {
1697+ // Recover incorrect visibility order such as `async pub`.
1698+ if self . check_keyword ( kw:: Pub ) {
1699+ let sp = sp_start. to ( self . prev_token . span ) ;
1700+ if let Ok ( snippet) = self . span_to_snippet ( sp) {
1701+ let vis = self . parse_visibility ( FollowedByType :: No ) ?;
1702+ let vs = pprust:: vis_to_string ( & vis) ;
1703+ let vs = vs. trim_end ( ) ;
1704+ err. span_suggestion (
1705+ sp_start. to ( self . prev_token . span ) ,
1706+ & format ! ( "visibility `{}` must come before `{}`" , vs, snippet) ,
1707+ format ! ( "{} {}" , vs, snippet) ,
1708+ Applicability :: MachineApplicable ,
1709+ ) ;
1710+ }
1711+ }
1712+ return Err ( err) ;
1713+ }
16841714 }
16851715 }
16861716
0 commit comments