@@ -204,6 +204,7 @@ impl<'a> Parser<'a> {
204
204
def : & mut Defaultness ,
205
205
req_name : ReqName ,
206
206
) -> PResult < ' a , Option < ItemInfo > > {
207
+ let def_final = def == & Defaultness :: Final ;
207
208
let mut def = || mem:: replace ( def, Defaultness :: Final ) ;
208
209
209
210
let info = if self . eat_keyword ( kw:: Use ) {
@@ -226,7 +227,7 @@ impl<'a> Parser<'a> {
226
227
}
227
228
228
229
( Ident :: invalid ( ) , ItemKind :: Use ( tree) )
229
- } else if self . check_fn_front_matter ( ) {
230
+ } else if self . check_fn_front_matter ( def_final ) {
230
231
// FUNCTION ITEM
231
232
let ( ident, sig, generics, body) = self . parse_fn ( attrs, req_name, lo) ?;
232
233
( ident, ItemKind :: Fn ( box FnKind ( def ( ) , sig, generics, body) ) )
@@ -1634,18 +1635,27 @@ impl<'a> Parser<'a> {
1634
1635
}
1635
1636
1636
1637
/// 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 {
1638
1642
// We use an over-approximation here.
1639
1643
// `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
+ } ;
1641
1651
self . check_keyword ( kw:: Fn ) // Definitely an `fn`.
1642
1652
// `$qual fn` or `$qual $qual`:
1643
- || QUALS . iter ( ) . any ( |& kw| self . check_keyword ( kw) )
1653
+ || quals . iter ( ) . any ( |& kw| self . check_keyword ( kw) )
1644
1654
&& self . look_ahead ( 1 , |t| {
1645
1655
// `$qual fn`, e.g. `const fn` or `async fn`.
1646
1656
t. is_keyword ( kw:: Fn )
1647
1657
// 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 )
1649
1659
// Rule out 2015 `const async: T = val`.
1650
1660
&& i. is_reserved ( )
1651
1661
// Rule out unsafe extern block.
@@ -1666,6 +1676,7 @@ impl<'a> Parser<'a> {
1666
1676
/// FnFrontMatter = FnQual "fn" ;
1667
1677
/// ```
1668
1678
pub ( super ) fn parse_fn_front_matter ( & mut self ) -> PResult < ' a , FnHeader > {
1679
+ let sp_start = self . token . span ;
1669
1680
let constness = self . parse_constness ( ) ;
1670
1681
let asyncness = self . parse_asyncness ( ) ;
1671
1682
let unsafety = self . parse_unsafety ( ) ;
@@ -1679,8 +1690,27 @@ impl<'a> Parser<'a> {
1679
1690
// It is possible for `expect_one_of` to recover given the contents of
1680
1691
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
1681
1692
// 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
+ }
1684
1714
}
1685
1715
}
1686
1716
0 commit comments