From 4c5d822a8ba8b11c653f48da73c0e281f7245bea Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 10 Nov 2018 18:58:37 +0300 Subject: [PATCH] resolve: Check resolution consistency for import paths and multi-segment macro paths --- src/librustc/hir/def.rs | 1 + src/librustc/hir/def_id.rs | 4 +- src/librustc_resolve/lib.rs | 45 +++-- src/librustc_resolve/macros.rs | 113 ++++++----- src/librustc_resolve/resolve_imports.rs | 178 +++++++++++------- src/libsyntax/ext/base.rs | 7 + src/test/ui/extern/extern-macro.rs | 2 +- src/test/ui/extern/extern-macro.stderr | 7 +- .../ui/macros/macro-path-prelude-fail-2.rs | 2 +- .../macros/macro-path-prelude-fail-2.stderr | 7 +- src/test/ui/privacy/decl-macro.rs | 9 + src/test/ui/privacy/decl-macro.stderr | 9 + .../non-existent-1.stderr | 2 +- .../block-scoped-shadow.rs | 4 +- .../block-scoped-shadow.stderr | 46 +++-- .../block-scoped-shadow-nested.rs | 20 ++ .../block-scoped-shadow-nested.stderr | 23 +++ .../uniform-paths/block-scoped-shadow.rs | 10 +- .../uniform-paths/block-scoped-shadow.stderr | 70 ++++--- .../rust-2018/uniform-paths/fn-local-enum.rs | 13 ++ 20 files changed, 369 insertions(+), 203 deletions(-) create mode 100644 src/test/ui/privacy/decl-macro.rs create mode 100644 src/test/ui/privacy/decl-macro.stderr create mode 100644 src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.rs create mode 100644 src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr create mode 100644 src/test/ui/rust-2018/uniform-paths/fn-local-enum.rs diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index c5e631ebafa..2ca1ff78435 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -330,6 +330,7 @@ impl Def { match *self { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::AssociatedExistential(..) | Def::Enum(..) | Def::Existential(..) | Def::Err => "an", + Def::Macro(.., macro_kind) => macro_kind.article(), _ => "a", } } diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index e378e1b8be0..319d63f66c4 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -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())?; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 525c75d15c4..ff222397e59 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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>>>, - legacy_macro_resolutions: RefCell, - Option<&'a NameBinding<'a>>)>>, - macro_resolutions: RefCell, ParentScope<'a>, Span)>>, + single_segment_macro_resolutions: RefCell, + Option<&'a NameBinding<'a>>)>>, + multi_segment_macro_resolutions: RefCell, Span, MacroKind, ParentScope<'a>, + Option)>>, builtin_attrs: RefCell)>>, // Macro invocations that can expand into items in this module. @@ -1106,8 +1119,8 @@ impl<'a> ModuleData<'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, + /// 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 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { 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 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { 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 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { 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 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } 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", diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 37d6773c9c4..a795ba0e9d1 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -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 @@ impl<'a, 'cl> Resolver<'a, 'cl> { 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 @@ impl<'a, 'cl> Resolver<'a, 'cl> { 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 @@ impl<'a, 'cl> Resolver<'a, 'cl> { 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()); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 15cf95b7ba7..d98562db3ec 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -222,40 +222,47 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { } } - 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { /// 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { ); 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { directive: &'b ImportDirective<'b> ) -> Option<(Span, String, Option)> { 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } 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 @@ 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 { - 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } } }; - 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 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } } - 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() { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 88ee80e6088..bb927b62a18 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -595,6 +595,13 @@ impl MacroKind { 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. diff --git a/src/test/ui/extern/extern-macro.rs b/src/test/ui/extern/extern-macro.rs index 4b1bf7d8f79..fcba5cb4f07 100644 --- a/src/test/ui/extern/extern-macro.rs +++ b/src/test/ui/extern/extern-macro.rs @@ -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 } diff --git a/src/test/ui/extern/extern-macro.stderr b/src/test/ui/extern/extern-macro.stderr index b5515bfcc64..159fefdd269 100644 --- a/src/test/ui/extern/extern-macro.stderr +++ b/src/test/ui/extern/extern-macro.stderr @@ -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`. diff --git a/src/test/ui/macros/macro-path-prelude-fail-2.rs b/src/test/ui/macros/macro-path-prelude-fail-2.rs index 82258dac37b..d9f99aa0119 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-2.rs +++ b/src/test/ui/macros/macro-path-prelude-fail-2.rs @@ -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 } } diff --git a/src/test/ui/macros/macro-path-prelude-fail-2.stderr b/src/test/ui/macros/macro-path-prelude-fail-2.stderr index 876ee2584e9..31e45b320ad 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-2.stderr +++ b/src/test/ui/macros/macro-path-prelude-fail-2.stderr @@ -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 index 00000000000..1eb49bd5301 --- /dev/null +++ b/src/test/ui/privacy/decl-macro.rs @@ -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 index 00000000000..c8b043d1b5f --- /dev/null +++ b/src/test/ui/privacy/decl-macro.stderr @@ -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`. diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr index 1a8ceec5dac..ba44f20facf 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr @@ -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 diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs index ca488fec516..2853b4b3a5b 100644 --- a/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.rs @@ -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 } diff --git a/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr index 27e0e883691..d0e3d002b08 100644 --- a/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr +++ b/src/test/ui/rust-2018/uniform-paths-forward-compat/block-scoped-shadow.stderr @@ -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 | - = help: write `self::std` explicitly instead - = note: in the future, `#![feature(uniform_paths)]` may become the default +note: `std` could refer to the function defined here + --> $DIR/block-scoped-shadow.rs:16:5 + | +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 index 00000000000..3f5897901a0 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.rs @@ -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 index 00000000000..32f5cb30177 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow-nested.stderr @@ -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`. diff --git a/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.rs b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.rs index ee141d444b2..36d996fc4f9 100644 --- a/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.rs +++ b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.rs @@ -12,20 +12,20 @@ #![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 } diff --git a/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.stderr b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.stderr index 86d95f2ac45..a1db1c3e0be 100644 --- a/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.stderr +++ b/src/test/ui/rust-2018/uniform-paths/block-scoped-shadow.stderr @@ -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)]` - -error: `std` import is ambiguous - --> $DIR/block-scoped-shadow.rs:28:9 +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; - | ----------- can refer to `self::std` -... + | ^^^^^^^^^^^ + = help: use `self::std` to refer to the struct unambiguously + +error[E0659]: `std` is ambiguous (name vs any other name during import resolution) + --> $DIR/block-scoped-shadow.rs:28:9 + | +LL | use std as foo; + | ^^^ ambiguous name + | +note: `std` could refer to the function defined here + --> $DIR/block-scoped-shadow.rs:26:5 + | LL | fn std() {} - | ----------- shadowed by block-scoped `std` -LL | enum std {} -LL | use std as foo; - | ^^^ + | ^^^^^^^^^^^ +note: `std` could also refer to the unit struct defined here + --> $DIR/block-scoped-shadow.rs:17:1 | - = help: write `self::std` explicitly instead - = note: relative `use` paths enabled by `#![feature(uniform_paths)]` +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 index 00000000000..0c2da1884b7 --- /dev/null +++ b/src/test/ui/rust-2018/uniform-paths/fn-local-enum.rs @@ -0,0 +1,13 @@ +// compile-pass +// edition:2018 + +fn main() { + enum E { A, B, C } + + use E::*; + match A { + A => {} + B => {} + C => {} + } +}