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