diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3f0780191fb2..2966e9ec9d9f 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -132,9 +132,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // so prefixes are prepended with crate root segment if necessary. // The root is prepended lazily, when the first non-empty prefix or terminating glob // appears, so imports in braced groups can have roots prepended independently. + // 2015 identifiers used on global 2018 edition enter special "virtual 2015 mode", don't + // get crate root prepended, but get special treatment during in-scope resolution instead. let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false }; let crate_root = match prefix_iter.peek() { - Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => { + Some(seg) if !seg.ident.is_path_segment_keyword() && + seg.ident.span.rust_2015() && self.session.rust_2015() => { Some(seg.ident.span.ctxt()) } None if is_glob && use_tree.span.rust_2015() => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2e7ed80c91bb..07ded5c6723f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -13,6 +13,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(crate_visibility_modifier)] +#![feature(label_break_value)] #![feature(nll)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] @@ -2191,28 +2192,45 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { fn resolve_ident_in_module( &mut self, module: ModuleOrUniformRoot<'a>, - mut ident: Ident, + ident: Ident, ns: Namespace, parent_scope: Option<&ParentScope<'a>>, record_used: bool, path_span: Span ) -> Result<&'a NameBinding<'a>, Determinacy> { - ident.span = ident.span.modern(); + self.resolve_ident_in_module_ext( + module, ident, ns, parent_scope, record_used, path_span + ).map_err(|(determinacy, _)| determinacy) + } + + fn resolve_ident_in_module_ext( + &mut self, + module: ModuleOrUniformRoot<'a>, + mut ident: Ident, + ns: Namespace, + parent_scope: Option<&ParentScope<'a>>, + record_used: bool, + path_span: Span + ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> { let orig_current_module = self.current_module; match module { ModuleOrUniformRoot::Module(module) => { + ident.span = ident.span.modern(); if let Some(def) = ident.span.adjust(module.expansion) { self.current_module = self.macro_def_scope(def); } } ModuleOrUniformRoot::UniformRoot(UniformRootKind::ExternPrelude) => { + ident.span = ident.span.modern(); ident.span.adjust(Mark::root()); } - _ => {} + ModuleOrUniformRoot::UniformRoot(UniformRootKind::CurrentScope) => { + // No adjustments + } } let result = self.resolve_ident_in_module_unadjusted_ext( module, ident, ns, parent_scope, false, record_used, path_span, - ).map_err(|(determinacy, _)| determinacy); + ); self.current_module = orig_current_module; result } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 6fa9110fedb7..bc3700b8c631 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -526,7 +526,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. crate fn early_resolve_ident_in_lexical_scope( &mut self, - mut ident: Ident, + orig_ident: Ident, ns: Namespace, macro_kind: Option, is_import: bool, @@ -582,6 +582,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { enum WhereToResolve<'a> { DeriveHelpers, MacroRules(LegacyScope<'a>), + CrateRoot, Module(Module<'a>), MacroUsePrelude, BuiltinMacros, @@ -605,8 +606,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> { assert!(force || !record_used); // `record_used` implies `force` assert!(macro_kind.is_none() || !is_import); // `is_import` implies no macro kind - let rust_2015 = ident.span.rust_2015(); - ident = ident.modern(); + let rust_2015 = orig_ident.span.rust_2015(); + let mut ident = orig_ident.modern(); // Make sure `self`, `super` etc produce an error when passed to here. if ident.is_path_segment_keyword() { @@ -627,10 +628,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let mut innermost_result: Option<(&NameBinding, Flags)> = None; // Go through all the scopes and try to resolve the name. - let mut where_to_resolve = if ns == MacroNS { - WhereToResolve::DeriveHelpers - } else { - WhereToResolve::Module(parent_scope.module) + let mut where_to_resolve = match ns { + _ if is_import && rust_2015 => WhereToResolve::CrateRoot, + TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module), + MacroNS => WhereToResolve::DeriveHelpers, }; let mut use_prelude = !parent_scope.module.no_implicit_prelude; let mut determinacy = Determinacy::Determined; @@ -668,6 +669,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> { Err(Determinacy::Undetermined), _ => Err(Determinacy::Determined), } + WhereToResolve::CrateRoot => { + let root_ident = Ident::new(keywords::CrateRoot.name(), orig_ident.span); + let root_module = self.resolve_crate_root(root_ident); + let binding = self.resolve_ident_in_module_ext( + ModuleOrUniformRoot::Module(root_module), + orig_ident, + ns, + None, + record_used, + path_span, + ); + match binding { + Ok(binding) => Ok((binding, Flags::MODULE)), + Err((Determinacy::Undetermined, Weak::No)) => + return Err(Determinacy::determined(force)), + Err((Determinacy::Undetermined, Weak::Yes)) => + Err(Determinacy::Undetermined), + Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), + } + } WhereToResolve::Module(module) => { let orig_current_module = mem::replace(&mut self.current_module, module); let binding = self.resolve_ident_in_module_unadjusted_ext( @@ -816,7 +837,11 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } else if innermost_flags.contains(Flags::MACRO_RULES) && flags.contains(Flags::MODULE) && !self.disambiguate_legacy_vs_modern(innermost_binding, - binding) { + binding) || + flags.contains(Flags::MACRO_RULES) && + innermost_flags.contains(Flags::MODULE) && + !self.disambiguate_legacy_vs_modern(binding, + innermost_binding) { Some(AmbiguityKind::LegacyVsModern) } else if innermost_binding.is_glob_import() { Some(AmbiguityKind::GlobVsOuter) @@ -867,6 +892,10 @@ impl<'a, 'cl> Resolver<'a, 'cl> { LegacyScope::Empty => WhereToResolve::Module(parent_scope.module), LegacyScope::Uninitialized => unreachable!(), } + WhereToResolve::CrateRoot => match ns { + TypeNS | ValueNS => WhereToResolve::Module(parent_scope.module), + MacroNS => WhereToResolve::DeriveHelpers, + } WhereToResolve::Module(module) => { match self.hygienic_lexical_parent(module, &mut ident.span) { Some(parent_module) => WhereToResolve::Module(parent_module), @@ -899,30 +928,43 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // The first found solution was the only one, return it. if let Some((binding, flags)) = innermost_result { - if is_import && !self.session.features_untracked().uniform_paths { - // We get to here only if there's no ambiguity, in ambiguous cases an error will - // be reported anyway, so there's no reason to report an additional feature error. - // The `binding` can actually be introduced by something other than `--extern`, - // but its `Def` should coincide with a crate passed with `--extern` - // (otherwise there would be ambiguity) and we can skip feature error in this case. - if ns != TypeNS || !use_prelude || - self.extern_prelude_get(ident, true).is_none() { - let msg = "imports can only refer to extern crate names \ - passed with `--extern` on stable channel"; - let mut err = feature_err(&self.session.parse_sess, "uniform_paths", - ident.span, GateIssue::Language, msg); - - 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() { - err.note(¬e_msg); - } else { - err.span_note(binding.span, ¬e_msg); - err.span_label(binding.span, "not an extern crate passed with `--extern`"); - } - err.emit(); + // We get to here only if there's no ambiguity, in ambiguous cases an error will + // be reported anyway, so there's no reason to report an additional feature error. + // The `binding` can actually be introduced by something other than `--extern`, + // but its `Def` should coincide with a crate passed with `--extern` + // (otherwise there would be ambiguity) and we can skip feature error in this case. + 'ok: { + if !is_import || self.session.features_untracked().uniform_paths { + break 'ok; } + if ns == TypeNS && use_prelude && self.extern_prelude_get(ident, true).is_some() { + break 'ok; + } + if rust_2015 { + let root_ident = Ident::new(keywords::CrateRoot.name(), orig_ident.span); + let root_module = self.resolve_crate_root(root_ident); + if self.resolve_ident_in_module_ext(ModuleOrUniformRoot::Module(root_module), + orig_ident, ns, None, false, path_span) + .is_ok() { + break 'ok; + } + } + + let msg = "imports can only refer to extern crate names \ + passed with `--extern` on stable channel"; + let mut err = feature_err(&self.session.parse_sess, "uniform_paths", + ident.span, GateIssue::Language, msg); + + 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() { + err.note(¬e_msg); + } else { + err.span_note(binding.span, ¬e_msg); + err.span_label(binding.span, "not an extern crate passed with `--extern`"); + } + err.emit(); } return Ok(binding); diff --git a/src/test/ui/editions/auxiliary/edition-imports-2015.rs b/src/test/ui/editions/auxiliary/edition-imports-2015.rs index fb1a89d40224..d7985d12dae6 100644 --- a/src/test/ui/editions/auxiliary/edition-imports-2015.rs +++ b/src/test/ui/editions/auxiliary/edition-imports-2015.rs @@ -3,7 +3,7 @@ #[macro_export] macro_rules! gen_imports { () => { use import::Path; - // use std::collections::LinkedList; // FIXME + use std::collections::LinkedList; fn check_absolute() { ::absolute::Path; @@ -15,3 +15,16 @@ macro_rules! gen_imports { () => { macro_rules! gen_glob { () => { use *; }} + +#[macro_export] +macro_rules! gen_gated { () => { + fn check_gated() { + enum E { A } + use E::*; + } +}} + +#[macro_export] +macro_rules! gen_ambiguous { () => { + use Ambiguous; +}} diff --git a/src/test/ui/editions/edition-imports-2018.rs b/src/test/ui/editions/edition-imports-2018.rs index cef4ce3bf167..989170d041fe 100644 --- a/src/test/ui/editions/edition-imports-2018.rs +++ b/src/test/ui/editions/edition-imports-2018.rs @@ -17,7 +17,7 @@ mod check { fn check() { Path; - // LinkedList::::new(); // FIXME + LinkedList::::new(); } } diff --git a/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.rs b/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.rs new file mode 100644 index 000000000000..2527b30f07b3 --- /dev/null +++ b/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.rs @@ -0,0 +1,18 @@ +// edition:2018 +// aux-build:edition-imports-2015.rs +// error-pattern: `Ambiguous` is ambiguous + +#[macro_use] +extern crate edition_imports_2015; + +pub struct Ambiguous {} + +mod check { + pub struct Ambiguous {} + + fn check() { + gen_ambiguous!(); + } +} + +fn main() {} diff --git a/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.stderr b/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.stderr new file mode 100644 index 000000000000..8e0b135121e0 --- /dev/null +++ b/src/test/ui/editions/edition-imports-virtual-2015-ambiguity.stderr @@ -0,0 +1,21 @@ +error[E0659]: `Ambiguous` is ambiguous (name vs any other name during import resolution) + --> <::edition_imports_2015::gen_ambiguous macros>:1:15 + | +LL | ( ) => { use Ambiguous ; } + | ^^^^^^^^^ ambiguous name + | +note: `Ambiguous` could refer to the struct defined here + --> $DIR/edition-imports-virtual-2015-ambiguity.rs:8:1 + | +LL | pub struct Ambiguous {} + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: `Ambiguous` could also refer to the struct defined here + --> $DIR/edition-imports-virtual-2015-ambiguity.rs:11:5 + | +LL | pub struct Ambiguous {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + = help: use `self::Ambiguous` to refer to this struct unambiguously + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/editions/edition-imports-virtual-2015-gated.rs b/src/test/ui/editions/edition-imports-virtual-2015-gated.rs new file mode 100644 index 000000000000..a1bf4f5eb51d --- /dev/null +++ b/src/test/ui/editions/edition-imports-virtual-2015-gated.rs @@ -0,0 +1,12 @@ +// edition:2018 +// aux-build:edition-imports-2015.rs +// error-pattern: imports can only refer to extern crate names passed with `--extern` + +#[macro_use] +extern crate edition_imports_2015; + +mod check { + gen_gated!(); +} + +fn main() {} diff --git a/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr b/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr new file mode 100644 index 000000000000..7c1837e3f56e --- /dev/null +++ b/src/test/ui/editions/edition-imports-virtual-2015-gated.stderr @@ -0,0 +1,22 @@ +error[E0658]: imports can only refer to extern crate names passed with `--extern` on stable channel (see issue #53130) + --> <::edition_imports_2015::gen_gated macros>:1:50 + | +LL | ( ) => { fn check_gated ( ) { enum E { A } use E :: * ; } } + | ^ + | + ::: $DIR/edition-imports-virtual-2015-gated.rs:9:5 + | +LL | gen_gated!(); + | ------------- not an extern crate passed with `--extern` + | + = help: add #![feature(uniform_paths)] to the crate attributes to enable +note: this import refers to the enum defined here + --> $DIR/edition-imports-virtual-2015-gated.rs:9:5 + | +LL | gen_gated!(); + | ^^^^^^^^^^^^^ + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`.