@@ -30,8 +30,8 @@ use rustc_ast::tokenstream::{
30
30
use rustc_ast:: util:: case:: Case ;
31
31
use rustc_ast:: {
32
32
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 ,
35
35
} ;
36
36
use rustc_ast_pretty:: pprust;
37
37
use rustc_data_structures:: fx:: FxHashMap ;
@@ -44,7 +44,9 @@ use token_type::TokenTypeSet;
44
44
pub use token_type:: { ExpKeywordPair , ExpTokenPair , TokenType } ;
45
45
use tracing:: debug;
46
46
47
- use crate :: errors:: { self , IncorrectVisibilityRestriction , NonStringAbiLiteral } ;
47
+ use crate :: errors:: {
48
+ self , IncorrectRestriction , IncorrectVisibilityRestriction , NonStringAbiLiteral ,
49
+ } ;
48
50
use crate :: exp;
49
51
50
52
#[ cfg( test) ]
@@ -1513,6 +1515,80 @@ impl<'a> Parser<'a> {
1513
1515
Ok ( ( ) )
1514
1516
}
1515
1517
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
+
1516
1592
/// Parses `extern string_literal?`.
1517
1593
fn parse_extern ( & mut self , case : Case ) -> Extern {
1518
1594
if self . eat_keyword_case ( exp ! ( Extern ) , case) {
0 commit comments