Skip to content

Commit 365b900

Browse files
committed
Auto merge of #54658 - petrochenkov:experelude, r=nikomatsakis
Add `extern crate` items to extern prelude With this patch each `extern crate orig_name as name` item adds name `name` into the extern prelude, as if it was passed with `--extern`. What changes this causes in practice? Almost none! After all, `--extern` passed from Cargo was supposed to replace `extern crate` items in source, so if some code has `extern crate` item (or had it on 2015 edition), then it most likely uses `--extern` as well... ... with exception of a few important cases. - Crates using `proc_macro`. `proc_macro` is not passed with `--extern` right now and is therefore not in extern prelude. Together with 2018 edition import behavior this causes problems like #54418, e.g. ```rust extern crate proc_macro; use proc_macro::TokenStream; ``` doesn't work. It starts working after this patch. - `#[no_std]` crates using `std` conditionally, like @aturon described in #53166 (comment), and still wanting to write `std` instead of `crate::std`. This PR covers that case as well. This allows us to revert placing `std` into the extern prelude unconditionally, which was, I think, a [bad idea](#53166 (comment)). - Later `extern crate` syntax can be extended to support adding an alias to some local path to extern prelude, as it may be required for resolving #54647. Notes: - Only `extern crate` items from the root module added to the prelude, mostly because this behavior for items from inner modules would look very strange, rather than for technical reasons. This means you can opt out from the prelude additions with something like ```rust mod inner { pub(crate) extern crate foo; } use inner::foo; ``` - I haven't updated logic for 2018 import canaries to work fully correctly with this. The cases where it matters are pretty exotic (the `extern crate` item must be "sufficiently macro expanded") and I'd rather spend the time on eliminating the canaries entirely.
2 parents f99911a + d1e337b commit 365b900

23 files changed

+369
-79
lines changed

src/librustc/ty/context.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,9 @@ pub struct GlobalCtxt<'tcx> {
931931

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

936938
// Internal cache for metadata decoding. No need to track deps on this.
937939
pub rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,

src/librustc/ty/item_path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
343343
// printing the `CrateRoot` so we don't prepend a `crate::` to paths.
344344
let mut is_prelude_crate = false;
345345
if let DefPathData::CrateRoot = self.def_key(parent_did).disambiguated_data.data {
346-
if self.extern_prelude.contains(&data.as_interned_str().as_symbol()) {
346+
if self.extern_prelude.contains_key(&data.as_interned_str().as_symbol()) {
347347
is_prelude_crate = true;
348348
}
349349
}

src/librustc/ty/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use ty::subst::{Subst, Substs};
3636
use ty::util::{IntTypeExt, Discr};
3737
use ty::walk::TypeWalker;
3838
use util::captures::Captures;
39-
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
39+
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
4040
use arena::SyncDroplessArena;
4141
use session::DataTypeKind;
4242

@@ -141,7 +141,9 @@ pub struct Resolutions {
141141
pub maybe_unused_trait_imports: NodeSet,
142142
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
143143
pub export_map: ExportMap,
144-
pub extern_prelude: FxHashSet<Name>,
144+
/// Extern prelude entries. The value is `true` if the entry was introduced
145+
/// via `extern crate` item and not `--extern` option or compiler built-in.
146+
pub extern_prelude: FxHashMap<Name, bool>,
145147
}
146148

147149
#[derive(Clone, Copy, PartialEq, Eq, Debug)]

src/librustc_driver/driver.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,9 @@ where
790790
trait_map: resolver.trait_map,
791791
maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
792792
maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
793-
extern_prelude: resolver.extern_prelude,
793+
extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| {
794+
(ident.name, entry.introduced_by_item)
795+
}).collect(),
794796
},
795797

796798
analysis: ty::CrateAnalysis {

src/librustc_resolve/build_reduced_graph.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use macros::{InvocationData, ParentScope, LegacyScope};
1717
use resolve_imports::ImportDirective;
1818
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport};
1919
use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding};
20-
use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas};
20+
use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry};
2121
use Namespace::{self, TypeNS, ValueNS, MacroNS};
2222
use {resolve_error, resolve_struct_error, ResolutionError};
2323

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

3030
use std::cell::Cell;
31+
use std::ptr;
3132
use rustc_data_structures::sync::Lrc;
3233

