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