]> git.lizzy.rs Git - rust.git/commitdiff
resolve: Check resolution consistency for import paths and multi-segment macro paths
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Sat, 10 Nov 2018 15:58:37 +0000 (18:58 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Sun, 18 Nov 2018 10:55:58 +0000 (13:55 +0300)
20 files changed:
src/librustc/hir/def.rs
src/librustc/hir/def_id.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_resolve/resolve_imports.rs
src/libsyntax/ext/base.rs
src/test/ui/extern/extern-macro.rs
src/test/ui/extern/extern-macro.stderr
src/test/ui/macros/macro-path-prelude-fail-2.rs
src/test/ui/macros/macro-path-prelude-fail-2.stderr
src/test/ui/privacy/decl-macro.rs [new file with mode: 0644]
src/test/ui/privacy/decl-macro.stderr [new file with mode: 0644]
src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr
src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs
src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr
src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.rs [new file with mode: 0644]
src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr [new file with mode: 0644]
src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.rs
src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.stderr
src/test/ui/rust-2018/uniform-paths/fn-local-enum.rs [new file with mode: 0644]

index c5e631ebafab1efcb48602f25b39f06f3a10c764..2ca1ff784351c1dd21cbdb5ab5271a89bc7e3421 100644 (file)
@@ -330,6 +330,7 @@ pub fn article(&self) -> &'static str {
         match *self {
             Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::AssociatedExistential(..) |
             Def::Enum(..) | Def::Existential(..) | Def::Err => "an",
+            Def::Macro(.., macro_kind) => macro_kind.article(),
             _ => "a",
         }
     }
index e378e1b8be0e922b6b8e56c52330b4ef411c6f34..319d63f66c465e6184f63e8ddc905abbd2ce0767 100644 (file)
@@ -225,8 +225,8 @@ pub struct DefId {
 
 impl fmt::Debug for DefId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "DefId({:?}/{}:{}",
-               self.krate.index(),
+        write!(f, "DefId({}/{}:{}",
+               self.krate,
                self.index.address_space().index(),
                self.index.as_array_index())?;
 
index 525c75d15c4bbf46e8a4e549f27bd5033a4ae93f..ff222397e59acd0385e9163e92700dc5e1319db1 100644 (file)
@@ -1025,6 +1025,18 @@ enum ModuleOrUniformRoot<'a> {
     UniformRoot(UniformRootKind),
 }
 
