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 +