Add extern crate items to extern prelude

This commit is contained in:
Vadim Petrochenkov 2018-09-29 01:31:54 +03:00
parent f99911a4a0
commit 0f625ac48d
18 changed files with 183 additions and 77 deletions

View File

@ -931,7 +931,7 @@ pub struct GlobalCtxt<'tcx> {
maybe_unused_trait_imports: FxHashSet<DefId>,
maybe_unused_extern_crates: Vec<(DefId, Span)>,
pub extern_prelude: FxHashSet<ast::Name>,
pub extern_prelude: FxHashMap<ast::Name, bool /* introduced by item */>,
// Internal cache for metadata decoding. No need to track deps on this.
pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,

View File

@ -343,7 +343,7 @@ pub fn push_item_path<T>(self, buffer: &mut T, def_id: DefId, pushed_prelude_cra
// printing the `CrateRoot` so we don't prepend a `crate::` to paths.
let mut is_prelude_crate = false;
if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data {
if self.extern_prelude.contains(&data.as_interned_str().as_symbol()) {
if self.extern_prelude.contains_key(&data.as_interned_str().as_symbol()) {
is_prelude_crate = true;
}
}

View File

@ -36,7 +36,7 @@
use ty::util::{IntTypeExt, Discr};
use ty::walk::TypeWalker;
use util::captures::Captures;
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
use arena::SyncDroplessArena;
use session::DataTypeKind;
@ -141,7 +141,7 @@ pub struct Resolutions {
pub maybe_unused_trait_imports: NodeSet,
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
pub export_map: ExportMap,
pub extern_prelude: FxHashSet<Name>,
pub extern_prelude: FxHashMap<Name, bool /* introduced by item */>,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]

View File

@ -790,7 +790,9 @@ pub fn phase_2_configure_and_expand<F>(
trait_map: resolver.trait_map,
maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
extern_prelude: resolver.extern_prelude,
extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
(ident.name, entry.introduced_by_item)
}).collect(),
},
analysis: ty::CrateAnalysis {

View File

@ -17,7 +17,7 @@
use resolve_imports::ImportDirective;
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas};
use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
use Namespace::{self, TypeNS, ValueNS, MacroNS};
use {resolve_error, resolve_struct_error, ResolutionError};
@ -28,6 +28,7 @@
use rustc_metadata::cstore::LoadedMacro;
use std::cell::Cell;
use std::ptr;
use rustc_data_structures::sync::Lrc;
use syntax::ast::{Name, Ident};
@ -437,13 +438,19 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
let module =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(module);
if injected_crate_name().map_or(false, |name| item.ident.name == name) {
if injected_crate_name().map_or(false, |name| ident.name == name) {
self.injected_crate = Some(module);
}
let used = self.process_legacy_macro_imports(item, module, expansion);
let binding =
(module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas);
if ptr::eq(self.current_module, self.graph_root) {
self.extern_prelude.entry(ident.modern()).or_insert(ExternPreludeEntry {
extern_crate_item: None,
introduced_by_item: true,
}).extern_crate_item = Some(binding);
}
let directive = self.arenas.alloc_import_directive(ImportDirective {
root_id: item.id,
id: item.id,
@ -468,7 +475,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
ItemKind::GlobalAsm(..) => {}
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
ItemKind::Mod(..) if ident == keywords::Invalid.ident() => {} // Crate root
ItemKind::Mod(..) => {
let def_id = self.definitions.local_def_id(item.id);

View File

@ -137,7 +137,7 @@ fn make_external_crate_suggestion(
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
// each time.
let external_crate_names: BTreeSet<Symbol> = self.resolver.extern_prelude
.clone().drain().collect();
.iter().map(|(ident, _)| ident.name).collect();
// Insert a new path segment that we can replace.
let new_path_segment = path[0].clone();
@ -146,19 +146,14 @@ fn make_external_crate_suggestion(
// Iterate in reverse so that we start with crates at the end of the alphabet. This means
// that we'll always get `std` before `core`.
for name in external_crate_names.iter().rev() {
let ident = Ident::with_empty_ctxt(*name);
// Calling `maybe_process_path_extern` ensures that we're only running `resolve_path`
// on a crate name that won't ICE.
if let Some(_) = self.crate_loader.maybe_process_path_extern(*name, ident.span) {
// Replace the first after root (a placeholder we inserted) with a crate name
// and check if that is valid.
path[1].name = *name;
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
name, path, result);
if let PathResult::Module(..) = result {
return Some(path)
}
// Replace the first after root (a placeholder we inserted) with a crate name
// and check if that is valid.
path[1].name = *name;
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
name, path, result);
if let PathResult::Module(..) = result {
return Some(path)
}
}

View File

@ -1340,6 +1340,12 @@ fn intern(&mut self, string: &str, primitive_type: PrimTy) {
}
}
#[derive(Default, Clone)]
pub struct ExternPreludeEntry<'a> {
extern_crate_item: Option<&'a NameBinding<'a>>,
pub introduced_by_item: bool,
}
/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
@ -1352,7 +1358,7 @@ pub struct Resolver<'a, 'b: 'a> {
graph_root: Module<'a>,
prelude: Option<Module<'a>>,
pub extern_prelude: FxHashSet<Name>,
pub extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'a>>,
/// n.b. This is used only for better diagnostics, not name resolution itself.
has_self: FxHashSet<DefId>,
@ -1668,15 +1674,16 @@ pub fn new(session: &'a Session,
DefCollector::new(&mut definitions, Mark::root())
.collect_root(crate_name, session.local_crate_disambiguator());
let mut extern_prelude: FxHashSet<Name> =
session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect();
let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry> =
session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default()))
.collect();
if !attr::contains_name(&krate.attrs, "no_core") {
extern_prelude.insert(Symbol::intern("core"));
extern_prelude.insert(Ident::from_str("core"), Default::default());
if !attr::contains_name(&krate.attrs, "no_std") {
extern_prelude.insert(Symbol::intern("std"));
extern_prelude.insert(Ident::from_str("std"), Default::default());
if session.rust_2018() {
extern_prelude.insert(Symbol::intern("meta"));
extern_prelude.insert(Ident::from_str("meta"), Default::default());
}
}
}
@ -1963,21 +1970,10 @@ fn resolve_ident_in_lexical_scope(&mut self,
}
if !module.no_implicit_prelude {
if ns == TypeNS && self.extern_prelude.contains(&ident.name) {
let crate_id = if record_used {
self.crate_loader.process_path_extern(ident.name, ident.span)
} else if let Some(crate_id) =
self.crate_loader.maybe_process_path_extern(ident.name, ident.span) {
crate_id
} else {
return None;
};
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(&crate_root);
let binding = (crate_root, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding));
if ns == TypeNS {
if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
return Some(LexicalScopeBinding::Item(binding));
}
}
if ns == TypeNS && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
@ -4018,7 +4014,7 @@ fn lookup_typo_candidate<FilterFn>(&mut self,
} else {
// Items from the prelude
if !module.no_implicit_prelude {
names.extend(self.extern_prelude.iter().cloned());
names.extend(self.extern_prelude.iter().map(|(ident, _)| ident.name));
if let Some(prelude) = self.prelude {
add_module_candidates(prelude, &mut names);
}
@ -4459,11 +4455,9 @@ fn lookup_import_candidates<FilterFn>(&mut self,
if self.session.rust_2018() {
let extern_prelude_names = self.extern_prelude.clone();
for &name in extern_prelude_names.iter() {
let ident = Ident::with_empty_ctxt(name);
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(name,
ident.span)
{
for (ident, _) in extern_prelude_names.into_iter() {
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
ident.span) {
let crate_root = self.get_module(DefId {
krate: crate_id,
index: CRATE_DEF_INDEX,
@ -4825,6 +4819,28 @@ fn report_conflict<'b>(&mut self,
err.emit();
self.name_already_seen.insert(name, span);
}
fn extern_prelude_get(&mut self, ident: Ident, speculative: bool)
-> Option<&'a NameBinding<'a>> {
self.extern_prelude.get(&ident.modern()).cloned().and_then(|entry| {
if let Some(binding) = entry.extern_crate_item {
Some(binding)
} else {
let crate_id = if !speculative {
self.crate_loader.process_path_extern(ident.name, ident.span)
} else if let Some(crate_id) =
self.crate_loader.maybe_process_path_extern(ident.name, ident.span) {
crate_id
} else {
return None;
};
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(&crate_root);
Some((crate_root, ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas))
}
})
}
}
fn is_self_type(path: &[Ident], namespace: Namespace) -> bool {

View File

@ -691,19 +691,13 @@ struct Flags: u8 {
}
}
WhereToResolve::ExternPrelude => {
if use_prelude && self.extern_prelude.contains(&ident.name) {
let crate_id =
self.crate_loader.process_path_extern(ident.name, ident.span);
let crate_root =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(crate_root);
let binding = (crate_root, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
Ok((binding, Flags::PRELUDE, Flags::empty()))
} else {
Err(Determinacy::Determined)
let mut result = Err(Determinacy::Determined);
if use_prelude {
if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
result = Ok((binding, Flags::PRELUDE, Flags::empty()));
}
}
result
}
WhereToResolve::ToolPrelude => {
if use_prelude && is_known_tool(ident.name) {

View File

@ -21,7 +21,7 @@
use rustc::ty;
use rustc::lint::builtin::BuiltinLintDiagnostics;
use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE};
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::def_id::DefId;
use rustc::hir::def::*;
use rustc::session::DiagnosticMessageId;
use rustc::util::nodemap::FxHashSet;
@ -202,7 +202,7 @@ pub fn resolve_ident_in_module_unadjusted(&mut self,
if !(
ns == TypeNS &&
!ident.is_path_segment_keyword() &&
self.extern_prelude.contains(&ident.name)
self.extern_prelude.contains_key(&ident.modern())
) {
// ... unless the crate name is not in the `extern_prelude`.
return binding;
@ -220,12 +220,15 @@ pub fn resolve_ident_in_module_unadjusted(&mut self,
self.resolve_crate_root(ident)
} else if
ns == TypeNS &&
!ident.is_path_segment_keyword() &&
self.extern_prelude.contains(&ident.name)
!ident.is_path_segment_keyword()
{
let crate_id =
self.crate_loader.process_path_extern(ident.name, ident.span);
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
let module = self.get_module(binding.def().def_id());
self.populate_module_if_necessary(module);
return Ok(binding);
} else {
return Err(Determined);
}
} else {
return Err(Determined);
};
@ -738,10 +741,9 @@ struct UniformPathsCanaryResults<'a> {
let uniform_paths_feature = self.session.features_untracked().uniform_paths;
for ((span, _, ns), results) in uniform_paths_canaries {
let name = results.name;
let external_crate = if ns == TypeNS && self.extern_prelude.contains(&name) {
let crate_id =
self.crate_loader.process_path_extern(name, span);
Some(Def::Mod(DefId { krate: crate_id, index: CRATE_DEF_INDEX }))
let external_crate = if ns == TypeNS {
self.extern_prelude_get(Ident::with_empty_ctxt(name), true)
.map(|binding| binding.def())
} else {
None
};

View File

@ -164,7 +164,7 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
// If the extern crate isn't in the extern prelude,
// there is no way it can be written as an `use`.
let orig_name = extern_crate.orig_name.unwrap_or(item.name);
if !tcx.extern_prelude.contains(&orig_name) {
if !tcx.extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) {
continue;
}

View File

@ -0,0 +1,7 @@
// compile-pass
// edition:2018
extern crate proc_macro;
use proc_macro::TokenStream; // OK
fn main() {}

View File

@ -0,0 +1,16 @@
// compile-pass
// compile-flags:--cfg my_feature
#![no_std]
#[cfg(my_feature)]
extern crate std;
mod m {
#[cfg(my_feature)]
fn conditional() {
std::vec::Vec::<u8>::new(); // OK
}
}
fn main() {}

View File

@ -0,0 +1,13 @@
// aux-build:two_macros.rs
mod n {
extern crate two_macros;
}
mod m {
fn check() {
two_macros::m!(); //~ ERROR failed to resolve. Use of undeclared type or module `two_macros`
}
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0433]: failed to resolve. Use of undeclared type or module `two_macros`
--> $DIR/extern-prelude-extern-crate-fail.rs:9:9
|
LL | two_macros::m!(); //~ ERROR failed to resolve. Use of undeclared type or module `two_macros`
| ^^^^^^^^^^ Use of undeclared type or module `two_macros`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0433`.

View File

@ -0,0 +1,12 @@
// compile-pass
// aux-build:two_macros.rs
extern crate two_macros;
mod m {
fn check() {
two_macros::m!(); // OK
}
}
fn main() {}

View File

@ -0,0 +1,17 @@
// aux-build:two_macros.rs
macro_rules! define_vec {
() => {
extern crate std as Vec;
}
}
define_vec!();
mod m {
fn check() {
Vec::panic!(); //~ ERROR `Vec` is ambiguous
}
}
fn main() {}

View File

@ -0,0 +1,20 @@
error[E0659]: `Vec` is ambiguous
--> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:13:9
|
LL | Vec::panic!(); //~ ERROR `Vec` is ambiguous
| ^^^ ambiguous name
|
note: `Vec` could refer to the name defined here
--> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:5:9
|
LL | extern crate std as Vec;
| ^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | define_vec!();
| -------------- in this macro invocation
note: `Vec` could also refer to the name defined here
= note: macro-expanded items do not shadow when used in a macro invocation path
error: aborting due to previous error
For more information about this error, try `rustc --explain E0659`.

View File

@ -10,10 +10,6 @@ note: `std` could refer to the name imported here
LL | use m2::*; // glob-import user-defined `std`
| ^^^^^
note: `std` could also refer to the name defined here
--> $DIR/macro-path-prelude-shadowing.rs:39:9
|
LL | std::panic!(); //~ ERROR `std` is ambiguous
| ^^^
= note: consider adding an explicit import of `std` to disambiguate
error: aborting due to previous error