Skip to content

Commit f28df20

Browse files
committed
Auto merge of #45771 - petrochenkov:crate, r=nikomatsakis
Support `::crate` in paths cc #45477 Fixes #45229
2 parents ebda766 + 90f5cfd commit f28df20

16 files changed

+187
-49
lines changed

src/librustc_passes/ast_validation.rs

-13
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use rustc::session::Session;
2121
use syntax::ast::*;
2222
use syntax::attr;
2323
use syntax::codemap::Spanned;
24-
use syntax::parse::token;
2524
use syntax::symbol::keywords;
2625
use syntax::visit::{self, Visitor};
2726
use syntax_pos::Span;
@@ -182,18 +181,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
182181
visit::walk_ty(self, ty)
183182
}
184183

185-
fn visit_path(&mut self, path: &'a Path, _: NodeId) {
186-
if path.segments.len() >= 2 && path.is_global() {
187-
let ident = path.segments[1].identifier;
188-
if token::Ident(ident).is_path_segment_keyword() {
189-
self.err_handler()
190-
.span_err(path.span, &format!("global paths cannot start with `{}`", ident));
191-
}
192-
}
193-
194-
visit::walk_path(self, path)
195-
}
196-
197184
fn visit_item(&mut self, item: &'a Item) {
198185
match item.node {
199186
ItemKind::Use(ref view_path) => {

src/librustc_resolve/build_reduced_graph.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl<'a> Resolver<'a> {
114114
// Extract and intern the module part of the path. For
115115
// globs and lists, the path is found directly in the AST;
116116
// for simple paths we have to munge the path a little.
117-
let mut module_path: Vec<_> = match view_path.node {
117+
let module_path: Vec<_> = match view_path.node {
118118
ViewPathSimple(_, ref full_path) => {
119119
full_path.segments
120120
.split_last()
@@ -134,14 +134,6 @@ impl<'a> Resolver<'a> {
134134
}
135135
};
136136

137-
// This can be removed once warning cycle #36888 is complete.
138-
if module_path.len() >= 2 &&
139-
module_path[0].node.name == keywords::CrateRoot.name() &&
140-
token::Ident(module_path[1].node).is_path_segment_keyword()
141-
{
142-
module_path.remove(0);
143-
}
144-
145137
// Build up the import directives.
146138
let is_prelude = attr::contains_name(&item.attrs, "prelude_import");
147139

src/librustc_resolve/lib.rs

+39-9
Original file line numberDiff line numberDiff line change
@@ -2865,12 +2865,13 @@ impl<'a> Resolver<'a> {
28652865
debug!("resolve_path ident {} {:?}", i, ident);
28662866
let is_last = i == path.len() - 1;
28672867
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
2868+
let name = ident.node.name;
28682869

2869-
if i == 0 && ns == TypeNS && ident.node.name == keywords::SelfValue.name() {
2870+
if i == 0 && ns == TypeNS && name == keywords::SelfValue.name() {
28702871
let mut ctxt = ident.node.ctxt.modern();
28712872
module = Some(self.resolve_self(&mut ctxt, self.current_module));
28722873
continue
2873-
} else if allow_super && ns == TypeNS && ident.node.name == keywords::Super.name() {
2874+
} else if allow_super && ns == TypeNS && name == keywords::Super.name() {
28742875
let mut ctxt = ident.node.ctxt.modern();
28752876
let self_module = match i {
28762877
0 => self.resolve_self(&mut ctxt, self.current_module),
@@ -2886,12 +2887,41 @@ impl<'a> Resolver<'a> {
28862887
}
28872888
allow_super = false;
28882889

2889-
if i == 0 && ns == TypeNS && ident.node.name == keywords::CrateRoot.name() {
2890-
module = Some(self.resolve_crate_root(ident.node.ctxt.modern()));
2891-
continue
2892-
} else if i == 0 && ns == TypeNS && ident.node.name == keywords::DollarCrate.name() {
2893-
module = Some(self.resolve_crate_root(ident.node.ctxt));
2894-
continue
2890+
if ns == TypeNS {
2891+
if (i == 0 && name == keywords::CrateRoot.name()) ||
2892+
(i == 1 && name == keywords::Crate.name() &&
2893+
path[0].node.name == keywords::CrateRoot.name()) {
2894+
// `::a::b` or `::crate::a::b`
2895+
module = Some(self.resolve_crate_root(ident.node.ctxt.modern()));
2896+
continue
2897+
} else if i == 0 && name == keywords::DollarCrate.name() {
2898+
// `$crate::a::b`
2899+
module = Some(self.resolve_crate_root(ident.node.ctxt));
2900+
continue
2901+
}
2902+
}
2903+
2904+
// Report special messages for path segment keywords in wrong positions.
2905+
if name == keywords::CrateRoot.name() && i != 0 ||
2906+
name == keywords::DollarCrate.name() && i != 0 ||
2907+
name == keywords::SelfValue.name() && i != 0 ||
2908+
name == keywords::SelfType.name() && i != 0 ||
2909+
name == keywords::Super.name() && i != 0 ||
2910+
name == keywords::Crate.name() && i != 1 &&
2911+
path[0].node.name != keywords::CrateRoot.name() {
2912+
let name_str = if name == keywords::CrateRoot.name() {
2913+
format!("crate root")
2914+
} else {
2915+
format!("`{}`", name)
2916+
};
2917+
let msg = if i == 1 && path[0].node.name == keywords::CrateRoot.name() {
2918+
format!("global paths cannot start with {}", name_str)
2919+
} else if i == 0 && name == keywords::Crate.name() {
2920+
format!("{} can only be used in absolute paths", name_str)
2921+
} else {
2922+
format!("{} in paths can only be used in start position", name_str)
2923+
};
2924+
return PathResult::Failed(ident.span, msg, false);
28952925
}
28962926

28972927
let binding = if let Some(module) = module {
@@ -2942,7 +2972,7 @@ impl<'a> Resolver<'a> {
29422972
let msg = if module.and_then(ModuleData::def) == self.graph_root.def() {
29432973
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
29442974
let mut candidates =
2945-
self.lookup_import_candidates(ident.node.name, TypeNS, is_mod);
2975+
self.lookup_import_candidates(name, TypeNS, is_mod);
29462976
candidates.sort_by_key(|c| (c.path.segments.len(), c.path.to_string()));
29472977
if let Some(candidate) = candidates.get(0) {
29482978
format!("Did you mean `{}`?", candidate.path)

src/librustc_resolve/resolve_imports.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -606,10 +606,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
606606
let module_result = self.resolve_path(&module_path, None, true, span);
607607
let module = match module_result {
608608
PathResult::Module(module) => module,
609-
PathResult::Failed(span, msg, _) => {
609+
PathResult::Failed(span, msg, false) => {
610+
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
611+
return None;
612+
}
613+
PathResult::Failed(span, msg, true) => {
610614
let (mut self_path, mut self_result) = (module_path.clone(), None);
611615
if !self_path.is_empty() &&
612-
!token::Ident(self_path[0].node).is_path_segment_keyword()
616+
!token::Ident(self_path[0].node).is_path_segment_keyword() &&
617+
!(self_path.len() > 1 &&
618+
token::Ident(self_path[1].node).is_path_segment_keyword())
613619
{
614620
self_path[0].node.name = keywords::SelfValue.name();
615621
self_result = Some(self.resolve_path(&self_path, None, false, span));

src/libsyntax/ast.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,15 @@ impl Path {
9696
}
9797
}
9898

99+
// Add starting "crate root" segment to all paths except those that
100+
// already have it or start with `self`, `super`, `Self` or `$crate`.
99101
pub fn default_to_global(mut self) -> Path {
100-
if !self.is_global() &&
101-
!::parse::token::Ident(self.segments[0].identifier).is_path_segment_keyword() {
102-
self.segments.insert(0, PathSegment::crate_root(self.span));
102+
if !self.is_global() {
103+
let ident = self.segments[0].identifier;
104+
if !::parse::token::Ident(ident).is_path_segment_keyword() ||
105+
ident.name == keywords::Crate.name() {
106+
self.segments.insert(0, PathSegment::crate_root(self.span));
107+
}
103108
}
104109
self
105110
}

src/libsyntax/feature_gate.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use syntax_pos::Span;
3333
use errors::{DiagnosticBuilder, Handler, FatalError};
3434
use visit::{self, FnKind, Visitor};
3535
use parse::ParseSess;
36-
use symbol::Symbol;
36+
use symbol::{keywords, Symbol};
3737

3838
use std::env;
3939

@@ -420,6 +420,9 @@ declare_features! (
420420

421421
// #![wasm_import_memory] attribute
422422
(active, wasm_import_memory, "1.22.0", None),
423+
424+
// `crate` in paths
425+
(active, crate_in_paths, "1.23.0", Some(45477)),
423426
);
424427

425428
declare_features! (
@@ -1634,6 +1637,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
16341637
visit::walk_impl_item(self, ii);
16351638
}
16361639

1640+
fn visit_path(&mut self, path: &'a ast::Path, _id: NodeId) {
1641+
for segment in &path.segments {
1642+
if segment.identifier.name == keywords::Crate.name() {
1643+
gate_feature_post!(&self, crate_in_paths, segment.span,
1644+
"`crate` in paths is experimental");
1645+
}
1646+
}
1647+
1648+
visit::walk_path(self, path);
1649+
}
1650+
16371651
fn visit_vis(&mut self, vis: &'a ast::Visibility) {
16381652
if let ast::Visibility::Crate(span, ast::CrateSugar::JustCrate) = *vis {
16391653
gate_feature_post!(&self, crate_visibility_modifier, span,

src/libsyntax/parse/parser.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -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

src/libsyntax/parse/token.rs

+1
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ impl Token {
347347
Some(id) => id.name == keywords::Super.name() ||
348348
id.name == keywords::SelfValue.name() ||
349349
id.name == keywords::SelfType.name() ||
350+
id.name == keywords::Crate.name() ||
350351
id.name == keywords::DollarCrate.name(),
351352
None => false,
352353
}

src/test/compile-fail/dollar-crate-is-keyword-2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ mod a {}
1313
macro_rules! m {
1414
() => {
1515
use a::$crate; //~ ERROR unresolved import `a::$crate`
16-
use a::$crate::b; //~ ERROR unresolved import `a::$crate`
17-
type A = a::$crate; //~ ERROR cannot find type `$crate` in module `a`
16+
use a::$crate::b; //~ ERROR `$crate` in paths can only be used in start position
17+
type A = a::$crate; //~ ERROR `$crate` in paths can only be used in start position
1818
}
1919
}
2020

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(crate_in_paths)]
12+
13+
struct S;
14+
15+
mod m {
16+
fn f() {
17+
let s = crate::S; //~ ERROR `crate` can only be used in absolute paths
18+
}
19+
}
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(crate_in_paths)]
12+
#![feature(crate_visibility_modifier)]
13+
14+
mod m {
15+
pub struct Z;
16+
pub struct S1(crate (::m::Z)); // OK
17+
pub struct S2(::crate ::m::Z); // OK
18+
pub struct S3(crate ::m::Z); //~ ERROR `crate` can only be used in absolute paths
19+
}
20+
21+
fn main() {
22+
crate struct S; // OK (item in statement position)
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct S;
12+
13+
fn main() {
14+
let _ = ::crate::S; //~ ERROR `crate` in paths is experimental
15+
}

src/test/parse-fail/keyword-crate-as-identifier.rs src/test/compile-fail/rfc-2126-crate-paths/keyword-crate-as-identifier.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// compile-flags: -Z parse-only
12-
13-
// This file was auto-generated using 'src/etc/generate-keyword-tests.py crate'
11+
#![feature(crate_in_paths)]
1412

1513
fn main() {
16-
let crate = "foo"; //~ error: expected pattern, found keyword `crate`
14+
let crate = 0; //~ ERROR `crate` can only be used in absolute paths
1715
}

src/test/compile-fail/super-at-top-level.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use super::f; //~ ERROR unresolved import `super` [E0432]
12-
//~^ There are too many initial `super`s.
11+
use super::f; //~ ERROR There are too many initial `super`s
1312

1413
fn main() {
1514
}

src/test/compile-fail/use-super-global-path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ mod foo {
1818

1919
pub fn g() {
2020
use ::super::main; //~ ERROR global paths cannot start with `super`
21-
main();
21+
main(); //~ ERROR cannot find function `main` in this scope
2222
}
2323
}
2424

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(crate_in_paths)]
12+
13+
use crate::m::f;
14+
15+
mod m {
16+
pub fn f() -> u8 { 1 }
17+
pub fn g() -> u8 { 2 }
18+
19+
// OK, visibilities are implicitly absolute like imports
20+
pub(in crate::m) struct S;
21+
}
22+
23+
mod n
24+
{
25+
use crate::m::f;
26+
pub fn check() {
27+
assert_eq!(f(), 1);
28+
assert_eq!(::crate::m::g(), 2);
29+
}
30+
}
31+
32+
fn main() {
33+
assert_eq!(f(), 1);
34+
assert_eq!(::crate::m::g(), 2);
35+
n::check();
36+
}

0 commit comments

Comments
 (0)