about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2018-11-24 15:07:03 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2018-11-27 00:32:34 +0300
commitc06e69ee70bf1fec4630458d8e4417efcabe0424 (patch)
treef4a615546e5f256170db6e7307285ac16e1dc8a3 /src
parentdae4c7b1ff62da4901caf28653baa3133a40496c (diff)
downloadrust-c06e69ee70bf1fec4630458d8e4417efcabe0424.tar.gz
rust-c06e69ee70bf1fec4630458d8e4417efcabe0424.zip
resolve: Fallback to uniform paths in 2015 imports used from global 2018 edition
Diffstat (limited to 'src')
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs5
-rw-r--r--src/librustc_resolve/lib.rs26
-rw-r--r--src/librustc_resolve/macros.rs102
-rw-r--r--src/test/ui/editions/auxiliary/edition-imports-2015.rs15
-rw-r--r--src/test/ui/editions/edition-imports-2018.rs2
-rw-r--r--src/test/ui/editions/edition-imports-virtual-2015-ambiguity.rs18
-rw-r--r--src/test/ui/editions/edition-imports-virtual-2015-ambiguity.stderr21
-rw-r--r--src/test/ui/editions/edition-imports-virtual-2015-gated.rs12
-rw-r--r--src/test/ui/editions/edition-imports-virtual-2015-gated.stderr22
9 files changed, 186 insertions, 37 deletions
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 3f0780191fb..2966e9ec9d9 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 2e7ed80c91b..07ded5c6723 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 6fa9110fedb..bc3700b8c63 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<MacroKind>,
         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(&note_msg);
-                    } else {
-                        err.span_note(binding.span, &note_msg);
-                        err.span_label(binding.span, "not an extern crate passed with `--extern`");
+            // 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;
                     }
-                    err.emit();
                 }
+
+                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(&note_msg);
+                } else {
+                    err.span_note(binding.span, &note_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 fb1a89d4022..d7985d12dae 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 cef4ce3bf16..989170d041f 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::<u8>::new(); // FIXME
+        LinkedList::<u8>::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 00000000000..2527b30f07b
--- /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 00000000000..8e0b135121e
--- /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 00000000000..a1bf4f5eb51
--- /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 00000000000..7c1837e3f56
--- /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`.