3334
use syntax::ast::{Name, Ident};
@@ -437,13 +438,32 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
437438
let module =
438439
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
439440
self.populate_module_if_necessary(module);
440-
if injected_crate_name().map_or(false, |name| item.ident.name == name) {
441+
if injected_crate_name().map_or(false, |name| ident.name == name) {
441442
self.injected_crate = Some(module);
442443
}
443444

444445
let used = self.process_legacy_macro_imports(item, module, expansion);
445446
let binding =
446447
(module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas);
448+
if ptr::eq(self.current_module, self.graph_root) {
449+
if let Some(entry) = self.extern_prelude.get(&ident.modern()) {
450+
if expansion != Mark::root() && orig_name.is_some() &&
451+
entry.extern_crate_item.is_none() {
452+
self.session.span_err(item.span, "macro-expanded `extern crate` items \
453+
cannot shadow names passed with \
454+
`--extern`");
455+
}
456+
}
457+
let entry = self.extern_prelude.entry(ident.modern())
458+
.or_insert(ExternPreludeEntry {
459+
extern_crate_item: None,
460+
introduced_by_item: true,
461+
});
462+
entry.extern_crate_item = Some(binding);
463+
if orig_name.is_some() {
464+
entry.introduced_by_item = true;
465+
}
466+
}
447467
let directive = self.arenas.alloc_import_directive(ImportDirective {
448468
root_id: item.id,
449469
id: item.id,
@@ -468,7 +488,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
468488

469489
ItemKind::GlobalAsm(..) => {}
470490

471-
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
491+
ItemKind::Mod(..) if ident == keywords::Invalid.ident() => {} // Crate root
472492

473493
ItemKind::Mod(..) => {
474494
let def_id = self.definitions.local_def_id(item.id);

src/librustc_resolve/error_reporting.rs

+9-14
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
137137
// into a `BTreeMap` so we can get consistent ordering (and therefore the same diagnostic)
138138
// each time.
139139
let external_crate_names: BTreeSet<Symbol> = self.resolver.extern_prelude
140-
.clone().drain().collect();
140+
.iter().map(|(ident, _)| ident.name).collect();
141141

142142
// Insert a new path segment that we can replace.
143143
let new_path_segment = path[0].clone();
@@ -146,19 +146,14 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
146146
// Iterate in reverse so that we start with crates at the end of the alphabet. This means
147147
// that we'll always get `std` before `core`.
148148
for name in external_crate_names.iter().rev() {
149-
let ident = Ident::with_empty_ctxt(*name);
150-
// Calling `maybe_process_path_extern` ensures that we're only running `resolve_path`
151-
// on a crate name that won't ICE.
152-
if let Some(_) = self.crate_loader.maybe_process_path_extern(*name, ident.span) {
153-
// Replace the first after root (a placeholder we inserted) with a crate name
154-
// and check if that is valid.
155-
path[1].name = *name;
156-
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
157-
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
158-
name, path, result);
159-
if let PathResult::Module(..) = result {
160-
return Some(path)
161-
}
149+
// Replace the first after root (a placeholder we inserted) with a crate name
150+
// and check if that is valid.
151+
path[1].name = *name;
152+
let result = self.resolve_path(None, &path, None, false, span, CrateLint::No);
153+
debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}",
154+
name, path, result);
155+
if let PathResult::Module(..) = result {
156+
return Some(path)
162157
}
163158
}
164159

src/librustc_resolve/lib.rs

+51-27
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
5858
use syntax::ext::base::SyntaxExtension;
5959
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
6060
use syntax::ext::base::MacroKind;
61+
use syntax::feature_gate::{emit_feature_err, GateIssue};
6162
use syntax::symbol::{Symbol, keywords};
6263
use syntax::util::lev_distance::find_best_match_for_name;
6364

@@ -1340,6 +1341,12 @@ impl PrimitiveTypeTable {
13401341
}
13411342
}
13421343

1344+
#[derive(Default, Clone)]
1345+
pub struct ExternPreludeEntry<'a> {
1346+
extern_crate_item: Option<&'a NameBinding<'a>>,
1347+
pub introduced_by_item: bool,
1348+
}
1349+
13431350
/// The main resolver class.
13441351
///
13451352
/// This is the visitor that walks the whole crate.
@@ -1352,7 +1359,7 @@ pub struct Resolver<'a, 'b: 'a> {
13521359
graph_root: Module<'a>,
13531360

13541361
prelude: Option<Module<'a>>,
1355-
pub extern_prelude: FxHashSet<Name>,
1362+
pub extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'a>>,
13561363

13571364
/// n.b. This is used only for better diagnostics, not name resolution itself.
13581365
has_self: FxHashSet<DefId>,
@@ -1668,15 +1675,16 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
16681675
DefCollector::new(&mut definitions, Mark::root())
16691676
.collect_root(crate_name, session.local_crate_disambiguator());
16701677

1671-
let mut extern_prelude: FxHashSet<Name> =
1672-
session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect();
1678+
let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry> =
1679+
session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default()))
1680+
.collect();
16731681

