From 0f625ac48dc3b834c35796496c600a96e053227e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 29 Sep 2018 01:31:54 +0300 Subject: [PATCH 1/4] Add `extern crate` items to extern prelude --- src/librustc/ty/context.rs | 2 +- src/librustc/ty/item_path.rs | 2 +- src/librustc/ty/mod.rs | 4 +- src/librustc_driver/driver.rs | 4 +- src/librustc_resolve/build_reduced_graph.rs | 13 +++- src/librustc_resolve/error_reporting.rs | 23 +++--- src/librustc_resolve/lib.rs | 70 ++++++++++++------- src/librustc_resolve/macros.rs | 18 ++--- src/librustc_resolve/resolve_imports.rs | 24 ++++--- src/librustc_typeck/check_unused.rs | 2 +- .../extern-prelude-extern-crate-proc-macro.rs | 7 ++ .../extern-prelude-extern-crate-cfg.rs | 16 +++++ .../extern-prelude-extern-crate-fail.rs | 13 ++++ .../extern-prelude-extern-crate-fail.stderr | 9 +++ .../extern-prelude-extern-crate-pass.rs | 12 ++++ ...elude-extern-crate-restricted-shadowing.rs | 17 +++++ ...e-extern-crate-restricted-shadowing.stderr | 20 ++++++ .../macro-path-prelude-shadowing.stderr | 4 -- 18 files changed, 183 insertions(+), 77 deletions(-) create mode 100644 src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs create mode 100644 src/test/ui/imports/extern-prelude-extern-crate-cfg.rs create mode 100644 src/test/ui/imports/extern-prelude-extern-crate-fail.rs create mode 100644 src/test/ui/imports/extern-prelude-extern-crate-fail.stderr create mode 100644 src/test/ui/imports/extern-prelude-extern-crate-pass.rs create mode 100644 src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs create mode 100644 src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index c60471c285dcb..3dae2aaec7ceb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -931,7 +931,7 @@ pub struct GlobalCtxt<'tcx> { maybe_unused_trait_imports: FxHashSet, maybe_unused_extern_crates: Vec<(DefId, Span)>, - pub extern_prelude: FxHashSet, + pub extern_prelude: FxHashMap, // Internal cache for metadata decoding. No need to track deps on this. pub rcache: Lock>>, diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 46669f1f9434b..7153c729d1542 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -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; } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index bb9346f2f468d..0d4a49e95ecde 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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; @@ -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, + pub extern_prelude: FxHashMap, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8020d596afd0f..7ad012409b53a 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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 { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 5222dd27d34d6..777a5ab79d090 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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}; @@ -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}; @@ -437,13 +438,19 @@ 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) { + 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 @@ 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); diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 74d1ae96e794f..6fcee4051ac37 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -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 = 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 @@ 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) } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2c09ae7b7d2a5..67dc749cb0051 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1340,6 +1340,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. @@ -1352,7 +1358,7 @@ pub struct Resolver<'a, 'b: 'a> { graph_root: Module<'a>, prelude: Option>, - pub extern_prelude: FxHashSet, + pub extern_prelude: FxHashMap>, /// n.b. This is used only for better diagnostics, not name resolution itself. has_self: FxHashSet, @@ -1668,15 +1674,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 = - session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect(); + let mut extern_prelude: FxHashMap = + 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 @@ 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) { + return Some(LexicalScopeBinding::Item(binding)); + } } if ns == TypeNS && is_known_tool(ident.name) { let binding = (Def::ToolMod, ty::Visibility::Public, @@ -4018,7 +4014,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); } @@ -4459,11 +4455,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, @@ -4825,6 +4819,28 @@ 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) + -> 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 { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 28284a45bcdd5..2f7e300b8ff38 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -691,19 +691,13 @@ 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) { + result = Ok((binding, Flags::PRELUDE, Flags::empty())); + } } + result } WhereToResolve::ToolPrelude => { if use_prelude && is_known_tool(ident.name) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 27ba1ced74985..a3aa50fe0276c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -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; @@ -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; @@ -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) { + 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 @@ 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) + .map(|binding| binding.def()) } else { None }; diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index f9aa0397257b8..9d785dfb58ac1 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -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; } diff --git a/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs b/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs new file mode 100644 index 0000000000000..25a2a37614778 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs @@ -0,0 +1,7 @@ +// compile-pass +// edition:2018 + +extern crate proc_macro; +use proc_macro::TokenStream; // OK + +fn main() {} diff --git a/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs b/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs new file mode 100644 index 0000000000000..6117e5f6f3cd7 --- /dev/null +++ b/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs @@ -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::::new(); // OK + } +} + +fn main() {} diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs new file mode 100644 index 0000000000000..22248af6d3a2d --- /dev/null +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs @@ -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() {} diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr new file mode 100644 index 0000000000000..464812f1f6902 --- /dev/null +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr @@ -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`. diff --git a/src/test/ui/imports/extern-prelude-extern-crate-pass.rs b/src/test/ui/imports/extern-prelude-extern-crate-pass.rs new file mode 100644 index 0000000000000..bb4cf6ca99c75 --- /dev/null +++ b/src/test/ui/imports/extern-prelude-extern-crate-pass.rs @@ -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() {} diff --git a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs new file mode 100644 index 0000000000000..3eefaf1267e88 --- /dev/null +++ b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs @@ -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() {} diff --git a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr new file mode 100644 index 0000000000000..6a28d74a343c9 --- /dev/null +++ b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr @@ -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`. diff --git a/src/test/ui/macros/macro-path-prelude-shadowing.stderr b/src/test/ui/macros/macro-path-prelude-shadowing.stderr index 607d3e100aa25..688b9dc2797d0 100644 --- a/src/test/ui/macros/macro-path-prelude-shadowing.stderr +++ b/src/test/ui/macros/macro-path-prelude-shadowing.stderr @@ -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 From faefc83a7a1ca31c4f32feca4f8b0b0b99b9831b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 20 Oct 2018 20:26:24 +0300 Subject: [PATCH 2/4] Feature gate extern prelude additions from `extern crate` items Fix rustdoc and fulldeps tests --- src/librustc_resolve/lib.rs | 12 +++- src/librustc_resolve/macros.rs | 3 +- src/librustc_resolve/resolve_imports.rs | 11 ++- src/librustdoc/core.rs | 4 +- src/libsyntax/feature_gate.rs | 3 + .../extern-prelude-extern-crate-proc-macro.rs | 2 + src/test/ui-fulldeps/resolve-error.stderr | 2 +- .../feature-gate-extern_crate_item_prelude.rs | 39 +++++++++++ ...ture-gate-extern_crate_item_prelude.stderr | 67 +++++++++++++++++++ .../extern-prelude-extern-crate-cfg.rs | 1 + .../extern-prelude-extern-crate-pass.rs | 2 + ...elude-extern-crate-restricted-shadowing.rs | 2 + ...e-extern-crate-restricted-shadowing.stderr | 4 +- 13 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs create mode 100644 src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 67dc749cb0051..2c21067bd58c8 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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; @@ -1971,7 +1972,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { if !module.no_implicit_prelude { if ns == TypeNS { - if let Some(binding) = self.extern_prelude_get(ident, !record_used) { + if let Some(binding) = self.extern_prelude_get(ident, !record_used, false) { return Some(LexicalScopeBinding::Item(binding)); } } @@ -4820,10 +4821,17 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { self.name_already_seen.insert(name, span); } - fn extern_prelude_get(&mut self, ident: Ident, speculative: bool) + 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 { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 2f7e300b8ff38..3345e01a929c7 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -693,7 +693,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> { WhereToResolve::ExternPrelude => { let mut result = Err(Determinacy::Determined); if use_prelude { - if let Some(binding) = self.extern_prelude_get(ident, !record_used) { + if let Some(binding) = self.extern_prelude_get(ident, !record_used, + innermost_result.is_some()) { result = Ok((binding, Flags::PRELUDE, Flags::empty())); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a3aa50fe0276c..6c73f1bd0f8c5 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -222,7 +222,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { ns == TypeNS && !ident.is_path_segment_keyword() { - if let Some(binding) = self.extern_prelude_get(ident, !record_used) { + 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); @@ -742,7 +742,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { for ((span, _, ns), results) in uniform_paths_canaries { let name = results.name; let external_crate = if ns == TypeNS { - self.extern_prelude_get(Ident::with_empty_ctxt(name), true) + self.extern_prelude_get(Ident::with_empty_ctxt(name), true, false) .map(|binding| binding.def()) } else { None @@ -1023,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); + } + } } }); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 49f13df64d6ea..8f9c3fa4b7f20 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -476,7 +476,9 @@ pub fn run_core(search_paths: SearchPaths, trait_map: resolver.trait_map.clone(), maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(), maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(), - extern_prelude: resolver.extern_prelude.clone(), + extern_prelude: resolver.extern_prelude.iter().map(|(ident, entry)| { + (ident.name, entry.introduced_by_item) + }).collect(), }; let analysis = ty::CrateAnalysis { access_levels: Lrc::new(AccessLevels::default()), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d0f407aa9243b..2cd4fd92bc81e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -501,6 +501,9 @@ declare_features! ( // Allows `const _: TYPE = VALUE` (active, underscore_const_names, "1.31.0", Some(54912), None), + + // `extern crate foo as bar;` puts `bar` into extern prelude. + (active, extern_crate_item_prelude, "1.31.0", Some(54658), None), ); declare_features! ( diff --git a/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs b/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs index 25a2a37614778..e320ad9713542 100644 --- a/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs +++ b/src/test/ui-fulldeps/proc-macro/extern-prelude-extern-crate-proc-macro.rs @@ -1,6 +1,8 @@ // compile-pass // edition:2018 +#![feature(extern_crate_item_prelude)] + extern crate proc_macro; use proc_macro::TokenStream; // OK diff --git a/src/test/ui-fulldeps/resolve-error.stderr b/src/test/ui-fulldeps/resolve-error.stderr index 278409c688ab9..59ca668d48525 100644 --- a/src/test/ui-fulldeps/resolve-error.stderr +++ b/src/test/ui-fulldeps/resolve-error.stderr @@ -20,7 +20,7 @@ error: cannot find derive macro `attr_proc_macra` in this scope --> $DIR/resolve-error.rs:54:10 | LL | #[derive(attr_proc_macra)] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro` error: cannot find macro `FooWithLongNama!` in this scope --> $DIR/resolve-error.rs:59:5 diff --git a/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs new file mode 100644 index 0000000000000..eb7c52c3d0f32 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs @@ -0,0 +1,39 @@ +// edition:2018 + +#![feature(alloc)] + +extern crate alloc; + +mod in_scope { + fn check() { + let v = alloc::vec![0]; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable + type A = alloc::boxed::Box; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable + } +} + +mod absolute { + fn check() { + let v = ::alloc::vec![0]; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable + type A = ::alloc::boxed::Box; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable + } +} + +mod import_in_scope { + use alloc; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable + use alloc::boxed; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable +} + +mod import_absolute { + use ::alloc; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable + use ::alloc::boxed; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr new file mode 100644 index 0000000000000..4dec8a35bcab1 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr @@ -0,0 +1,67 @@ +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:26:9 + | +LL | use alloc; + | ^^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:28:9 + | +LL | use alloc::boxed; + | ^^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:33:11 + | +LL | use ::alloc; + | ^^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:35:11 + | +LL | use ::alloc::boxed; + | ^^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:9:17 + | +LL | let v = alloc::vec![0]; + | ^^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:11:18 + | +LL | type A = alloc::boxed::Box; + | ^^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:18:19 + | +LL | let v = ::alloc::vec![0]; + | ^^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:20:20 + | +LL | type A = ::alloc::boxed::Box; + | ^^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs b/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs index 6117e5f6f3cd7..c48a65798b6c1 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs +++ b/src/test/ui/imports/extern-prelude-extern-crate-cfg.rs @@ -1,6 +1,7 @@ // compile-pass // compile-flags:--cfg my_feature +#![feature(extern_crate_item_prelude)] #![no_std] #[cfg(my_feature)] diff --git a/src/test/ui/imports/extern-prelude-extern-crate-pass.rs b/src/test/ui/imports/extern-prelude-extern-crate-pass.rs index bb4cf6ca99c75..8c147dfd04a3c 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-pass.rs +++ b/src/test/ui/imports/extern-prelude-extern-crate-pass.rs @@ -1,6 +1,8 @@ // compile-pass // aux-build:two_macros.rs +#![feature(extern_crate_item_prelude)] + extern crate two_macros; mod m { diff --git a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs index 3eefaf1267e88..732f1c4de2fb3 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs +++ b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.rs @@ -1,5 +1,7 @@ // aux-build:two_macros.rs +#![feature(extern_crate_item_prelude)] + macro_rules! define_vec { () => { extern crate std as Vec; diff --git a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr index 6a28d74a343c9..6c832e70e49a7 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr +++ b/src/test/ui/imports/extern-prelude-extern-crate-restricted-shadowing.stderr @@ -1,11 +1,11 @@ error[E0659]: `Vec` is ambiguous - --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:13:9 + --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:15: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 + --> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:7:9 | LL | extern crate std as Vec; | ^^^^^^^^^^^^^^^^^^^^^^^^ From 7976aa32a97335f8f15dd70ce3f67adea595dd46 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 22 Oct 2018 22:54:18 +0300 Subject: [PATCH 3/4] Minor doc improvements --- src/librustc/ty/context.rs | 4 +++- src/librustc/ty/mod.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3dae2aaec7ceb..1a9f86306325f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -931,7 +931,9 @@ pub struct GlobalCtxt<'tcx> { maybe_unused_trait_imports: FxHashSet, maybe_unused_extern_crates: Vec<(DefId, Span)>, - pub extern_prelude: FxHashMap, + /// 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, // Internal cache for metadata decoding. No need to track deps on this. pub rcache: Lock>>, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0d4a49e95ecde..6ea759dee2126 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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: FxHashMap, + /// 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, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] From d1e337bded30b84df777f6de3d8fc588286f0834 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 24 Oct 2018 01:03:47 +0300 Subject: [PATCH 4/4] Prohibit macro-expanded `extern crate` items shadowing crates passed with `--extern` --- src/librustc_resolve/build_reduced_graph.rs | 17 +++++++++++++++-- .../feature-gate-extern_crate_item_prelude.rs | 7 +++++++ ...eature-gate-extern_crate_item_prelude.stderr | 10 +++++++++- .../imports/extern-prelude-extern-crate-fail.rs | 9 +++++++++ .../extern-prelude-extern-crate-fail.stderr | 13 +++++++++++-- 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 777a5ab79d090..aa7bfeae5f48b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -446,10 +446,23 @@ impl<'a, 'cl> Resolver<'a, 'cl> { 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 { + 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, - }).extern_crate_item = Some(binding); + }); + 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, diff --git a/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs index eb7c52c3d0f32..a043b6c2e6107 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs +++ b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.rs @@ -36,4 +36,11 @@ mod import_absolute { //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable } +extern crate alloc as core; + +mod unrelated_crate_renamed { + type A = core::boxed::Box; + //~^ ERROR use of extern prelude names introduced with `extern crate` items is unstable +} + fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr index 4dec8a35bcab1..cabfb56d7a840 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr +++ b/src/test/ui/feature-gates/feature-gate-extern_crate_item_prelude.stderr @@ -62,6 +62,14 @@ LL | type A = ::alloc::boxed::Box; | = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable -error: aborting due to 8 previous errors +error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658) + --> $DIR/feature-gate-extern_crate_item_prelude.rs:42:14 + | +LL | type A = core::boxed::Box; + | ^^^^ + | + = help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs index 22248af6d3a2d..57b097c9df318 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs @@ -1,4 +1,5 @@ // aux-build:two_macros.rs +// compile-flags:--extern non_existent mod n { extern crate two_macros; @@ -10,4 +11,12 @@ mod m { } } +macro_rules! define_std_as_non_existent { + () => { + extern crate std as non_existent; + //~^ ERROR `extern crate` items cannot shadow names passed with `--extern` + } +} +define_std_as_non_existent!(); + fn main() {} diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr index 464812f1f6902..8f68d2af34ca3 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr @@ -1,9 +1,18 @@ +error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` + --> $DIR/extern-prelude-extern-crate-fail.rs:16:9 + | +LL | extern crate std as non_existent; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_std_as_non_existent!(); + | ------------------------------ in this macro invocation + error[E0433]: failed to resolve. Use of undeclared type or module `two_macros` - --> $DIR/extern-prelude-extern-crate-fail.rs:9:9 + --> $DIR/extern-prelude-extern-crate-fail.rs:10: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 +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0433`.