From 9552b9cfd22b9378bb2a86f8f0738f92c1982d20 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 10 Dec 2017 03:29:35 +0300 Subject: [PATCH 1/2] rustc_metadata: Refactor away `ExternCrateInfo` --- src/librustc_metadata/creader.rs | 80 +++++++++++--------------------- 1 file changed, 26 insertions(+), 54 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 264c15bcd0b76..9ca7f87f79d89 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -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 { - 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 { 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,19 +1058,31 @@ 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); } _ => {} } From b07e26e36e370b95c5fb3db418370d45a064d9ea Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 10 Dec 2017 03:30:47 +0300 Subject: [PATCH 2/2] Resolve absolute paths as extern under a feature flag --- src/librustc/middle/cstore.rs | 1 + src/librustc_metadata/creader.rs | 4 ++ src/librustc_resolve/lib.rs | 11 ++++ src/librustc_resolve/resolve_imports.rs | 58 ++++++++++++++++++- src/libsyntax/feature_gate.rs | 3 + .../auxiliary/xcrate.rs | 15 +++++ .../non-existent-1.rs | 15 +++++ .../non-existent-2.rs | 15 +++++ .../non-existent-3.rs | 15 +++++ .../single-segment.rs | 24 ++++++++ .../crate-path-absolute.rs | 5 ++ .../auxiliary/xcrate.rs | 15 +++++ .../rfc-2126-extern-absolute-paths/basic.rs | 31 ++++++++++ .../ui/feature-gate-extern_absolute_paths.rs | 15 +++++ .../feature-gate-extern_absolute_paths.stderr | 14 +++++ 15 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs create mode 100644 src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs create mode 100644 src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs create mode 100644 src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs create mode 100644 src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs create mode 100644 src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs create mode 100644 src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs create mode 100644 src/test/ui/feature-gate-extern_absolute_paths.rs create mode 100644 src/test/ui/feature-gate-extern_absolute_paths.stderr diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4be23fb711d77..914fb0670b605 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -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 diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 9ca7f87f79d89..58453066cf34b 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1087,4 +1087,8 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { _ => {} } } + + 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 + } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 49c452cddb2cd..ca822faeeac01 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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() && + !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 } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index d4a08d643ab67..2dbcbb364d86c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -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. + let extern_absolute_paths = self.session.features.borrow().extern_absolute_paths; + if module_path.len() == 1 && module_path[0].node.name == keywords::CrateRoot.name() { + 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, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 22cef25320ed3..c7bfb121f801e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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! ( diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs new file mode 100644 index 0000000000000..c3da4a518720d --- /dev/null +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs @@ -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 or the MIT license +// , 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; diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs new file mode 100644 index 0000000000000..14d5d9caa317f --- /dev/null +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-1.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs new file mode 100644 index 0000000000000..defd103f9e457 --- /dev/null +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-2.rs @@ -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 or the MIT license +// , 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` +} diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs new file mode 100644 index 0000000000000..be1708e2b5748 --- /dev/null +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/non-existent-3.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs new file mode 100644 index 0000000000000..e44465750d1dd --- /dev/null +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/run-pass/rfc-2126-crate-paths/crate-path-absolute.rs b/src/test/run-pass/rfc-2126-crate-paths/crate-path-absolute.rs index 172c34e79d233..7003541e86cd3 100644 --- a/src/test/run-pass/rfc-2126-crate-paths/crate-path-absolute.rs +++ b/src/test/run-pass/rfc-2126-crate-paths/crate-path-absolute.rs @@ -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(); } diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs new file mode 100644 index 0000000000000..c3da4a518720d --- /dev/null +++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs @@ -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 or the MIT license +// , 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; diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs new file mode 100644 index 0000000000000..0fa125a3e503e --- /dev/null +++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/basic.rs @@ -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 or the MIT license +// , 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"); +} diff --git a/src/test/ui/feature-gate-extern_absolute_paths.rs b/src/test/ui/feature-gate-extern_absolute_paths.rs new file mode 100644 index 0000000000000..40fdbf0bbdba6 --- /dev/null +++ b/src/test/ui/feature-gate-extern_absolute_paths.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/ui/feature-gate-extern_absolute_paths.stderr b/src/test/ui/feature-gate-extern_absolute_paths.stderr new file mode 100644 index 0000000000000..111cd06cb3c3e --- /dev/null +++ b/src/test/ui/feature-gate-extern_absolute_paths.stderr @@ -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 +