16741682
if !attr::contains_name(&krate.attrs, "no_core") {
1675-
extern_prelude.insert(Symbol::intern("core"));
1683+
extern_prelude.insert(Ident::from_str("core"), Default::default());
16761684
if !attr::contains_name(&krate.attrs, "no_std") {
1677-
extern_prelude.insert(Symbol::intern("std"));
1685+
extern_prelude.insert(Ident::from_str("std"), Default::default());
16781686
if session.rust_2018() {
1679-
extern_prelude.insert(Symbol::intern("meta"));
1687+
extern_prelude.insert(Ident::from_str("meta"), Default::default());
16801688
}
16811689
}
16821690
}
@@ -1963,21 +1971,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
19631971
}
19641972

19651973
if !module.no_implicit_prelude {
1966-
if ns == TypeNS && self.extern_prelude.contains(&ident.name) {
1967-
let crate_id = if record_used {
1968-
self.crate_loader.process_path_extern(ident.name, ident.span)
1969-
} else if let Some(crate_id) =
1970-
self.crate_loader.maybe_process_path_extern(ident.name, ident.span) {
1971-
crate_id
1972-
} else {
1973-
return None;
1974-
};
1975-
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
1976-
self.populate_module_if_necessary(&crate_root);
1977-
1978-
let binding = (crate_root, ty::Visibility::Public,
1979-
ident.span, Mark::root()).to_name_binding(self.arenas);
1980-
return Some(LexicalScopeBinding::Item(binding));
1974+
if ns == TypeNS {
1975+
if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) {
1976+
return Some(LexicalScopeBinding::Item(binding));
1977+
}
19811978
}
19821979
if ns == TypeNS && is_known_tool(ident.name) {
19831980
let binding = (Def::ToolMod, ty::Visibility::Public,
@@ -4018,7 +4015,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
40184015
} else {
40194016
// Items from the prelude
40204017
if !module.no_implicit_prelude {
4021-
names.extend(self.extern_prelude.iter().cloned());
4018+
names.extend(self.extern_prelude.iter().map(|(ident, _)| ident.name));
40224019
if let Some(prelude) = self.prelude {
40234020
add_module_candidates(prelude, &mut names);
40244021
}
@@ -4459,11 +4456,9 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
44594456

44604457
if self.session.rust_2018() {
44614458
let extern_prelude_names = self.extern_prelude.clone();
4462-
for &name in extern_prelude_names.iter() {
4463-
let ident = Ident::with_empty_ctxt(name);
4464-
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(name,
4465-
ident.span)
4466-
{
4459+
for (ident, _) in extern_prelude_names.into_iter() {
4460+
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name,
4461+
ident.span) {
44674462
let crate_root = self.get_module(DefId {
44684463
krate: crate_id,
44694464
index: CRATE_DEF_INDEX,
@@ -4825,6 +4820,35 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
48254820
err.emit();
48264821
self.name_already_seen.insert(name, span);
48274822
}
4823+
4824+
fn extern_prelude_get(&mut self, ident: Ident, speculative: bool, skip_feature_gate: bool)
4825+
-> Option<&'a NameBinding<'a>> {
4826+
self.extern_prelude.get(&ident.modern()).cloned().and_then(|entry| {
4827+
if let Some(binding) = entry.extern_crate_item {
4828+
if !speculative && !skip_feature_gate && entry.introduced_by_item &&
4829+
!self.session.features_untracked().extern_crate_item_prelude {
4830+
emit_feature_err(&self.session.parse_sess, "extern_crate_item_prelude",
4831+
ident.span, GateIssue::Language,
4832+
"use of extern prelude names introduced \
4833+
with `extern crate` items is unstable");
4834+
}
4835+
Some(binding)
4836+
} else {
4837+
let crate_id = if !speculative {
4838+
self.crate_loader.process_path_extern(ident.name, ident.span)
4839+
} else if let Some(crate_id) =
4840+
self.crate_loader.maybe_process_path_extern(ident.name, ident.span) {
4841+
crate_id
4842+
} else {
4843+
return None;
4844+
};
4845+
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
4846+
self.populate_module_if_necessary(&crate_root);
4847+
Some((crate_root, ty::Visibility::Public, ident.span, Mark::root())
4848+
.to_name_binding(self.arenas))
4849+
}
4850+
})
4851+
}
48284852
}
48294853

48304854
fn is_self_type(path: &[Ident], namespace: Namespace) -> bool {

src/librustc_resolve/macros.rs

+7-12
Original file line numberDiff line numberDiff line change
@@ -691,19 +691,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
691691
}
692692
}
693693
WhereToResolve::ExternPrelude => {
694-
if use_prelude && self.extern_prelude.contains(&ident.name) {
695-
let crate_id =
696-
self.crate_loader.process_path_extern(ident.name, ident.span);
697-
let crate_root =
698-
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
699-
self.populate_module_if_necessary(crate_root);
700-
701-
let binding = (crate_root, ty::Visibility::Public,
702-
ident.span, Mark::root()).to_name_binding(self.arenas);
703-
Ok((binding, Flags::PRELUDE, Flags::empty()))
704-
} else {
705-
Err(Determinacy::Determined)
694+
let mut result = Err(Determinacy::Determined);
695+
if use_prelude {
696+
if let Some(binding) = self.extern_prelude_get(ident, !record_used,
697+
innermost_result.is_some()) {
698+
result = Ok((binding, Flags::PRELUDE, Flags::empty()));
699+
}
706700
}
701+
result
707702
}
708703
WhereToResolve::ToolPrelude => {
709704
if use_prelude && is_known_tool(ident.name) {

src/librustc_resolve/resolve_imports.rs

+20-11
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_data_structures::ptr_key::PtrKey;
2121
use rustc::ty;
2222
use rustc::lint::builtin::BuiltinLintDiagnostics;
2323
use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE};
24-
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
24+
use rustc::hir::def_id::DefId;
2525
use rustc::hir::def::*;
2626
use rustc::session::DiagnosticMessageId;
2727
use rustc::util::nodemap::FxHashSet;
@@ -202,7 +202,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
202202
if !(
203203
ns == TypeNS &&
204204
!ident.is_path_segment_keyword() &&
205-
self.extern_prelude.contains(&ident.name)
205+
self.extern_prelude.contains_key(&ident.modern())
206206
) {
207207
// ... unless the crate name is not in the `extern_prelude`.
208208
return binding;
@@ -220,12 +220,15 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> {
220220
self.resolve_crate_root(ident)
221221
} else if
222222
ns == TypeNS &&
223-
!ident.is_path_segment_keyword() &&
224-
self.extern_prelude.contains(&ident.name)
223+
!ident.is_path_segment_keyword()
225224
{
226-
let crate_id =
227-
self.crate_loader.process_path_extern(ident.name, ident.span);
228-
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
225+
if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) {
226+
let module = self.get_module(binding.def().def_id());
227+
self.populate_module_if_necessary(module);
228+
return Ok(binding);
229+
} else {
230+
return Err(Determined);
231+
}
229232
} else {
230233
return Err(Determined);
231234
};
@@ -738,10 +741,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
738741
let uniform_paths_feature = self.session.features_untracked().uniform_paths;
739742
for ((span, _, ns), results) in uniform_paths_canaries {
740743
let name = results.name;
741-
let external_crate = if ns == TypeNS && self.extern_prelude.contains(&name) {
742-
let crate_id =
743-
self.crate_loader.process_path_extern(name, span);
744-
Some(Def::Mod(DefId { krate: crate_id, index: CRATE_DEF_INDEX }))
744+
let external_crate = if ns == TypeNS {
745+
self.extern_prelude_get(Ident::with_empty_ctxt(name), true, false)
746+
.map(|binding| binding.def())
745747
} else {
746748
None
747749
};
@@ -1021,6 +1023,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> {
10211023
Some(this.dummy_binding);
10221024
}
10231025
}
1026+
if record_used && ns == TypeNS {
1027+
if let ModuleOrUniformRoot::UniformRoot(..) = module {
1028+
// Make sure single-segment import is resolved non-speculatively
1029+
// at least once to report the feature error.
1030+
this.extern_prelude_get(ident, false, false);
1031+
}
1032+
}
10241033
}
10251034
});
10261035

src/librustc_typeck/check_unused.rs

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

0 commit comments

Comments
 (0)