Skip to content

Resolve absolute paths as extern under a feature flag #46613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 13, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
@@ -357,6 +357,7 @@ impl CrateStore for DummyCrateStore {
pub trait CrateLoader {
fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
fn postprocess(&mut self, krate: &ast::Crate);
fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum;
}

// This method is used when generating the command line to pass through to
84 changes: 30 additions & 54 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
@@ -71,14 +71,6 @@ fn dump_crates(cstore: &CStore) {
});
}

#[derive(Debug)]
struct ExternCrateInfo {
ident: Symbol,
name: Symbol,
id: ast::NodeId,
dep_kind: DepKind,
}

// Extra info about a crate loaded for plugins or exported macros.
struct ExtensionCrate {
metadata: PMDSource,
@@ -117,34 +109,6 @@ impl<'a> CrateLoader<'a> {
}
}

fn extract_crate_info(&self, i: &ast::Item) -> Option<ExternCrateInfo> {
match i.node {
ast::ItemKind::ExternCrate(ref path_opt) => {
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
i.ident, path_opt);
let name = match *path_opt {
Some(name) => {
validate_crate_name(Some(self.sess), &name.as_str(),
Some(i.span));
name
}
None => i.ident.name,
};
Some(ExternCrateInfo {
ident: i.ident.name,
name,
id: i.id,
dep_kind: if attr::contains_name(&i.attrs, "no_link") {
DepKind::UnexportedMacrosOnly
} else {
DepKind::Explicit
},
})
}
_ => None
}
}

fn existing_match(&self, name: Symbol, hash: Option<&Svh>, kind: PathKind)
-> Option<CrateNum> {
let mut ret = None;
@@ -478,17 +442,17 @@ impl<'a> CrateLoader<'a> {
})).collect()
}

fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate {
info!("read extension crate {} `extern crate {} as {}` dep_kind={:?}",
info.id, info.name, info.ident, info.dep_kind);
fn read_extension_crate(&mut self, span: Span, orig_name: Symbol, rename: Symbol)
-> ExtensionCrate {
info!("read extension crate `extern crate {} as {}`", orig_name, rename);
let target_triple = &self.sess.opts.target_triple[..];
let is_cross = target_triple != config::host_triple();
let mut target_only = false;
let mut locate_ctxt = locator::Context {
sess: self.sess,
span,
ident: info.ident,
crate_name: info.name,
ident: orig_name,
crate_name: rename,
hash: None,
filesearch: self.sess.host_filesearch(PathKind::Crate),
target: &self.sess.host,
@@ -625,12 +589,8 @@ impl<'a> CrateLoader<'a> {
span: Span,
name: &str)
-> Option<(PathBuf, CrateDisambiguator, DefIndex)> {
let ekrate = self.read_extension_crate(span, &ExternCrateInfo {
name: Symbol::intern(name),
ident: Symbol::intern(name),
id: ast::DUMMY_NODE_ID,
dep_kind: DepKind::UnexportedMacrosOnly,
});
let name = Symbol::intern(name);
let ekrate = self.read_extension_crate(span, name, name);

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

fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
match item.node {
ast::ItemKind::ExternCrate(_) => {
let info = self.extract_crate_info(item).unwrap();
ast::ItemKind::ExternCrate(rename) => {
debug!("resolving extern crate stmt. ident: {} rename: {:?}", item.ident, rename);
let rename = match rename {
Some(rename) => {
validate_crate_name(Some(self.sess), &rename.as_str(), Some(item.span));
rename
}
None => item.ident.name,
};
let dep_kind = if attr::contains_name(&item.attrs, "no_link") {
DepKind::UnexportedMacrosOnly
} else {
DepKind::Explicit
};

let (cnum, ..) = self.resolve_crate(
&None, info.ident, info.name, None, item.span, PathKind::Crate, info.dep_kind,
&None, item.ident.name, rename, None, item.span, PathKind::Crate, dep_kind,
);

let def_id = definitions.opt_local_def_id(item.id).unwrap();
let len = definitions.def_path(def_id.index).data.len();
let path_len = definitions.def_path(def_id.index).data.len();

let extern_crate =
ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len };
let extern_crate = ExternCrate { def_id, span: item.span, direct: true, path_len };
self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
self.cstore.add_extern_mod_stmt_cnum(item.id, cnum);
}
_ => {}
}
}

fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum {
self.resolve_crate(&None, name, name, None, span, PathKind::Crate, DepKind::Explicit).0
}
}
11 changes: 11 additions & 0 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
@@ -58,6 +58,7 @@ use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
use syntax::parse::token;

use syntax_pos::{Span, DUMMY_SP, MultiSpan};
use errors::{DiagnosticBuilder, DiagnosticId};
@@ -2959,6 +2960,16 @@ impl<'a> Resolver<'a> {
// `$crate::a::b`
module = Some(self.resolve_crate_root(ident.node.ctxt));
continue
} else if i == 1 && self.session.features.borrow().extern_absolute_paths &&
path[0].node.name == keywords::CrateRoot.name() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: isn't there some helper function we can use here for this test against keywords::CrateRoot.name()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no such existing function.
(Also there are too many "crate roots" with different properties now, it's better to be explicit.)

!token::Ident(ident.node).is_path_segment_keyword() {
// `::extern_crate::a::b`
let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
let crate_root =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(crate_root);
module = Some(crate_root);
continue
}
}

58 changes: 55 additions & 3 deletions src/librustc_resolve/resolve_imports.rs
Original file line number Diff line number Diff line change
@@ -12,14 +12,14 @@ use self::ImportDirectiveSubclass::*;

use {AmbiguityError, Module, PerNS};
use Namespace::{self, TypeNS, MacroNS};
use {NameBinding, NameBindingKind, PathResult, PrivacyError};
use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
use Resolver;
use {names_to_string, module_to_string};
use {resolve_error, ResolutionError};

use rustc::ty;
use rustc::lint::builtin::PUB_USE_OF_PRIVATE_EXTERN_CRATE;
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::def::*;
use rustc::session::DiagnosticMessageId;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
@@ -602,8 +602,60 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
// If appropriate, returns an error to report.
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
self.current_module = directive.parent;

let ImportDirective { ref module_path, span, .. } = *directive;

// Extern crate mode for absolute paths needs some
// special support for single-segment imports.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The part about single-segment imports (use my_crate;/use crate;) works, but it is kinda hacked into.
Solving it properly requires larger refactoring that would also solve a number of pre-existing problems (#29036 and similar).

let extern_absolute_paths = self.session.features.borrow().extern_absolute_paths;
if module_path.len() == 1 && module_path[0].node.name == keywords::CrateRoot.name() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: as above, helper function?

match directive.subclass {
GlobImport { .. } if extern_absolute_paths => {
return Some((directive.span,
"cannot glob-import all possible crates".to_string()));
}
SingleImport { source, target, .. } => {
let crate_root = if source.name == keywords::Crate.name() {
if target.name == keywords::Crate.name() {
return Some((directive.span,
"crate root imports need to be explicitly named: \
`use crate as name;`".to_string()));
} else {
Some(self.resolve_crate_root(source.ctxt.modern()))
}
} else if extern_absolute_paths &&
!token::Ident(source).is_path_segment_keyword() {
let crate_id =
self.crate_loader.resolve_crate_from_path(source.name, directive.span);
let crate_root =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(crate_root);
Some(crate_root)
} else {
None
};

if let Some(crate_root) = crate_root {
let binding = (crate_root, ty::Visibility::Public, directive.span,
directive.expansion).to_name_binding(self.arenas);
let binding = self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Import {
binding,
directive,
used: Cell::new(false),
legacy_self_import: false,
},
vis: directive.vis.get(),
span: directive.span,
expansion: directive.expansion,
});
let _ = self.try_define(directive.parent, target, TypeNS, binding);
return None;
}
}
_ => {}
}
}

