Skip to content

Commit 691f022

Browse files
committed
Auto merge of #46613 - petrochenkov:absext, r=nikomatsakis
Resolve absolute paths as extern under a feature flag cc #44660 r? @nikomatsakis
2 parents 442b7bd + b07e26e commit 691f022

File tree

15 files changed

+264
-57
lines changed

15 files changed

+264
-57
lines changed

src/librustc/middle/cstore.rs

+1
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ impl CrateStore for DummyCrateStore {
357357
pub trait CrateLoader {
358358
fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
359359
fn postprocess(&mut self, krate: &ast::Crate);
360+
fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum;
360361
}
361362

362363
// This method is used when generating the command line to pass through to

src/librustc_metadata/creader.rs

+30-54
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,6 @@ fn dump_crates(cstore: &CStore) {
7171
});
7272
}
7373

74-
#[derive(Debug)]
75-
struct ExternCrateInfo {
76-
ident: Symbol,
77-
name: Symbol,
78-
id: ast::NodeId,
79-
dep_kind: DepKind,
80-
}
81-
8274
// Extra info about a crate loaded for plugins or exported macros.
8375
struct ExtensionCrate {
8476
metadata: PMDSource,
@@ -117,34 +109,6 @@ impl<'a> CrateLoader<'a> {
117109
}
118110
}
119111

120-
fn extract_crate_info(&self, i: &ast::Item) -> Option<ExternCrateInfo> {
121-
match i.node {
122-
ast::ItemKind::ExternCrate(ref path_opt) => {
123-
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
124-
i.ident, path_opt);
125-
let name = match *path_opt {
126-
Some(name) => {
127-
validate_crate_name(Some(self.sess), &name.as_str(),
128-
Some(i.span));
129-
name
130-
}
131-
None => i.ident.name,
132-
};
133-
Some(ExternCrateInfo {
134-
ident: i.ident.name,
135-
name,
136-
id: i.id,
137-
dep_kind: if attr::contains_name(&i.attrs, "no_link") {
138-
DepKind::UnexportedMacrosOnly
139-
} else {
140-
DepKind::Explicit
141-
},
142-
})
143-
}
144-
_ => None
145-
}
146-
}
147-
148112
fn existing_match(&self, name: Symbol, hash: Option<&Svh>, kind: PathKind)
149113
-> Option<CrateNum> {
150114
let mut ret = None;
@@ -478,17 +442,17 @@ impl<'a> CrateLoader<'a> {
478442
})).collect()
479443
}
480444

