@@ -3916,6 +3916,10 @@ impl<'a> Parser<'a> {
39163916 self . look_ahead ( 1 , |t| t. is_ident ( ) && !t. is_reserved_ident ( ) )
39173917 }
39183918
3919+ fn is_crate_vis ( & self ) -> bool {
3920+ self . token . is_keyword ( keywords:: Crate ) && self . look_ahead ( 1 , |t| t != & token:: ModSep )
3921+ }
3922+
39193923 fn eat_auto_trait ( & mut self ) -> bool {
39203924 if self . token . is_keyword ( keywords:: Auto )
39213925 && self . look_ahead ( 1 , |t| t. is_keyword ( keywords:: Trait ) )
@@ -4026,10 +4030,15 @@ impl<'a> Parser<'a> {
40264030 node : StmtKind :: Item ( macro_def) ,
40274031 span : lo. to ( self . prev_span ) ,
40284032 }
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.
40304038 } else if self . token . is_path_start ( ) &&
40314039 !self . token . is_qpath_start ( ) &&
4032- !self . is_union_item ( ) {
4040+ !self . is_union_item ( ) &&
4041+ !self . is_crate_vis ( ) {
40334042 let pth = self . parse_path ( PathStyle :: Expr ) ?;
40344043
40354044 if !self . eat ( & token:: Not ) {
@@ -5399,7 +5408,9 @@ impl<'a> Parser<'a> {
53995408 pub fn parse_visibility ( & mut self , can_take_tuple : bool ) -> PResult < ' a , Visibility > {
54005409 maybe_whole ! ( self , NtVis , |x| x) ;
54015410
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`
54035414 return Ok ( Visibility :: Crate ( self . prev_span , CrateSugar :: JustCrate ) ) ;
54045415 }
54055416
0 commit comments