let module_result = self.resolve_path(&module_path, None, true, span);
let module = match module_result {
PathResult::Module(module) => module,
3 changes: 3 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -430,6 +430,9 @@ declare_features! (

// generic associated types (RFC 1598)
(active, generic_associated_types, "1.23.0", Some(44265)),

// Resolve absolute paths as paths from other crates
(active, extern_absolute_paths, "1.24.0", Some(44660)),
);

declare_features! (
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[derive(Debug)]
pub struct S;

#[derive(Debug)]
pub struct Z;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(extern_absolute_paths)]

use xcrate::S; //~ ERROR can't find crate for `xcrate`

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(extern_absolute_paths)]

fn main() {
let s = ::xcrate::S; //~ ERROR can't find crate for `xcrate`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(extern_absolute_paths)]

use ycrate; //~ ERROR can't find crate for `ycrate`

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:xcrate.rs

#![feature(crate_in_paths)]
#![feature(extern_absolute_paths)]

use crate; //~ ERROR unresolved import `crate`
//~^ NOTE crate root imports need to be explicitly named: `use crate as name;`
use *; //~ ERROR unresolved import `*`
//~^ NOTE cannot glob-import all possible crates

fn main() {
let s = ::xcrate; //~ ERROR expected value, found module `xcrate`
//~^ NOTE not a value
}
5 changes: 5 additions & 0 deletions src/test/run-pass/rfc-2126-crate-paths/crate-path-absolute.rs
Original file line number Diff line number Diff line change
@@ -11,10 +11,12 @@
#![feature(crate_in_paths)]

use crate::m::f;
use crate as root;

mod m {
pub fn f() -> u8 { 1 }
pub fn g() -> u8 { 2 }
pub fn h() -> u8 { 3 }

// OK, visibilities are implicitly absolute like imports
pub(in crate::m) struct S;
@@ -23,14 +25,17 @@ mod m {
mod n
{
use crate::m::f;
use crate as root;
pub fn check() {
assert_eq!(f(), 1);
assert_eq!(::crate::m::g(), 2);
assert_eq!(root::m::h(), 3);
}
}

fn main() {
assert_eq!(f(), 1);
assert_eq!(::crate::m::g(), 2);
assert_eq!(root::m::h(), 3);
n::check();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[derive(Debug)]
pub struct S;

#[derive(Debug)]
pub struct Z;
31 changes: 31 additions & 0 deletions src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// aux-build:xcrate.rs

#![feature(extern_absolute_paths)]

use xcrate::Z;

fn f() {
use xcrate;
use xcrate as ycrate;
let s = xcrate::S;
assert_eq!(format!("{:?}", s), "S");
let z = ycrate::Z;
assert_eq!(format!("{:?}", z), "Z");
}

fn main() {
let s = ::xcrate::S;
assert_eq!(format!("{:?}", s), "S");
let z = Z;
assert_eq!(format!("{:?}", z), "Z");
}
15 changes: 15 additions & 0 deletions src/test/ui/feature-gate-extern_absolute_paths.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::default; //~ ERROR unresolved import `core`

fn main() {
let _: u8 = ::core::default::Default(); //~ ERROR failed to resolve
}
14 changes: 14 additions & 0 deletions src/test/ui/feature-gate-extern_absolute_paths.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0432]: unresolved import `core`
--> $DIR/feature-gate-extern_absolute_paths.rs:11:5
|
11 | use core::default; //~ ERROR unresolved import `core`
| ^^^^ Maybe a missing `extern crate core;`?

error[E0433]: failed to resolve. Maybe a missing `extern crate core;`?
--> $DIR/feature-gate-extern_absolute_paths.rs:14:19
|
14 | let _: u8 = ::core::default::Default(); //~ ERROR failed to resolve
| ^^^^ Maybe a missing `extern crate core;`?

error: aborting due to 2 previous errors