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

Add extern crate items to extern prelude #54658

Merged
merged 4 commits into from
Oct 25, 2018
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
4 changes: 3 additions & 1 deletion src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,9 @@ pub struct GlobalCtxt<'tcx> {

maybe_unused_trait_imports: FxHashSet<DefId>,
maybe_unused_extern_crates: Vec<(DefId, Span)>,
pub extern_prelude: FxHashSet<ast::Name>,
/// Extern prelude entries. The value is `true` if the entry was introduced
/// via `extern crate` item and not `--extern` option or compiler built-in.
pub extern_prelude: FxHashMap<ast::Name, bool>,

// Internal cache for metadata decoding. No need to track deps on this.
pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/item_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// 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;
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use ty::subst::{Subst, Substs};
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;

Expand Down Expand Up @@ -141,7 +141,9 @@ 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>,
/// Extern prelude entries. The value is `true` if the entry was introduced
/// via `extern crate` item and not `--extern` option or compiler built-in.
pub extern_prelude: FxHashMap<Name, bool>,
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,9 @@ where
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 {
Expand Down
26 changes: 23 additions & 3 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use macros::{InvocationData, ParentScope, LegacyScope};
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};

Expand All @@ -28,6 +28,7 @@ use rustc::middle::cstore::CrateStore;
use rustc_metadata::cstore::LoadedMacro;

use std::cell::Cell;
use std::ptr;
use rustc_data_structures::sync::Lrc;

use syntax::ast::{Name, Ident};
Expand Down Expand Up @@ -437,13 +438,32 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
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) {
if let Some(entry) = self.extern_prelude.get(&ident.modern()) {
if expansion != Mark::root() && orig_name.is_some() &&
entry.extern_crate_item.is_none() {
self.session.span_err(item.span, "macro-expanded `extern crate` items \
cannot shadow names passed with \
`--extern`");
}
}
let entry = self.extern_prelude.entry(ident.modern())
.or_insert(ExternPreludeEntry {
extern_crate_item: None,
introduced_by_item: true,
});
entry.extern_crate_item = Some(binding);
if orig_name.is_some() {
entry.introduced_by_item = true;
}
}
let directive = self.arenas.alloc_import_directive(ImportDirective {
root_id: item.id,
id: item.id,
Expand All @@ -468,7 +488,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {

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);
Expand Down
23 changes: 9 additions & 14 deletions src/librustc_resolve/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
// 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();
Expand All @@ -146,19 +146,14 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
// 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)
}
}

Expand Down
78 changes: 51 additions & 27 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::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::base::MacroKind;
use syntax::feature_gate::{emit_feature_err, GateIssue};
use syntax::symbol::{Symbol, keywords};
use syntax::util::lev_distance::find_best_match_for_name;

Expand Down Expand Up @@ -1340,6 +1341,12 @@ impl PrimitiveTypeTable {
}
}

#[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.
Expand All @@ -1352,7 +1359,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>,
Expand Down Expand Up @@ -1668,15 +1675,16 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
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());
}
}
}
Expand Down Expand Up @@ -1963,21 +1971,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
}

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, false) {
return Some(LexicalScopeBinding::Item(binding));
}
}
if ns == TypeNS && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
Expand Down Expand Up @@ -4018,7 +4015,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
} 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);
}
Expand Down Expand Up @@ -4459,11 +4456,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {

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,
Expand Down Expand Up @@ -4825,6 +4820,35 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
err.emit();
self.name_already_seen.insert(name, span);
}

fn extern_prelude_get(&mut self, ident: Ident, speculative: bool, skip_feature_gate: bool)
-> Option<&'a NameBinding<'a>> {
self.extern_prelude.get(&ident.modern()).cloned().and_then(|entry| {
if let Some(binding) = entry.extern_crate_item {
if !speculative && !skip_feature_gate && entry.introduced_by_item &&
!self.session.features_untracked().extern_crate_item_prelude {
emit_feature_err(&self.session.parse_sess, "extern_crate_item_prelude",
ident.span, GateIssue::Language,
"use of extern prelude names introduced \
with `extern crate` items is unstable");
}
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 {
Expand Down
19 changes: 7 additions & 12 deletions src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -691,19 +691,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
}
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,
innermost_result.is_some()) {
result = Ok((binding, Flags::PRELUDE, Flags::empty()));
}
}
result
}
WhereToResolve::ToolPrelude => {
if use_prelude && is_known_tool(ident.name) {
Expand Down
31 changes: 20 additions & 11 deletions src/librustc_resolve/resolve_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rustc_data_structures::ptr_key::PtrKey;
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;
Expand Down Expand Up @@ -202,7 +202,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
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;
Expand All @@ -220,12 +220,15 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
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, false) {
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);
};
Expand Down Expand Up @@ -738,10 +741,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
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, false)
.map(|binding| binding.def())
} else {
None
};
Expand Down Expand Up @@ -1021,6 +1023,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
Some(this.dummy_binding);
}
}
if record_used && ns == TypeNS {
if let ModuleOrUniformRoot::UniformRoot(..) = module {
// Make sure single-segment import is resolved non-speculatively
// at least once to report the feature error.
this.extern_prelude_get(ident, false, false);
}
}
}
});

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check_unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Loading