Skip to content
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

Resolve absolute paths as extern under a feature flag #46613

Merged
merged 2 commits into from
Dec 13, 2017
Merged
Show file tree
Hide file tree
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
Expand Up @@ -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
Expand Down
84 changes: 30 additions & 54 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Up @@ -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};
Expand Down Expand Up @@ -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
}
}

Expand Down
58 changes: 55 additions & 3 deletions src/librustc_resolve/resolve_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! (
Expand Down
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
Expand Up @@ -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;
Expand All @@ -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;
Loading