@@ -30,8 +30,8 @@ use rustc_ast::tokenstream::{
3030use rustc_ast:: util:: case:: Case ;
3131use rustc_ast:: {
3232 self as ast, AnonConst , AttrArgs , AttrId , ByRef , Const , CoroutineKind , DUMMY_NODE_ID ,
33- DelimArgs , Expr , ExprKind , Extern , HasAttrs , HasTokens , Mutability , Recovered , Safety , StrLit ,
34- Visibility , VisibilityKind ,
33+ DelimArgs , Expr , ExprKind , Extern , HasAttrs , HasTokens , Mutability , Recovered , Restriction ,
34+ Safety , StrLit , Visibility , VisibilityKind ,
3535} ;
3636use rustc_ast_pretty:: pprust;
3737use rustc_data_structures:: fx:: FxHashMap ;
@@ -44,7 +44,9 @@ use token_type::TokenTypeSet;
4444pub use token_type:: { ExpKeywordPair , ExpTokenPair , TokenType } ;
4545use tracing:: debug;
4646
47- use crate :: errors:: { self , IncorrectVisibilityRestriction , NonStringAbiLiteral } ;
47+ use crate :: errors:: {
48+ self , IncorrectRestriction , IncorrectVisibilityRestriction , NonStringAbiLiteral ,
49+ } ;
4850use crate :: exp;
4951
5052#[ cfg( test) ]
@@ -1513,6 +1515,80 @@ impl<'a> Parser<'a> {
15131515 Ok ( ( ) )
15141516 }
15151517
1518+ /// Parses `kw`, `kw(in path)` plus shortcuts `kw(crate)` for `kw(in crate)`, `kw(self)` for
1519+ /// `kw(in self)` and `kw(super)` for `kw(in super)`.
1520+ fn parse_restriction (
1521+ & mut self ,
1522+ kw : ExpKeywordPair ,
1523+ action : & ' static str ,
1524+ description : & ' static str ,
1525+ fbt : FollowedByType ,
1526+ ) -> PResult < ' a , Restriction > {
1527+ if !self . eat_keyword ( kw) {
1528+ // We need a span, but there's inherently no keyword to grab a span from for an implied
1529+ // restriction. An empty span at the beginning of the current token is a reasonable
1530+ // fallback.
1531+ return Ok ( Restriction :: implied ( ) . with_span ( self . token . span . shrink_to_lo ( ) ) ) ;
1532+ }
1533+
1534+ let lo = self . prev_token . span ;
1535+
1536+ if self . check ( exp ! ( OpenParen ) ) {
1537+ // We don't `self.bump()` the `(` yet because this might be a struct definition where
1538+ // `()` or a tuple might be allowed. For example, `struct Struct(kw (), kw (usize));`.
1539+ // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
1540+ // by the following tokens.
1541+ if self . is_keyword_ahead ( 1 , & [ kw:: In ] ) {
1542+ // Parse `kw(in path)`.
1543+ self . bump ( ) ; // `(`
1544+ self . bump ( ) ; // `in`
1545+ let path = self . parse_path ( PathStyle :: Mod ) ?; // `path`
1546+ self . expect ( exp ! ( CloseParen ) ) ?; // `)`
1547+ return Ok ( Restriction :: restricted ( P ( path) , ast:: DUMMY_NODE_ID , false )
1548+ . with_span ( lo. to ( self . prev_token . span ) ) ) ;
1549+ } else if self . look_ahead ( 2 , |t| t == & TokenKind :: CloseParen )
1550+ && self . is_keyword_ahead ( 1 , & [ kw:: Crate , kw:: Super , kw:: SelfLower ] )
1551+ {
1552+ // Parse `kw(crate)`, `kw(self)`, or `kw(super)`.
1553+ self . bump ( ) ; // `(`
1554+ let path = self . parse_path ( PathStyle :: Mod ) ?; // `crate`/`super`/`self`
1555+ self . expect ( exp ! ( CloseParen ) ) ?; // `)`
1556+ return Ok ( Restriction :: restricted ( P ( path) , ast:: DUMMY_NODE_ID , false )
1557+ . with_span ( lo. to ( self . prev_token . span ) ) ) ;
1558+ } else if let FollowedByType :: No = fbt {
1559+ // Provide this diagnostic if a type cannot follow;
1560+ // in particular, if this is not a tuple struct.
1561+ self . recover_incorrect_restriction ( kw. kw . as_str ( ) , action, description) ?;
1562+ // Emit diagnostic, but continue unrestricted.
1563+ }
1564+ }
1565+
1566+ Ok ( Restriction :: unrestricted ( ) . with_span ( lo) )
1567+ }
1568+
1569+ /// Recovery for e.g. `kw(something) fn ...` or `struct X { kw(something) y: Z }`
1570+ fn recover_incorrect_restriction < ' kw > (
1571+ & mut self ,
1572+ kw : & ' kw str ,
1573+ action : & ' static str ,
1574+ description : & ' static str ,
1575+ ) -> PResult < ' a , ( ) > {
1576+ self . bump ( ) ; // `(`
1577+ let path = self . parse_path ( PathStyle :: Mod ) ?;
1578+ self . expect ( exp ! ( CloseParen ) ) ?; // `)`
1579+
1580+ let path_str = pprust:: path_to_string ( & path) ;
1581+ self . dcx ( ) . emit_err ( IncorrectRestriction {
1582+ span : path. span ,
1583+ inner_str : path_str,
1584+ keyword : kw,
1585+ adjective : action,
1586+ noun : description,
1587+ } ) ;
1588+
1589+ Ok ( ( ) )
1590+ }
1591+
15161592 /// Parses `extern string_literal?`.
15171593 fn parse_extern ( & mut self , case : Case ) -> Extern {
15181594 if self . eat_keyword_case ( exp ! ( Extern ) , case) {
0 commit comments