481-
fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate {
482-
info!("read extension crate {} `extern crate {} as {}` dep_kind={:?}",
483-
info.id, info.name, info.ident, info.dep_kind);
445+
fn read_extension_crate(&mut self, span: Span, orig_name: Symbol, rename: Symbol)
446+
-> ExtensionCrate {
447+
info!("read extension crate `extern crate {} as {}`", orig_name, rename);
484448
let target_triple = &self.sess.opts.target_triple[..];
485449
let is_cross = target_triple != config::host_triple();
486450
let mut target_only = false;
487451
let mut locate_ctxt = locator::Context {
488452
sess: self.sess,
489453
span,
490-
ident: info.ident,
491-
crate_name: info.name,
454+
ident: orig_name,
455+
crate_name: rename,
492456
hash: None,
493457
filesearch: self.sess.host_filesearch(PathKind::Crate),
494458
target: &self.sess.host,
@@ -625,12 +589,8 @@ impl<'a> CrateLoader<'a> {
625589
span: Span,
626590
name: &str)
627591
-> Option<(PathBuf, CrateDisambiguator, DefIndex)> {
628-
let ekrate = self.read_extension_crate(span, &ExternCrateInfo {
629-
name: Symbol::intern(name),
630-
ident: Symbol::intern(name),
631-
id: ast::DUMMY_NODE_ID,
632-
dep_kind: DepKind::UnexportedMacrosOnly,
633-
});
592+
let name = Symbol::intern(name);
593+
let ekrate = self.read_extension_crate(span, name, name);
634594

635595
if ekrate.target_only {
636596
// Need to abort before syntax expansion.
@@ -1098,21 +1058,37 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
10981058

10991059
fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
11001060
match item.node {
1101-
ast::ItemKind::ExternCrate(_) => {
1102-
let info = self.extract_crate_info(item).unwrap();
1061+
ast::ItemKind::ExternCrate(rename) => {
1062+
debug!("resolving extern crate stmt. ident: {} rename: {:?}", item.ident, rename);
1063+
let rename = match rename {
1064+
Some(rename) => {
1065+
validate_crate_name(Some(self.sess), &rename.as_str(), Some(item.span));
1066+
rename
1067+
}
1068+
None => item.ident.name,
1069+
};
1070+
let dep_kind = if attr::contains_name(&item.attrs, "no_link") {
1071+
DepKind::UnexportedMacrosOnly
1072+
} else {
1073+
DepKind::Explicit
1074+
};
1075+
11031076
let (cnum, ..) = self.resolve_crate(
1104-
&None, info.ident, info.name, None, item.span, PathKind::Crate, info.dep_kind,
1077+
&None, item.ident.name, rename, None, item.span, PathKind::Crate, dep_kind,
11051078
);
11061079

11071080
let def_id = definitions.opt_local_def_id(item.id).unwrap();
1108-
let len = definitions.def_path(def_id.index).data.len();
1081+
let path_len = definitions.def_path(def_id.index).data.len();
11091082

1110-
let extern_crate =
1111-
ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
1083+
let extern_crate = ExternCrate { def_id, span: item.span, direct: true, path_len };
11121084
self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
1113-
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
1085+
self.cstore.add_extern_mod_stmt_cnum(item.id, cnum);
11141086
}
11151087
_ => {}
11161088
}
11171089
}
1090+
1091+
fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum {
1092+
self.resolve_crate(&None, name, name, None, span, PathKind::Crate, DepKind::Explicit).0
1093+
}
11181094
}

src/librustc_resolve/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
5858
use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
5959
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
6060
use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
61+
use syntax::parse::token;
6162

6263
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
6364
use errors::{DiagnosticBuilder, DiagnosticId};
@@ -2959,6 +2960,16 @@ impl<'a> Resolver<'a> {
29592960
// `$crate::a::b`
29602961
module = Some(self.resolve_crate_root(ident.node.ctxt));
29612962
continue
2963+
} else if i == 1 && self.session.features.borrow().extern_absolute_paths &&
2964+
path[0].node.name == keywords::CrateRoot.name() &&
2965+
!token::Ident(ident.node).is_path_segment_keyword() {
2966+
// `::extern_crate::a::b`
2967+
let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
2968+
let crate_root =
2969+
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
2970+
self.populate_module_if_necessary(crate_root);
2971+
module = Some(crate_root);
2972+
continue
29622973
}
29632974
}
29642975

src/librustc_resolve/resolve_imports.rs

+55-3
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ use self::ImportDirectiveSubclass::*;
1212

1313
use {AmbiguityError, Module, PerNS};
1414
use Namespace::{self, TypeNS, MacroNS};
15-
use {NameBinding, NameBindingKind, PathResult, PrivacyError};
15+
use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
1616
use Resolver;
1717
use {names_to_string, module_to_string};
1818
use {resolve_error, ResolutionError};
1919

2020
use rustc::ty;
2121
use rustc::lint::builtin::PUB_USE_OF_PRIVATE_EXTERN_CRATE;
22-
use rustc::hir::def_id::DefId;
22+
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
2323
use rustc::hir::def::*;
2424
use rustc::session::DiagnosticMessageId;
2525
use rustc::util::nodemap::{FxHashMap, FxHashSet};
@@ -602,8 +602,60 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
602602
// If appropriate, returns an error to report.
603603
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
604604
self.current_module = directive.parent;
605-
606605
let ImportDirective { ref module_path, span, .. } = *directive;
606+
607+
// Extern crate mode for absolute paths needs some
608+
// special support for single-segment imports.
609+
let extern_absolute_paths = self.session.features.borrow().extern_absolute_paths;
610+
if module_path.len() == 1 && module_path[0].node.name == keywords::CrateRoot.name() {
611+
match directive.subclass {
612+
GlobImport { .. } if extern_absolute_paths => {
613+
return Some((directive.span,
614+
"cannot glob-import all possible crates".to_string()));
615+
}
616+
SingleImport { source, target, .. } => {
617+
let crate_root = if source.name == keywords::Crate.name() {
618+
if target.name == keywords::Crate.name() {
619+
return Some((directive.span,
620+
"crate root imports need to be explicitly named: \
621+
`use crate as name;`".to_string()));
622+
} else {
623+
Some(self.resolve_crate_root(source.ctxt.modern()))
624+
}
625+
} else if extern_absolute_paths &&
626+
!token::Ident(source).is_path_segment_keyword() {
627+
let crate_id =
628+
self.crate_loader.resolve_crate_from_path(source.name, directive.span);
629+
let crate_root =
630+
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
631+
self.populate_module_if_necessary(crate_root);
632+
Some(crate_root)
633+
} else {
634+
None
635+
};
636+
637+
if let Some(crate_root) = crate_root {
638+
let binding = (crate_root, ty::Visibility::Public, directive.span,
639+
directive.expansion).to_name_binding(self.arenas);
640+
let binding = self.arenas.alloc_name_binding(NameBinding {
641+
kind: NameBindingKind::Import {
642+
binding,
643+
directive,
644+
used: Cell::new(false),
645+
legacy_self_import: false,
646+
},
647+
vis: directive.vis.get(),
648+
span: directive.span,
649+
expansion: directive.expansion,
650+
});
651+
let _ = self.try_define(directive.parent, target, TypeNS, binding);
652+
return None;
653+
}
654+
}
655+
_ => {}
656+
}
657+
}
658+
607659
let module_result = self.resolve_path(&module_path, None, true, span);
608660
let module = match module_result {
609661
PathResult::Module(module) => module,

src/libsyntax/feature_gate.rs

+3
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ declare_features! (
430430

431431
// generic associated types (RFC 1598)
432432
(active, generic_associated_types, "1.23.0", Some(44265)),
433+
434+
// Resolve absolute paths as paths from other crates
435+
(active, extern_absolute_paths, "1.24.0", Some(44660)),
433436
);
434437

435438
declare_features! (
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+
#[derive(Debug)]
12+
pub struct S;
13+
14+
#[derive(Debug)]
15+
pub struct Z;
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+
#![feature(extern_absolute_paths)]
12+
13+
use xcrate::S; //~ ERROR can't find crate for `xcrate`
14+
15+
fn main() {}
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+
#![feature(extern_absolute_paths)]
12+
13+
fn main() {
14+
let s = ::xcrate::S; //~ ERROR can't find crate for `xcrate`
15+
}
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+
#![feature(extern_absolute_paths)]
12+
13+
use ycrate; //~ ERROR can't find crate for `ycrate`
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
// aux-build:xcrate.rs
12+
13+
#![feature(crate_in_paths)]
14+
#![feature(extern_absolute_paths)]
15+
16+
use crate; //~ ERROR unresolved import `crate`
17+
//~^ NOTE crate root imports need to be explicitly named: `use crate as name;`
18+
use *; //~ ERROR unresolved import `*`
19+
//~^ NOTE cannot glob-import all possible crates
20+
21+
fn main() {
22+
let s = ::xcrate; //~ ERROR expected value, found module `xcrate`
23+
//~^ NOTE not a value
24+
}

src/test/run-pass/rfc-2126-crate-paths/crate-path-absolute.rs

+5
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
#![feature(crate_in_paths)]
1212

1313
use crate::m::f;
14+
use crate as root;
1415

1516
mod m {
1617
pub fn f() -> u8 { 1 }
1718
pub fn g() -> u8 { 2 }
19+
pub fn h() -> u8 { 3 }
1820

1921
// OK, visibilities are implicitly absolute like imports
2022
pub(in crate::m) struct S;
@@ -23,14 +25,17 @@ mod m {
2325
mod n
2426
{
2527
use crate::m::f;
28+
use crate as root;
2629
pub fn check() {
2730
assert_eq!(f(), 1);
2831
assert_eq!(::crate::m::g(), 2);
32+
assert_eq!(root::m::h(), 3);
2933
}
3034
}
3135

3236
fn main() {
3337
assert_eq!(f(), 1);
3438
assert_eq!(::crate::m::g(), 2);
39+
assert_eq!(root::m::h(), 3);
3540
n::check();
3641
}
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+
#[derive(Debug)]
12+
pub struct S;
13+
14+
#[derive(Debug)]
15+
pub struct Z;

0 commit comments

Comments
 (0)