summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-21 12:32:59 +0000
committerbors <bors@rust-lang.org>2017-11-21 12:32:59 +0000
commitf28df200260c89b2a0bdf942510e0f888c29a70d (patch)
tree731a918787dcc36a4ce994d5a79626d59b61ee13 /src/libsyntax
parentebda7662dbb79ab0a9feb79d367d0818c23ff1dc (diff)
parent90f5cfdfbd3c9e39f897fd2271c7b1c7fdaae58e (diff)
downloadrust-f28df200260c89b2a0bdf942510e0f888c29a70d.tar.gz
rust-f28df200260c89b2a0bdf942510e0f888c29a70d.zip
Auto merge of #45771 - petrochenkov:crate, r=nikomatsakis
Support `::crate` in paths

cc https://github.com/rust-lang/rust/issues/45477
Fixes https://github.com/rust-lang/rust/issues/45229
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs11
-rw-r--r--src/libsyntax/feature_gate.rs16
-rw-r--r--src/libsyntax/parse/parser.rs17
-rw-r--r--src/libsyntax/parse/token.rs1
4 files changed, 38 insertions, 7 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 99dff4edaad..ad9d5865120 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -96,10 +96,15 @@ impl Path {
         }
     }
 
+    // Add starting "crate root" segment to all paths except those that
+    // already have it or start with `self`, `super`, `Self` or `$crate`.
     pub fn default_to_global(mut self) -> Path {
-        if !self.is_global() &&
-           !::parse::token::Ident(self.segments[0].identifier).is_path_segment_keyword() {
-            self.segments.insert(0, PathSegment::crate_root(self.span));
+        if !self.is_global() {
+            let ident = self.segments[0].identifier;
+            if !::parse::token::Ident(ident).is_path_segment_keyword() ||
+               ident.name == keywords::Crate.name() {
+                self.segments.insert(0, PathSegment::crate_root(self.span));
+            }
         }
         self
     }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 5c7450baa2f..036c9414990 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -33,7 +33,7 @@ use syntax_pos::Span;
 use errors::{DiagnosticBuilder, Handler, FatalError};
 use visit::{self, FnKind, Visitor};
 use parse::ParseSess;
-use symbol::Symbol;
+use symbol::{keywords, Symbol};
 
 use std::env;
 
@@ -420,6 +420,9 @@ declare_features! (
 
     // #![wasm_import_memory] attribute
     (active, wasm_import_memory, "1.22.0", None),
+
+    // `crate` in paths
+    (active, crate_in_paths, "1.23.0", Some(45477)),
 );
 
 declare_features! (
@@ -1634,6 +1637,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         visit::walk_impl_item(self, ii);
     }
 
+    fn visit_path(&mut self, path: &'a ast::Path, _id: NodeId) {
+        for segment in &path.segments {
+            if segment.identifier.name == keywords::Crate.name() {
+                gate_feature_post!(&self, crate_in_paths, segment.span,
+                                   "`crate` in paths is experimental");
+            }
+        }
+
+        visit::walk_path(self, path);
+    }
+
     fn visit_vis(&mut self, vis: &'a ast::Visibility) {
         if let ast::Visibility::Crate(span, ast::CrateSugar::JustCrate) = *vis {
             gate_feature_post!(&self, crate_visibility_modifier, span,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c1819307928..0b03429ea2e 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3916,6 +3916,10 @@ impl<'a> Parser<'a> {
         self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
     }
 
+    fn is_crate_vis(&self) -> bool {
+        self.token.is_keyword(keywords::Crate) && self.look_ahead(1, |t| t != &token::ModSep)
+    }
+
     fn eat_auto_trait(&mut self) -> bool {
         if self.token.is_keyword(keywords::Auto)
             && self.look_ahead(1, |t| t.is_keyword(keywords::Trait))
@@ -4026,10 +4030,15 @@ impl<'a> Parser<'a> {
                 node: StmtKind::Item(macro_def),
                 span: lo.to(self.prev_span),
             }
-        // Starts like a simple path, but not a union item.
+        // Starts like a simple path, but not a union item or item with `crate` visibility.
+        // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts
+        // like a path (1 token), but it fact not a path.
+        // `union::b::c` - path, `union U { ... }` - not a path.
+        // `crate::b::c` - path, `crate struct S;` - not a path.
         } else if self.token.is_path_start() &&
                   !self.token.is_qpath_start() &&
-                  !self.is_union_item() {
+                  !self.is_union_item() &&
+                  !self.is_crate_vis() {
             let pth = self.parse_path(PathStyle::Expr)?;
 
             if !self.eat(&token::Not) {
@@ -5399,7 +5408,9 @@ impl<'a> Parser<'a> {
     pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> {
         maybe_whole!(self, NtVis, |x| x);
 
-        if self.eat_keyword(keywords::Crate) {
+        self.expected_tokens.push(TokenType::Keyword(keywords::Crate));
+        if self.is_crate_vis() {
+            self.bump(); // `crate`
             return Ok(Visibility::Crate(self.prev_span, CrateSugar::JustCrate));
         }
 
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index f83343bf9af..ff87f146c0a 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -347,6 +347,7 @@ impl Token {
             Some(id) => id.name == keywords::Super.name() ||
                         id.name == keywords::SelfValue.name() ||
                         id.name == keywords::SelfType.name() ||
+                        id.name == keywords::Crate.name() ||
                         id.name == keywords::DollarCrate.name(),
             None => false,
         }