From c658d7340149274bb30a56fb3e7de799c266f4bc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 30 Nov 2018 21:16:21 +0300 Subject: [PATCH 1/3] resolve: Avoid "self-confirming" resolutions in import validation --- src/librustc_resolve/build_reduced_graph.rs | 9 +++- src/librustc_resolve/lib.rs | 2 + src/librustc_resolve/macros.rs | 8 ++-- src/librustc_resolve/resolve_imports.rs | 45 ++++++++++++------- .../feature-gate-uniform-paths.stderr | 18 ++------ 5 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 0fa41cb484fc9..b9de05f7d6f48 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -230,13 +230,18 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } let subclass = SingleImport { - target: ident, source: source.ident, - result: PerNS { + target: ident, + source_bindings: PerNS { type_ns: Cell::new(Err(Undetermined)), value_ns: Cell::new(Err(Undetermined)), macro_ns: Cell::new(Err(Undetermined)), }, + target_bindings: PerNS { + type_ns: Cell::new(None), + value_ns: Cell::new(None), + macro_ns: Cell::new(None), + }, type_ns_only, }; self.add_import_directive( diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c1d4643c2403e..04495d2ea9bfd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1521,6 +1521,7 @@ pub struct Resolver<'a, 'b: 'a> { /// FIXME: Refactor things so that this is passed through arguments and not resolver. last_import_segment: bool, + blacklisted_binding: Option<&'a NameBinding<'a>>, /// The idents for the primitive types. primitive_type_table: PrimitiveTypeTable, @@ -1871,6 +1872,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { current_self_type: None, current_self_item: None, last_import_segment: false, + blacklisted_binding: None, primitive_type_table: PrimitiveTypeTable::new(), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 5db3efee9f6a1..1707eeca1430c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -977,12 +977,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let what = self.binding_description(binding, ident, flags.contains(Flags::MISC_FROM_PRELUDE)); let note_msg = format!("this import refers to {what}", what = what); - if binding.span.is_dummy() { + let label_span = if binding.span.is_dummy() { err.note(¬e_msg); + ident.span } else { err.span_note(binding.span, ¬e_msg); - err.span_label(binding.span, "not an extern crate passed with `--extern`"); - } + binding.span + }; + err.span_label(label_span, "not an extern crate passed with `--extern`"); err.emit(); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e7cd32f4e810f..8695e38e1523b 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -42,9 +42,10 @@ use std::{mem, ptr}; #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { SingleImport { - target: Ident, source: Ident, - result: PerNS, Determinacy>>>, + target: Ident, + source_bindings: PerNS, Determinacy>>>, + target_bindings: PerNS>>>, type_ns_only: bool, }, GlobImport { @@ -227,6 +228,11 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { } let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| { + if let Some(blacklisted_binding) = this.blacklisted_binding { + if ptr::eq(binding, blacklisted_binding) { + return Err((Determined, Weak::No)); + } + } // `extern crate` are always usable for backwards compatibility, see issue #37020, // remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`. let usable = this.is_accessible(binding.vis) || binding.is_extern_crate(); @@ -642,10 +648,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { if let Some((span, err, note)) = self.finalize_import(import) { errors = true; - if let SingleImport { source, ref result, .. } = import.subclass { + if let SingleImport { source, ref source_bindings, .. } = import.subclass { if source.name == "self" { // Silence `unresolved import` error if E0429 is already emitted - if let Err(Determined) = result.value_ns.get() { + if let Err(Determined) = source_bindings.value_ns.get() { continue; } } @@ -765,9 +771,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { }; directive.imported_module.set(Some(module)); - let (source, target, result, type_ns_only) = match directive.subclass { - SingleImport { source, target, ref result, type_ns_only } => - (source, target, result, type_ns_only), + let (source, target, source_bindings, target_bindings, type_ns_only) = + match directive.subclass { + SingleImport { source, target, ref source_bindings, + ref target_bindings, type_ns_only } => + (source, target, source_bindings, target_bindings, type_ns_only), GlobImport { .. } => { self.resolve_glob_import(directive); return true; @@ -777,7 +785,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let mut indeterminate = false; self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { - if let Err(Undetermined) = result[ns].get() { + if let Err(Undetermined) = source_bindings[ns].get() { // For better failure detection, pretend that the import will // not define any names while resolving its module path. let orig_vis = directive.vis.replace(ty::Visibility::Invisible); @@ -786,13 +794,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { ); directive.vis.set(orig_vis); - result[ns].set(binding); + source_bindings[ns].set(binding); } else { return }; let parent = directive.parent_scope.module; - match result[ns].get() { + match source_bindings[ns].get() { Err(Undetermined) => indeterminate = true, Err(Determined) => { this.update_resolution(parent, target, ns, |_, resolution| { @@ -810,6 +818,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } Ok(binding) => { let imported_binding = this.import(binding, directive); + target_bindings[ns].set(Some(imported_binding)); let conflict = this.try_define(parent, target, ns, imported_binding); if let Err(old_binding) = conflict { this.report_conflict(parent, target, ns, imported_binding, old_binding); @@ -879,8 +888,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(), }; - let (ident, result, type_ns_only) = match directive.subclass { - SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only), + let (ident, source_bindings, target_bindings, type_ns_only) = match directive.subclass { + SingleImport { source, ref source_bindings, ref target_bindings, type_ns_only, .. } => + (source, source_bindings, target_bindings, type_ns_only), GlobImport { is_prelude, ref max_vis } => { if directive.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least @@ -919,17 +929,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let mut all_ns_err = true; self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS { let orig_vis = directive.vis.replace(ty::Visibility::Invisible); + let orig_blacklisted_binding = + mem::replace(&mut this.blacklisted_binding, target_bindings[ns].get()); let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true); let binding = this.resolve_ident_in_module( module, ident, ns, Some(&directive.parent_scope), true, directive.span ); this.last_import_segment = orig_last_import_segment; + this.blacklisted_binding = orig_blacklisted_binding; directive.vis.set(orig_vis); match binding { Ok(binding) => { // Consistency checks, analogous to `finalize_current_module_macro_resolutions`. - let initial_def = result[ns].get().map(|initial_binding| { + let initial_def = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; this.record_use(ident, ns, initial_binding, directive.module_path.is_empty()); @@ -1034,7 +1047,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let mut reexport_error = None; let mut any_successful_reexport = false; self.per_ns(|this, ns| { - if let Ok(binding) = result[ns].get() { + if let Ok(binding) = source_bindings[ns].get() { let vis = directive.vis.get(); if !binding.pseudo_vis().is_at_least(vis, &*this) { reexport_error = Some((ns, binding)); @@ -1078,7 +1091,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let mut full_path = directive.module_path.clone(); full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { - if let Ok(binding) = result[ns].get() { + if let Ok(binding) = source_bindings[ns].get() { this.lint_if_path_starts_with_module( directive.crate_lint(), &full_path, @@ -1092,7 +1105,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() { + self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() { let mut def = binding.def(); if let Def::Macro(def_id, _) = def { // `DefId`s from the "built-in macro crate" should not leak from resolve because diff --git a/src/test/ui/feature-gates/feature-gate-uniform-paths.stderr b/src/test/ui/feature-gates/feature-gate-uniform-paths.stderr index ec8937bbc5f5c..0631f2c355f7c 100644 --- a/src/test/ui/feature-gates/feature-gate-uniform-paths.stderr +++ b/src/test/ui/feature-gates/feature-gate-uniform-paths.stderr @@ -25,11 +25,7 @@ LL | use inline; //~ ERROR imports can only refer to extern crate names | ^^^^^^ not an extern crate passed with `--extern` | = help: add #![feature(uniform_paths)] to the crate attributes to enable -note: this import refers to the built-in attribute imported here - --> $DIR/feature-gate-uniform-paths.rs:21:5 - | -LL | use inline; //~ ERROR imports can only refer to extern crate names - | ^^^^^^ + = note: this import refers to a built-in attribute error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130) --> $DIR/feature-gate-uniform-paths.rs:23:5 @@ -38,11 +34,7 @@ LL | use Vec; //~ ERROR imports can only refer to extern crate names | ^^^ not an extern crate passed with `--extern` | = help: add #![feature(uniform_paths)] to the crate attributes to enable -note: this import refers to the struct imported here - --> $DIR/feature-gate-uniform-paths.rs:23:5 - | -LL | use Vec; //~ ERROR imports can only refer to extern crate names - | ^^^ + = note: this import refers to a struct from prelude error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130) --> $DIR/feature-gate-uniform-paths.rs:25:5 @@ -51,11 +43,7 @@ LL | use vec; //~ ERROR imports can only refer to extern crate names | ^^^ not an extern crate passed with `--extern` | = help: add #![feature(uniform_paths)] to the crate attributes to enable -note: this import refers to the macro imported here - --> $DIR/feature-gate-uniform-paths.rs:25:5 - | -LL | use vec; //~ ERROR imports can only refer to extern crate names - | ^^^ + = note: this import refers to a macro from prelude error: aborting due to 4 previous errors From 2d4b633be36a59667f8648d987169f59f8314b1c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 30 Nov 2018 22:34:24 +0300 Subject: [PATCH 2/3] Delay gensym creation for "underscore items" until name resolution Prohibit `static _` Fis unused import warnings for `use foo as _` Add more tests for `use foo as _` --- src/librustc_resolve/build_reduced_graph.rs | 10 ++++--- src/librustc_resolve/resolve_imports.rs | 14 ++++++---- src/libsyntax/parse/parser.rs | 27 +++++++++---------- src/libsyntax_pos/symbol.rs | 6 ++++- .../underscore_const_names_feature_gate.rs | 1 - ...underscore_const_names_feature_gate.stderr | 10 +------ src/test/ui/parser/underscore_static.rs | 3 +++ src/test/ui/parser/underscore_static.stderr | 8 ++++++ .../auxiliary/duplicate.rs | 14 ++++++++++ .../auxiliary/underscore-imports.rs | 22 +++++++++++++++ .../ui/rfc-2166-underscore-imports/basic.rs | 6 +++++ .../rfc-2166-underscore-imports/basic.stderr | 6 ++--- .../rfc-2166-underscore-imports/duplicate.rs | 17 ++++++++++++ .../rfc-2166-underscore-imports/intercrate.rs | 11 ++++++++ .../unused-2018.rs | 18 +++++++++++++ .../unused-2018.stderr | 20 ++++++++++++++ 16 files changed, 157 insertions(+), 36 deletions(-) rename src/test/ui/{ => feature-gates}/underscore_const_names_feature_gate.rs (92%) rename src/test/ui/{ => feature-gates}/underscore_const_names_feature_gate.stderr (51%) create mode 100644 src/test/ui/parser/underscore_static.rs create mode 100644 src/test/ui/parser/underscore_static.stderr create mode 100644 src/test/ui/rfc-2166-underscore-imports/auxiliary/duplicate.rs create mode 100644 src/test/ui/rfc-2166-underscore-imports/auxiliary/underscore-imports.rs create mode 100644 src/test/ui/rfc-2166-underscore-imports/duplicate.rs create mode 100644 src/test/ui/rfc-2166-underscore-imports/intercrate.rs create mode 100644 src/test/ui/rfc-2166-underscore-imports/unused-2018.rs create mode 100644 src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index b9de05f7d6f48..b40988d0d09c9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -157,7 +157,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { }; match use_tree.kind { ast::UseTreeKind::Simple(rename, ..) => { - let mut ident = use_tree.ident(); + let mut ident = use_tree.ident().gensym_if_underscore(); let mut module_path = prefix; let mut source = module_path.pop().unwrap(); let mut type_ns_only = false; @@ -334,7 +334,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScope<'a>) { let parent = parent_scope.module; let expansion = parent_scope.expansion; - let ident = item.ident; + let ident = item.ident.gensym_if_underscore(); let sp = item.span; let vis = self.resolve_visibility(&item.vis); @@ -628,7 +628,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, child: Export) { - let Export { ident, def, vis, span, .. } = child; + let Export { ident, def, vis, span } = child; + // FIXME: We shouldn't create the gensym here, it should come from metadata, + // but metadata cannot encode gensyms currently, so we create it here. + // This is only a guess, two equivalent idents may incorrectly get different gensyms here. + let ident = ident.gensym_if_underscore(); let def_id = def.def_id(); let expansion = Mark::root(); // FIXME(jseyfried) intercrate hygiene match def { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8695e38e1523b..65224badc83cd 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -888,9 +888,11 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { PathResult::Indeterminate | PathResult::NonModule(..) => unreachable!(), }; - let (ident, source_bindings, target_bindings, type_ns_only) = match directive.subclass { - SingleImport { source, ref source_bindings, ref target_bindings, type_ns_only, .. } => - (source, source_bindings, target_bindings, type_ns_only), + let (ident, target, source_bindings, target_bindings, type_ns_only) = + match directive.subclass { + SingleImport { source, target, ref source_bindings, + ref target_bindings, type_ns_only } => + (source, target, source_bindings, target_bindings, type_ns_only), GlobImport { is_prelude, ref max_vis } => { if directive.module_path.len() <= 1 { // HACK(eddyb) `lint_if_path_starts_with_module` needs at least @@ -944,8 +946,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // Consistency checks, analogous to `finalize_current_module_macro_resolutions`. let initial_def = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; - this.record_use(ident, ns, initial_binding, - directive.module_path.is_empty()); + if target.name == "_" && + initial_binding.is_extern_crate() && !initial_binding.is_import() { + this.used_imports.insert((directive.id, TypeNS)); + } initial_binding.def_ignoring_ambiguity() }); let def = binding.def_ignoring_ambiguity(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 33715f206dedf..280060863623a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2017,6 +2017,17 @@ impl<'a> Parser<'a> { } } + fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> { + match self.token { + token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { + let span = self.span; + self.bump(); + Ok(Ident::new(ident.name, span)) + } + _ => self.parse_ident(), + } + } + /// Parses qualified path. /// Assumes that the leading `<` has been parsed already. /// @@ -6435,13 +6446,7 @@ impl<'a> Parser<'a> { } fn parse_item_const(&mut self, m: Option) -> PResult<'a, ItemInfo> { - let id = match self.token { - token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { - self.bump(); // `_` - ident.gensym() - }, - _ => self.parse_ident()?, - }; + let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; self.expect(&token::Eq)?; @@ -7726,13 +7731,7 @@ impl<'a> Parser<'a> { fn parse_rename(&mut self) -> PResult<'a, Option> { if self.eat_keyword(keywords::As) { - match self.token { - token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { - self.bump(); // `_` - Ok(Some(ident.gensym())) - } - _ => self.parse_ident().map(Some), - } + self.parse_ident_or_underscore().map(Some) } else { Ok(None) } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 741877bb4c88f..2721ab70e223d 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -80,6 +80,10 @@ impl Ident { Ident::new(self.name.gensymed(), self.span) } + pub fn gensym_if_underscore(self) -> Ident { + if self.name == keywords::Underscore.name() { self.gensym() } else { self } + } + pub fn as_str(self) -> LocalInternedString { self.name.as_str() } @@ -465,7 +469,7 @@ impl Ident { // We see this identifier in a normal identifier position, like variable name or a type. // How was it written originally? Did it use the raw form? Let's try to guess. pub fn is_raw_guess(self) -> bool { - self.name != keywords::Invalid.name() && + self.name != keywords::Invalid.name() && self.name != keywords::Underscore.name() && self.is_reserved() && !self.is_path_segment_keyword() } } diff --git a/src/test/ui/underscore_const_names_feature_gate.rs b/src/test/ui/feature-gates/underscore_const_names_feature_gate.rs similarity index 92% rename from src/test/ui/underscore_const_names_feature_gate.rs rename to src/test/ui/feature-gates/underscore_const_names_feature_gate.rs index b2174036dede0..b41e3503d7ab5 100644 --- a/src/test/ui/underscore_const_names_feature_gate.rs +++ b/src/test/ui/feature-gates/underscore_const_names_feature_gate.rs @@ -9,6 +9,5 @@ // except according to those terms. const _: () = (); //~ ERROR is unstable -static _: () = (); //~ ERROR is unstable fn main() {} diff --git a/src/test/ui/underscore_const_names_feature_gate.stderr b/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr similarity index 51% rename from src/test/ui/underscore_const_names_feature_gate.stderr rename to src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr index c97b3f8d4d3cd..192cc258cf4e1 100644 --- a/src/test/ui/underscore_const_names_feature_gate.stderr +++ b/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr @@ -6,14 +6,6 @@ LL | const _: () = (); //~ ERROR is unstable | = help: add #![feature(underscore_const_names)] to the crate attributes to enable -error[E0658]: naming constants with `_` is unstable (see issue #54912) - --> $DIR/underscore_const_names_feature_gate.rs:12:1 - | -LL | static _: () = (); //~ ERROR is unstable - | ^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(underscore_const_names)] to the crate attributes to enable - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/underscore_static.rs b/src/test/ui/parser/underscore_static.rs new file mode 100644 index 0000000000000..e1a9a02f9aaae --- /dev/null +++ b/src/test/ui/parser/underscore_static.rs @@ -0,0 +1,3 @@ +// compile-flags: -Z parse-only + +static _: () = (); //~ ERROR expected identifier, found reserved identifier `_` diff --git a/src/test/ui/parser/underscore_static.stderr b/src/test/ui/parser/underscore_static.stderr new file mode 100644 index 0000000000000..1b766f785a524 --- /dev/null +++ b/src/test/ui/parser/underscore_static.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/underscore_static.rs:3:8 + | +LL | static _: () = (); //~ ERROR expected identifier, found reserved identifier `_` + | ^ expected identifier, found reserved identifier + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2166-underscore-imports/auxiliary/duplicate.rs b/src/test/ui/rfc-2166-underscore-imports/auxiliary/duplicate.rs new file mode 100644 index 0000000000000..92d741b6a2663 --- /dev/null +++ b/src/test/ui/rfc-2166-underscore-imports/auxiliary/duplicate.rs @@ -0,0 +1,14 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_attribute] +pub fn duplicate(_: TokenStream, input: TokenStream) -> TokenStream { + let clone = input.clone(); + input.into_iter().chain(clone.into_iter()).collect() +} diff --git a/src/test/ui/rfc-2166-underscore-imports/auxiliary/underscore-imports.rs b/src/test/ui/rfc-2166-underscore-imports/auxiliary/underscore-imports.rs new file mode 100644 index 0000000000000..70de9167332b0 --- /dev/null +++ b/src/test/ui/rfc-2166-underscore-imports/auxiliary/underscore-imports.rs @@ -0,0 +1,22 @@ +#![feature(underscore_imports)] + +#[macro_export] +macro_rules! do_nothing { + () => () +} + +mod m1 { + pub trait InScope1 { + fn in_scope1(&self) {} + } + impl InScope1 for () {} +} +mod m2 { + pub trait InScope2 { + fn in_scope2(&self) {} + } + impl InScope2 for () {} +} + +pub use m1::InScope1 as _; +pub use m2::InScope2 as _; diff --git a/src/test/ui/rfc-2166-underscore-imports/basic.rs b/src/test/ui/rfc-2166-underscore-imports/basic.rs index 104bd9e166c79..64a8d0720d628 100644 --- a/src/test/ui/rfc-2166-underscore-imports/basic.rs +++ b/src/test/ui/rfc-2166-underscore-imports/basic.rs @@ -9,10 +9,16 @@ // except according to those terms. // compile-pass +// aux-build:underscore-imports.rs #![feature(underscore_imports)] #![warn(unused_imports, unused_extern_crates)] +#[macro_use] +extern crate underscore_imports as _; + +do_nothing!(); // OK + struct S; mod m { diff --git a/src/test/ui/rfc-2166-underscore-imports/basic.stderr b/src/test/ui/rfc-2166-underscore-imports/basic.stderr index 2be0317019d3c..e1fe5cc0783d9 100644 --- a/src/test/ui/rfc-2166-underscore-imports/basic.stderr +++ b/src/test/ui/rfc-2166-underscore-imports/basic.stderr @@ -1,17 +1,17 @@ warning: unused import: `m::Tr1 as _` - --> $DIR/basic.rs:31:9 + --> $DIR/basic.rs:37:9 | LL | use m::Tr1 as _; //~ WARN unused import | ^^^^^^^^^^^ | note: lint level defined here - --> $DIR/basic.rs:14:9 + --> $DIR/basic.rs:15:9 | LL | #![warn(unused_imports, unused_extern_crates)] | ^^^^^^^^^^^^^^ warning: unused import: `S as _` - --> $DIR/basic.rs:32:9 + --> $DIR/basic.rs:38:9 | LL | use S as _; //~ WARN unused import | ^^^^^^ diff --git a/src/test/ui/rfc-2166-underscore-imports/duplicate.rs b/src/test/ui/rfc-2166-underscore-imports/duplicate.rs new file mode 100644 index 0000000000000..92615c4966dae --- /dev/null +++ b/src/test/ui/rfc-2166-underscore-imports/duplicate.rs @@ -0,0 +1,17 @@ +// compile-pass +// aux-build:duplicate.rs + +#![feature(underscore_imports)] + +extern crate duplicate; + +#[duplicate::duplicate] +use main as _; // OK + +macro_rules! duplicate { + ($item: item) => { $item $item } +} + +duplicate!(use std as _;); // OK + +fn main() {} diff --git a/src/test/ui/rfc-2166-underscore-imports/intercrate.rs b/src/test/ui/rfc-2166-underscore-imports/intercrate.rs new file mode 100644 index 0000000000000..8b5bb8b326097 --- /dev/null +++ b/src/test/ui/rfc-2166-underscore-imports/intercrate.rs @@ -0,0 +1,11 @@ +// compile-pass +// aux-build:underscore-imports.rs + +extern crate underscore_imports; + +use underscore_imports::*; + +fn main() { + ().in_scope1(); + ().in_scope2(); +} diff --git a/src/test/ui/rfc-2166-underscore-imports/unused-2018.rs b/src/test/ui/rfc-2166-underscore-imports/unused-2018.rs new file mode 100644 index 0000000000000..611eb3c67ca52 --- /dev/null +++ b/src/test/ui/rfc-2166-underscore-imports/unused-2018.rs @@ -0,0 +1,18 @@ +// edition:2018 + +#![feature(underscore_imports)] +#![deny(unused_imports)] + +mod multi_segment { + use core::any; //~ ERROR unused import: `core::any` +} + +mod single_segment { + use core; //~ ERROR unused import: `core` +} + +mod single_segment_underscore { + use core as _; // OK +} + +fn main() {} diff --git a/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr b/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr new file mode 100644 index 0000000000000..02b29b3f4fe61 --- /dev/null +++ b/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr @@ -0,0 +1,20 @@ +error: unused import: `core::any` + --> $DIR/unused-2018.rs:7:9 + | +LL | use core::any; //~ ERROR unused import: `core::any` + | ^^^^^^^^^ + | +note: lint level defined here + --> $DIR/unused-2018.rs:4:9 + | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: unused import: `core` + --> $DIR/unused-2018.rs:11:9 + | +LL | use core; //~ ERROR unused import: `core` + | ^^^^ + +error: aborting due to 2 previous errors + From eb1d2e637ee9be0d111feb435b068081f10e6ec3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 1 Dec 2018 22:14:37 +0300 Subject: [PATCH 3/3] Address review comments --- src/librustc_resolve/lib.rs | 5 ++++- src/librustc_resolve/resolve_imports.rs | 14 +++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 04495d2ea9bfd..9bc9bc6de5b4b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1519,8 +1519,11 @@ pub struct Resolver<'a, 'b: 'a> { /// The current self item if inside an ADT (used for better errors). current_self_item: Option, - /// FIXME: Refactor things so that this is passed through arguments and not resolver. + /// FIXME: Refactor things so that these fields are passed through arguments and not resolver. + /// We are resolving a last import segment during import validation. last_import_segment: bool, + /// This binding should be ignored during in-module resolution, so that we don't get + /// "self-confirming" import resolutions during import validation. blacklisted_binding: Option<&'a NameBinding<'a>>, /// The idents for the primitive types. diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 65224badc83cd..f0268672082ed 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -42,10 +42,15 @@ use std::{mem, ptr}; #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { SingleImport { + /// `source` in `use prefix::source as target`. source: Ident, + /// `target` in `use prefix::source as target`. target: Ident, + /// Bindings to which `source` refers to. source_bindings: PerNS, Determinacy>>>, + /// Bindings introduced by `target`. target_bindings: PerNS>>>, + /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, }, GlobImport { @@ -946,9 +951,12 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // Consistency checks, analogous to `finalize_current_module_macro_resolutions`. let initial_def = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; - if target.name == "_" && - initial_binding.is_extern_crate() && !initial_binding.is_import() { - this.used_imports.insert((directive.id, TypeNS)); + if let Some(target_binding) = target_bindings[ns].get() { + if target.name == "_" && + initial_binding.is_extern_crate() && !initial_binding.is_import() { + this.record_use(ident, ns, target_binding, + directive.module_path.is_empty()); + } } initial_binding.def_ignoring_ambiguity() });