+impl<'a> PartialEq for ModuleOrUniformRoot<'a> {
+    fn eq(&self, other: &Self) -> bool {
+        match (*self, *other) {
+            (ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) =>
+                ptr::eq(lhs, rhs),
+            (ModuleOrUniformRoot::UniformRoot(lhs), ModuleOrUniformRoot::UniformRoot(rhs)) =>
+                lhs == rhs,
+            _ => false,
+        }
+    }
+}
+
 #[derive(Clone, Debug)]
 enum PathResult<'a> {
     Module(ModuleOrUniformRoot<'a>),
@@ -1066,9 +1078,10 @@ pub struct ModuleData<'a> {
     normal_ancestor_id: DefId,
 
     resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
-    legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
-                                           Option<&'a NameBinding<'a>>)>>,
-    macro_resolutions: RefCell<Vec<(Vec<Segment>, ParentScope<'a>, Span)>>,
+    single_segment_macro_resolutions: RefCell<Vec<(Ident, MacroKind, ParentScope<'a>,
+                                                   Option<&'a NameBinding<'a>>)>>,
+    multi_segment_macro_resolutions: RefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>,
+                                                  Option<Def>)>>,
     builtin_attrs: RefCell<Vec<(Ident, ParentScope<'a>)>>,
 
     // Macro invocations that can expand into items in this module.
@@ -1106,8 +1119,8 @@ fn new(parent: Option<Module<'a>>,
             kind,
             normal_ancestor_id,
             resolutions: Default::default(),
-            legacy_macro_resolutions: RefCell::new(Vec::new()),
-            macro_resolutions: RefCell::new(Vec::new()),
+            single_segment_macro_resolutions: RefCell::new(Vec::new()),
+            multi_segment_macro_resolutions: RefCell::new(Vec::new()),
             builtin_attrs: RefCell::new(Vec::new()),
             unresolved_invocations: Default::default(),
             no_implicit_prelude: false,
@@ -1503,6 +1516,9 @@ pub struct Resolver<'a, 'b: 'a> {
     /// The current self item if inside an ADT (used for better errors).
     current_self_item: Option<NodeId>,
 
+    /// FIXME: Refactor things so that this is passed through arguments and not resolver.
+    last_import_segment: bool,
+
     /// The idents for the primitive types.
     primitive_type_table: PrimitiveTypeTable,
 
@@ -1852,6 +1868,7 @@ pub fn new(session: &'a Session,
             current_trait_ref: None,
             current_self_type: None,
             current_self_item: None,
+            last_import_segment: false,
 
             primitive_type_table: PrimitiveTypeTable::new(),
 
@@ -1953,27 +1970,23 @@ fn new_module(
         self.arenas.alloc_module(module)
     }
 
-    fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>)
-                  -> bool /* true if an error was reported */ {
+    fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>) {
         match binding.kind {
-            NameBindingKind::Import { directive, binding, ref used }
-                    if !used.get() => {
+            NameBindingKind::Import { directive, binding, ref used } if !used.get() => {
                 used.set(true);
                 directive.used.set(true);
                 self.used_imports.insert((directive.id, ns));
                 self.add_to_glob_map(directive.id, ident);
-                self.record_use(ident, ns, binding)
+                self.record_use(ident, ns, binding);
             }
-            NameBindingKind::Import { .. } => false,
             NameBindingKind::Ambiguity { kind, b1, b2 } => {
                 self.ambiguity_errors.push(AmbiguityError {
                     kind, ident, b1, b2,
                     misc1: AmbiguityErrorMisc::None,
                     misc2: AmbiguityErrorMisc::None,
                 });
-                true
             }
-            _ => false
+            _ => {}
         }
     }
 
@@ -4801,7 +4814,6 @@ fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError) {
 
     fn report_errors(&mut self, krate: &Crate) {
         self.report_with_use_injections(krate);
-        let mut reported_spans = FxHashSet::default();
 
         for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
             let msg = "macro-expanded `macro_export` macros from the current crate \
@@ -4815,11 +4827,10 @@ fn report_errors(&mut self, krate: &Crate) {
         }
 
         for ambiguity_error in &self.ambiguity_errors {
-            if reported_spans.insert(ambiguity_error.ident.span) {
-                self.report_ambiguity_error(ambiguity_error);
-            }
+            self.report_ambiguity_error(ambiguity_error);
         }
 
+        let mut reported_spans = FxHashSet::default();
         for &PrivacyError(dedup_span, ident, binding) in &self.privacy_errors {
             if reported_spans.insert(dedup_span) {
                 span_err!(self.session, ident.span, E0603, "{} `{}` is private",
index 37d6773c9c4f81e1173e849e877b29a7ee24cf4a..a795ba0e9d15df1481ec7604120a3aa77bd5639d 100644 (file)
@@ -9,8 +9,9 @@
 // except according to those terms.
 
 use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
-use {CrateLint, DeterminacyExt, Resolver, ResolutionError, is_known_tool, resolve_error};
+use {CrateLint, DeterminacyExt, Resolver, ResolutionError};
 use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
+use {is_known_tool, names_to_string, resolve_error};
 use ModuleOrUniformRoot;
 use Namespace::{self, *};
 use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
@@ -480,29 +481,19 @@ pub fn resolve_macro_to_def_inner(
         if path.len() > 1 {
             let def = match self.resolve_path(&path, Some(MacroNS), parent_scope,
                                               false, path_span, CrateLint::No) {
-                PathResult::NonModule(path_res) => match path_res.base_def() {
-                    Def::Err => Err(Determinacy::Determined),
-                    def @ _ => {
-                        if path_res.unresolved_segments() > 0 {
-                            self.found_unresolved_macro = true;
-                            self.session.span_err(path_span,
-                                                  "fail to resolve non-ident macro path");
-                            Err(Determinacy::Determined)
-                        } else {
-                            Ok(def)
-                        }
-                    }
-                },
-                PathResult::Module(..) => unreachable!(),
+                PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
+                    Ok(path_res.base_def())
+                }
                 PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
-                _ => {
+                PathResult::NonModule(..) | PathResult::Indeterminate | PathResult::Failed(..) => {
                     self.found_unresolved_macro = true;
                     Err(Determinacy::Determined)
-                },
+                }
+                PathResult::Module(..) => unreachable!(),
             };
 
-            parent_scope.module.macro_resolutions.borrow_mut()
-                .push((path, parent_scope.clone(), path_span));
+            parent_scope.module.multi_segment_macro_resolutions.borrow_mut()
+                .push((path, path_span, kind, parent_scope.clone(), def.ok()));
 
             def
         } else {
@@ -515,7 +506,7 @@ pub fn resolve_macro_to_def_inner(
                 Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
             }
 
-            parent_scope.module.legacy_macro_resolutions.borrow_mut()
+            parent_scope.module.single_segment_macro_resolutions.borrow_mut()
                 .push((path[0].ident, kind, parent_scope.clone(), binding.ok()));
 
             binding.map(|binding| binding.def_ignoring_ambiguity())
@@ -922,50 +913,68 @@ struct Flags: u8 {
     pub fn finalize_current_module_macro_resolutions(&mut self) {
         let module = self.current_module;
 
+        let check_consistency = |this: &mut Self, path: &[Ident], span,
+                                 kind: MacroKind, initial_def, def| {
+            if let Some(initial_def) = initial_def {
+                if def != initial_def && def != Def::Err && this.ambiguity_errors.is_empty() {
+                    // Make sure compilation does not succeed if preferred macro resolution
+                    // has changed after the macro had been expanded. In theory all such
+                    // situations should be reported as ambiguity errors, so this is a bug.
+                    span_bug!(span, "inconsistent resolution for a macro");
+                }
+            } else {
+                // It's possible that the macro was unresolved (indeterminate) and silently
+                // expanded into a dummy fragment for recovery during expansion.
+                // Now, post-expansion, the resolution may succeed, but we can't change the
+                // past and need to report an error.
+                // However, non-speculative `resolve_path` can successfully return private items
+                // even if speculative `resolve_path` returned nothing previously, so we skip this
+                // less informative error if the privacy error is reported elsewhere.
+                if this.privacy_errors.is_empty() {
+                    let msg = format!("cannot determine resolution for the {} `{}`",
+                                        kind.descr(), names_to_string(path));
+                    let msg_note = "import resolution is stuck, try simplifying macro imports";
+                    this.session.struct_span_err(span, &msg).note(msg_note).emit();
+                }
+            }
+        };
+
         let macro_resolutions =
-            mem::replace(&mut *module.macro_resolutions.borrow_mut(), Vec::new());
-        for (mut path, parent_scope, path_span) in macro_resolutions {
+            mem::replace(&mut *module.multi_segment_macro_resolutions.borrow_mut(), Vec::new());
+        for (mut path, path_span, kind, parent_scope, initial_def) in macro_resolutions {
             // FIXME: Path resolution will ICE if segment IDs present.
             for seg in &mut path { seg.id = None; }
             match self.resolve_path(&path, Some(MacroNS), &parent_scope,
                                     true, path_span, CrateLint::No) {
-                PathResult::NonModule(_) => {},
-                PathResult::Failed(span, msg, _) => {
+                PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
+                    let def = path_res.base_def();
+                    check_consistency(self, &path, path_span, kind, initial_def, def);
+                }
+                path_res @ PathResult::NonModule(..) | path_res @  PathResult::Failed(..) => {
+                    let (span, msg) = if let PathResult::Failed(span, msg, ..) = path_res {
+                        (span, msg)
+                    } else {
+                        (path_span, format!("partially resolved path in {} {}",
+                                            kind.article(), kind.descr()))
+                    };
                     resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
                 }
-                _ => unreachable!(),
+                PathResult::Module(..) | PathResult::Indeterminate => unreachable!(),
             }
         }
 
-        let legacy_macro_resolutions =
-            mem::replace(&mut *module.legacy_macro_resolutions.borrow_mut(), Vec::new());
-        for (ident, kind, parent_scope, initial_binding) in legacy_macro_resolutions {
-            let binding = self.early_resolve_ident_in_lexical_scope(
-                ident, MacroNS, Some(kind), false, &parent_scope, true, true, ident.span
-            );
-            match binding {
+        let macro_resolutions =
+            mem::replace(&mut *module.single_segment_macro_resolutions.borrow_mut(), Vec::new());
+        for (ident, kind, parent_scope, initial_binding) in macro_resolutions {
+            match self.early_resolve_ident_in_lexical_scope(ident, MacroNS, Some(kind), false,
+                                                            &parent_scope, true, true, ident.span) {
                 Ok(binding) => {
-                    let def = binding.def_ignoring_ambiguity();
-                    if let Some(initial_binding) = initial_binding {
+                    let initial_def = initial_binding.map(|initial_binding| {
                         self.record_use(ident, MacroNS, initial_binding);
-                        let initial_def = initial_binding.def_ignoring_ambiguity();
-                        if self.ambiguity_errors.is_empty() &&
-                           def != initial_def && def != Def::Err {
-                            // Make sure compilation does not succeed if preferred macro resolution
-                            // has changed after the macro had been expanded. In theory all such
-                            // situations should be reported as ambiguity errors, so this is a bug.
-                            span_bug!(ident.span, "inconsistent resolution for a macro");
-                        }
-                    } else {
-                        // It's possible that the macro was unresolved (indeterminate) and silently
-                        // expanded into a dummy fragment for recovery during expansion.
-                        // Now, post-expansion, the resolution may succeed, but we can't change the
-                        // past and need to report an error.
-                        let msg = format!("cannot determine resolution for the {} `{}`",
-                                          kind.descr(), ident);
-                        let msg_note = "import resolution is stuck, try simplifying macro imports";
-                        self.session.struct_span_err(ident.span, &msg).note(msg_note).emit();
-                    }
+                        initial_binding.def_ignoring_ambiguity()
+                    });
+                    let def = binding.def_ignoring_ambiguity();
+                    check_consistency(self, &[ident], ident.span, kind, initial_def, def);
                 }
                 Err(..) => {
                     assert!(initial_binding.is_none());
index 15cf95b7ba74dac920c932395e7e05377c837112..d98562db3ec8cf11bee814fa1e3300af44731bff 100644 (file)
@@ -222,40 +222,47 @@ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
             }
         }
 
-        if record_used {
-            if let Some(binding) = resolution.binding {
-                if let Some(shadowed_glob) = resolution.shadowed_glob {
-                    // Forbid expanded shadowing to avoid time travel.
-                    if restricted_shadowing &&
-                       binding.expansion != Mark::root() &&
-                       binding.def() != shadowed_glob.def() {
-                        self.ambiguity_errors.push(AmbiguityError {
-                            kind: AmbiguityKind::GlobVsExpanded,
-                            ident,
-                            b1: binding,
-                            b2: shadowed_glob,
-                            misc1: AmbiguityErrorMisc::None,
-                            misc2: AmbiguityErrorMisc::None,
-                        });
-                    }
-                }
-                if self.record_use(ident, ns, binding) {
-                    return Ok(self.dummy_binding);
-                }
-                if !self.is_accessible(binding.vis) {
-                    self.privacy_errors.push(PrivacyError(path_span, ident, binding));
-                }
-            }
-
-            return resolution.binding.ok_or(DeterminacyExt::Determined);
-        }
-
         let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
-            // `extern crate` are always usable for backwards compatibility, see issue #37020.
+            // `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();
             if usable { Ok(binding) } else { Err(DeterminacyExt::Determined) }
         };
 
+        if record_used {
+            return resolution.binding.ok_or(DeterminacyExt::Determined).and_then(|binding| {
+                if self.last_import_segment && check_usable(self, binding).is_err() {
+                    Err(DeterminacyExt::Determined)
+                } else {
+                    self.record_use(ident, ns, binding);
+
+                    if let Some(shadowed_glob) = resolution.shadowed_glob {
+                        // Forbid expanded shadowing to avoid time travel.
+                        if restricted_shadowing &&
+                        binding.expansion != Mark::root() &&
+                        binding.def() != shadowed_glob.def() {
+                            self.ambiguity_errors.push(AmbiguityError {
+                                kind: AmbiguityKind::GlobVsExpanded,
+                                ident,
+                                b1: binding,
+                                b2: shadowed_glob,
+                                misc1: AmbiguityErrorMisc::None,
+                                misc2: AmbiguityErrorMisc::None,
+                            });
+                        }
+                    }
+
+                    if !self.is_accessible(binding.vis) &&
+                       // Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
+                       !(self.last_import_segment && binding.is_extern_crate()) {
+                        self.privacy_errors.push(PrivacyError(path_span, ident, binding));
+                    }
+
+                    Ok(binding)
+                }
+            })
+        }
+
         // Items and single imports are not shadowable, if we have one, then it's determined.
         if let Some(binding) = resolution.binding {
             if !binding.is_glob_import() {
@@ -628,8 +635,7 @@ pub fn finalize_imports(&mut self) {
         let mut prev_root_id: NodeId = NodeId::from_u32(0);
         for i in 0 .. self.determined_imports.len() {
             let import = self.determined_imports[i];
-            let error = self.finalize_import(import);
-            if let Some((span, err, note)) = error {
+            if let Some((span, err, note)) = self.finalize_import(import) {
                 errors = true;
 
                 if let SingleImport { source, ref result, .. } = import.subclass {
@@ -726,7 +732,7 @@ fn throw_unresolved_import_error(
     /// If successful, the resolved bindings are written into the module.
     fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
         debug!("(resolving import for module) resolving import `{}::...` in `{}`",
-               Segment::names_to_string(&directive.module_path[..]),
+               Segment::names_to_string(&directive.module_path),
                module_to_string(self.current_module).unwrap_or_else(|| "???".to_string()));
 
         self.current_module = directive.parent_scope.module;
@@ -737,8 +743,8 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
             // 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);
-            let result = self.resolve_path(
-                &directive.module_path[..],
+            let path_res = self.resolve_path(
+                &directive.module_path,
                 None,
                 &directive.parent_scope,
                 false,
@@ -747,10 +753,10 @@ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
             );
             directive.vis.set(orig_vis);
 
-            match result {
+            match path_res {
                 PathResult::Module(module) => module,
                 PathResult::Indeterminate => return false,
-                _ => return true,
+                PathResult::NonModule(..) | PathResult::Failed(..) => return true,
             }
         };
 
@@ -817,25 +823,37 @@ fn finalize_import(
         directive: &'b ImportDirective<'b>
     ) -> Option<(Span, String, Option<String>)> {
         self.current_module = directive.parent_scope.module;
-        let ImportDirective { ref module_path, span, .. } = *directive;
 
-        let module_result = self.resolve_path(
-            &module_path,
-            None,
-            &directive.parent_scope,
-            true,
-            span,
-            directive.crate_lint(),
-        );
-        let module = match module_result {
-            PathResult::Module(module) => module,
+        let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
+        let path_res = self.resolve_path(&directive.module_path, None, &directive.parent_scope,
+                                         true, directive.span, directive.crate_lint());
+        directive.vis.set(orig_vis);
+        let module = match path_res {
+            PathResult::Module(module) => {
+                // Consistency checks, analogous to `finalize_current_module_macro_resolutions`.
+                if let Some(initial_module) = directive.imported_module.get() {
+                    if module != initial_module && self.ambiguity_errors.is_empty() {
+                        span_bug!(directive.span, "inconsistent resolution for an import");
+                    }
+                } else {
+                    if self.privacy_errors.is_empty() {
+                        let msg = "cannot determine resolution for the import";
+                        let msg_note = "import resolution is stuck, try simplifying other imports";
+                        self.session.struct_span_err(directive.span, msg).note(msg_note).emit();
+                    }
+                }
+
+                module
+            }
             PathResult::Failed(span, msg, false) => {
+                assert!(directive.imported_module.get().is_none());
                 resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
                 return None;
             }
             PathResult::Failed(span, msg, true) => {
+                assert!(directive.imported_module.get().is_none());
                 return if let Some((suggested_path, note)) = self.make_path_suggestion(
-                    span, module_path.clone(), &directive.parent_scope
+                    span, directive.module_path.clone(), &directive.parent_scope
                 ) {
                     Some((
                         span,
@@ -845,17 +863,22 @@ fn finalize_import(
                 } else {
                     Some((span, msg, None))
                 };
-            },
-            _ => return None,
+            }
+            PathResult::NonModule(path_res) if path_res.base_def() == Def::Err => {
+                // The error was already reported earlier.
+                assert!(directive.imported_module.get().is_none());
+                return None;
+            }
+            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),
             GlobImport { is_prelude, ref max_vis } => {
-                if module_path.len() <= 1 {
+                if directive.module_path.len() <= 1 {
                     // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
                     // 2 segments, so the `resolve_path` above won't trigger it.
-                    let mut full_path = module_path.clone();
+                    let mut full_path = directive.module_path.clone();
                     full_path.push(Segment::from_ident(keywords::Invalid.ident()));
                     self.lint_if_path_starts_with_module(
                         directive.crate_lint(),
@@ -888,20 +911,39 @@ fn finalize_import(
 
         let mut all_ns_err = true;
         self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
-            if let Ok(binding) = result[ns].get() {
-                all_ns_err = false;
-                if this.record_use(ident, ns, binding) {
-                    if let ModuleOrUniformRoot::Module(module) = module {
-                        this.resolution(module, ident, ns).borrow_mut().binding =
-                            Some(this.dummy_binding);
+            let orig_vis = directive.vis.replace(ty::Visibility::Invisible);
+            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;
+            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| {
+                        all_ns_err = false;
+                        this.record_use(ident, MacroNS, initial_binding);
+                        initial_binding.def_ignoring_ambiguity()
+                    });
+                    let def = binding.def_ignoring_ambiguity();
+                    if let Ok(initial_def) = initial_def {
+                        if def != initial_def && this.ambiguity_errors.is_empty() {
+                            span_bug!(directive.span, "inconsistent resolution for an import");
+                        }
+                    } else {
+                        if def != Def::Err &&
+                           this.ambiguity_errors.is_empty() && this.privacy_errors.is_empty() {
+                            let msg = "cannot determine resolution for the import";
+                            let msg_note =
+                                "import resolution is stuck, try simplifying other imports";
+                            this.session.struct_span_err(directive.span, msg).note(msg_note).emit();
+                        }
                     }
                 }
-                if 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);
-                    }
+                Err(..) => {
+                    assert!(result[ns].get().is_err());
                 }
             }
         });
@@ -910,7 +952,7 @@ fn finalize_import(
             let mut all_ns_failed = true;
             self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
                 let binding = this.resolve_ident_in_module(
-                    module, ident, ns, Some(&directive.parent_scope), true, span
+                    module, ident, ns, Some(&directive.parent_scope), true, directive.span
                 );
                 if binding.is_ok() {
                     all_ns_failed = false;
@@ -969,7 +1011,7 @@ fn finalize_import(
                         }
                     }
                 };
-                Some((span, msg, None))
+                Some((directive.span, msg, None))
             } else {
                 // `resolve_ident_in_module` reported a privacy error.
                 self.import_dummy_binding(directive);
@@ -1018,10 +1060,10 @@ fn finalize_import(
             }
         }
 
-        if module_path.len() <= 1 {
+        if directive.module_path.len() <= 1 {
             // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
             // 2 segments, so the `resolve_path` above won't trigger it.
-            let mut full_path = module_path.clone();
+            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() {
index 88ee80e60888f93a2d8cace0b01a332e29443aa5..bb927b62a181ed779e94b8393c4d2e5e4c88f918 100644 (file)
@@ -595,6 +595,13 @@ pub fn descr(self) -> &'static str {
             MacroKind::ProcMacroStub => "crate-local procedural macro",
         }
     }
+
+    pub fn article(self) -> &'static str {
+        match self {
+            MacroKind::Attr => "an",
+            _ => "a",
+        }
+    }
 }
 
 /// An enum representing the different kinds of syntax extensions.
index 4b1bf7d8f7923ff4438ed51bdddef297bb7a081c..fcba5cb4f07a16c26f0abd27982edbac959a659f 100644 (file)
@@ -12,5 +12,5 @@
 
 fn main() {
     enum Foo {}
-    let _ = Foo::bar!(); //~ ERROR fail to resolve non-ident macro path
+    let _ = Foo::bar!(); //~ ERROR failed to resolve. partially resolved path in a macro
 }
index b5515bfcc64232c7c45ea732945ed0db026eaf9b..159fefdd2696b96b57f527ac29c8713a162762ad 100644 (file)
@@ -1,8 +1,9 @@
-error: fail to resolve non-ident macro path
+error[E0433]: failed to resolve. partially resolved path in a macro
   --> $DIR/extern-macro.rs:15:13
    |
-LL |     let _ = Foo::bar!(); //~ ERROR fail to resolve non-ident macro path
-   |             ^^^^^^^^
+LL |     let _ = Foo::bar!(); //~ ERROR failed to resolve. partially resolved path in a macro
+   |             ^^^^^^^^ partially resolved path in a macro
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0433`.
index 82258dac37b86bf9b64cf0b99ebf37fb6041c72a..d9f99aa0119ce91b8b75879b20c0aa834e834397 100644 (file)
@@ -10,7 +10,7 @@
 
 mod m {
     fn check() {
-        Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
+        Result::Ok!(); //~ ERROR failed to resolve. partially resolved path in a macro
     }
 }
 
index 876ee2584e9aa8287f74bb50f93960b3c54e9ab0..31e45b320ad73f13f1c83c30fa1150b060f3e769 100644 (file)
@@ -1,8 +1,9 @@
-error: fail to resolve non-ident macro path
+error[E0433]: failed to resolve. partially resolved path in a macro
   --> $DIR/macro-path-prelude-fail-2.rs:13:9
    |
-LL |         Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
-   |         ^^^^^^^^^^
+LL |         Result::Ok!(); //~ ERROR failed to resolve. partially resolved path in a macro
+   |         ^^^^^^^^^^ partially resolved path in a macro
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/ui/privacy/decl-macro.rs b/src/test/ui/privacy/decl-macro.rs
new file mode 100644 (file)
index 0000000..1eb49bd
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(decl_macro)]
+
+mod m {
+    macro mac() {}
+}
+
+fn main() {
+    m::mac!(); //~ ERROR macro `mac` is private
+}
diff --git a/src/test/ui/privacy/decl-macro.stderr b/src/test/ui/privacy/decl-macro.stderr
new file mode 100644 (file)
index 0000000..c8b043d
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0603]: macro `mac` is private
+  --> $DIR/decl-macro.rs:8:8
+   |
+LL |     m::mac!(); //~ ERROR macro `mac` is private
+   |        ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
index 1a8ceec5dac068ddd8a4bffbc2f7e16686910ce4..ba44f20facfd209033fe31766be887bf6f96461c 100644 (file)
@@ -2,7 +2,7 @@ error[E0432]: unresolved import `xcrate`
   --> $DIR/non-existent-1.rs:13:5
    |
 LL | use xcrate::S; //~ ERROR unresolved import `xcrate`
-   |     ^^^^^^ Could not find `xcrate` in `{{root}}`
+   |     ^^^^^^ Use of undeclared type or module `xcrate`
 
 error: aborting due to previous error
 
index ca488fec5162de71299105f3e913850c2599e880..2853b4b3a5b3f6c9dc4c242df7efe5ab3c95b389 100644 (file)
@@ -16,6 +16,6 @@ fn main() {
     fn std() {}
     enum std {}
     use std as foo;
-    //~^ ERROR `std` import is ambiguous
-    //~| ERROR `std` import is ambiguous
+    //~^ ERROR `std` is ambiguous
+    //~| ERROR `std` is ambiguous
 }
index 27e0e883691272dab890cab8fc4b1b643a014bca..d0e3d002b0885181907d9f3f0124e7ffe37b797f 100644 (file)
@@ -1,31 +1,39 @@
-error: `std` import is ambiguous
+error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
   --> $DIR/block-scoped-shadow.rs:18:9
    |
-LL | struct std;
-   | ----------- may refer to `self::std` in the future
-...
-LL |     enum std {}
-   |     ----------- shadowed by block-scoped `std`
 LL |     use std as foo;
-   |         ^^^ can refer to external crate `::std`
+   |         ^^^ ambiguous name
    |
-   = help: write `::std` or `self::std` explicitly instead
-   = note: in the future, `#![feature(uniform_paths)]` may become the default
+note: `std` could refer to the enum defined here
+  --> $DIR/block-scoped-shadow.rs:17:5
+   |
+LL |     enum std {}
+   |     ^^^^^^^^^^^
+note: `std` could also refer to the struct defined here
+  --> $DIR/block-scoped-shadow.rs:13:1
+   |
+LL | struct std;
+   | ^^^^^^^^^^^
+   = help: use `self::std` to refer to the struct unambiguously
 
-error: `std` import is ambiguous
+error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
   --> $DIR/block-scoped-shadow.rs:18:9
    |
-LL | struct std;
-   | ----------- may refer to `self::std` in the future
-...
-LL |     fn std() {}
-   |     ----------- shadowed by block-scoped `std`
-LL |     enum std {}
 LL |     use std as foo;
-   |         ^^^
+   |         ^^^ ambiguous name
+   |
+note: `std` could refer to the function defined here
+  --> $DIR/block-scoped-shadow.rs:16:5
    |
-   = help: write `self::std` explicitly instead
-   = note: in the future, `#![feature(uniform_paths)]` may become the default
+LL |     fn std() {}
+   |     ^^^^^^^^^^^
+note: `std` could also refer to the unit struct defined here
+  --> $DIR/block-scoped-shadow.rs:13:1
+   |
+LL | struct std;
+   | ^^^^^^^^^^^
+   = help: use `self::std` to refer to the unit struct unambiguously
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.rs b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.rs
new file mode 100644 (file)
index 0000000..3f58979
--- /dev/null
@@ -0,0 +1,20 @@
+// edition:2018
+
+mod my {
+    pub mod sub {
+        pub fn bar() {}
+    }
+}
+
+mod sub {
+    pub fn bar() {}
+}
+
+fn foo() {
+    use my::sub;
+    {
+        use sub::bar; //~ ERROR `sub` is ambiguous
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr
new file mode 100644 (file)
index 0000000..32f5cb3
--- /dev/null
@@ -0,0 +1,23 @@
+error[E0659]: `sub` is ambiguous (name vs any other name during import resolution)
+  --> $DIR/block-scoped-shadow-nested.rs:16:13
+   |
+LL |         use sub::bar; //~ ERROR `sub` is ambiguous
+   |             ^^^ ambiguous name
+   |
+note: `sub` could refer to the module imported here
+  --> $DIR/block-scoped-shadow-nested.rs:14:9
+   |
+LL |     use my::sub;
+   |         ^^^^^^^
+note: `sub` could also refer to the module defined here
+  --> $DIR/block-scoped-shadow-nested.rs:9:1
+   |
+LL | / mod sub {
+LL | |     pub fn bar() {}
+LL | | }
+   | |_^
+   = help: use `self::sub` to refer to the module unambiguously
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
index ee141d444b2cf36e5dc08a5cdf4100d5b347564e..36d996fc4f930753dc4f6e73ffcebfb63bfada25 100644 (file)
 
 #![feature(uniform_paths)]
 
-enum Foo { A, B }
+enum Foo {}
 
 struct std;
 
 fn main() {
-    enum Foo {}
+    enum Foo { A, B }
     use Foo::*;
-    //~^ ERROR `Foo` import is ambiguous
+    //~^ ERROR `Foo` is ambiguous
 
     let _ = (A, B);
 
     fn std() {}
     enum std {}
     use std as foo;
-    //~^ ERROR `std` import is ambiguous
-    //~| ERROR `std` import is ambiguous
+    //~^ ERROR `std` is ambiguous
+    //~| ERROR `std` is ambiguous
 }
index 86d95f2ac4567234c60af0942dd13be8b4ec5193..a1db1c3e0be6c8f3e93912d6e8c4de168cde6454 100644 (file)
@@ -1,45 +1,57 @@
-error: `Foo` import is ambiguous
+error[E0659]: `Foo` is ambiguous (name vs any other name during import resolution)
   --> $DIR/block-scoped-shadow.rs:21:9
    |
-LL | enum Foo { A, B }
-   | ----------------- can refer to `self::Foo`
-...
-LL |     enum Foo {}
-   |     ----------- shadowed by block-scoped `Foo`
 LL |     use Foo::*;
-   |         ^^^
+   |         ^^^ ambiguous name
    |
-   = help: write `self::Foo` explicitly instead
-   = note: relative `use` paths enabled by `#![feature(uniform_paths)]`
+note: `Foo` could refer to the enum defined here
+  --> $DIR/block-scoped-shadow.rs:20:5
+   |
+LL |     enum Foo { A, B }
+   |     ^^^^^^^^^^^^^^^^^
+note: `Foo` could also refer to the enum defined here
+  --> $DIR/block-scoped-shadow.rs:15:1
+   |
+LL | enum Foo {}
+   | ^^^^^^^^^^^
+   = help: use `self::Foo` to refer to the enum unambiguously
 
-error: `std` import is ambiguous
+error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
   --> $DIR/block-scoped-shadow.rs:28:9
    |
-LL | struct std;
-   | ----------- can refer to `self::std`
-...
-LL |     enum std {}
-   |     ----------- shadowed by block-scoped `std`
 LL |     use std as foo;
-   |         ^^^ can refer to external crate `::std`
+   |         ^^^ ambiguous name
    |
-   = help: write `::std` or `self::std` explicitly instead
-   = note: relative `use` paths enabled by `#![feature(uniform_paths)]`
+note: `std` could refer to the enum defined here
+  --> $DIR/block-scoped-shadow.rs:27:5
+   |
+LL |     enum std {}
+   |     ^^^^^^^^^^^
+note: `std` could also refer to the struct defined here
+  --> $DIR/block-scoped-shadow.rs:17:1
+   |
+LL | struct std;
+   | ^^^^^^^^^^^
+   = help: use `self::std` to refer to the struct unambiguously
 
-error: `std` import is ambiguous
+error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
   --> $DIR/block-scoped-shadow.rs:28:9
    |
-LL | struct std;
-   | ----------- can refer to `self::std`
-...
-LL |     fn std() {}
-   |     ----------- shadowed by block-scoped `std`
-LL |     enum std {}
 LL |     use std as foo;
-   |         ^^^
+   |         ^^^ ambiguous name
+   |
+note: `std` could refer to the function defined here
+  --> $DIR/block-scoped-shadow.rs:26:5
    |
-   = help: write `self::std` explicitly instead
-   = note: relative `use` paths enabled by `#![feature(uniform_paths)]`
+LL |     fn std() {}
+   |     ^^^^^^^^^^^
+note: `std` could also refer to the unit struct defined here
+  --> $DIR/block-scoped-shadow.rs:17:1
+   |
+LL | struct std;
+   | ^^^^^^^^^^^
+   = help: use `self::std` to refer to the unit struct unambiguously
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0659`.
diff --git a/src/test/ui/rust-2018/uniform-paths/fn-local-enum.rs b/src/test/ui/rust-2018/uniform-paths/fn-local-enum.rs
new file mode 100644 (file)
index 0000000..0c2da18
--- /dev/null
@@ -0,0 +1,13 @@
+// compile-pass
+// edition:2018
+
+fn main() {
+    enum E { A, B, C }
+
+    use E::*;
+    match A {
+        A => {}
+        B => {}
+        C => {}
+    }
+}