@@ -3916,6 +3916,10 @@ impl<'a> Parser<'a> {
3916
3916
self . look_ahead ( 1 , |t| t. is_ident ( ) && !t. is_reserved_ident ( ) )
3917
3917
}
3918
3918
3919
+ fn is_crate_vis ( & self ) -> bool {
3920
+ self . token . is_keyword ( keywords:: Crate ) && self . look_ahead ( 1 , |t| t != & token:: ModSep )
3921
+ }
3922
+
3919
3923
fn eat_auto_trait ( & mut self ) -> bool {
3920
3924
if self . token . is_keyword ( keywords:: Auto )
3921
3925
&& self . look_ahead ( 1 , |t| t. is_keyword ( keywords:: Trait ) )
@@ -4026,10 +4030,15 @@ impl<'a> Parser<'a> {
4026
4030
node : StmtKind :: Item ( macro_def) ,
4027
4031
span : lo. to ( self . prev_span ) ,
4028
4032
}
4029
- // Starts like a simple path, but not a union item.
4033
+ // Starts like a simple path, but not a union item or item with `crate` visibility.
4034
+ // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts
4035
+ // like a path (1 token), but it fact not a path.
4036
+ // `union::b::c` - path, `union U { ... }` - not a path.
4037
+ // `crate::b::c` - path, `crate struct S;` - not a path.
4030
4038
} else if self . token . is_path_start ( ) &&
4031
4039
!self . token . is_qpath_start ( ) &&
4032
- !self . is_union_item ( ) {
4040
+ !self . is_union_item ( ) &&
4041
+ !self . is_crate_vis ( ) {
4033
4042
let pth = self . parse_path ( PathStyle :: Expr ) ?;
4034
4043
4035
4044
if !self . eat ( & token:: Not ) {
@@ -5399,7 +5408,9 @@ impl<'a> Parser<'a> {
5399
5408
pub fn parse_visibility ( & mut self , can_take_tuple : bool ) -> PResult < ' a , Visibility > {
5400
5409
maybe_whole ! ( self , NtVis , |x| x) ;
5401
5410
5402
- if self . eat_keyword ( keywords:: Crate ) {
5411
+ self . expected_tokens . push ( TokenType :: Keyword ( keywords:: Crate ) ) ;
5412
+ if self . is_crate_vis ( ) {
5413
+ self . bump ( ) ; // `crate`
5403
5414
return Ok ( Visibility :: Crate ( self . prev_span , CrateSugar :: JustCrate ) ) ;
5404
5415
}
5405
5416
0 commit comments