From 637bfe68a1dc23108e8103034cb1e0590d1a9f6c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Oct 2022 13:35:31 +0400 Subject: [PATCH 1/2] resolve: Not all imports have their own `NodeId` --- .../rustc_resolve/src/build_reduced_graph.rs | 21 +-- compiler/rustc_resolve/src/check_unused.rs | 8 +- compiler/rustc_resolve/src/diagnostics.rs | 2 +- .../src/effective_visibilities.rs | 48 ++++-- compiler/rustc_resolve/src/imports.rs | 153 +++++++++++------- compiler/rustc_resolve/src/lib.rs | 16 +- 6 files changed, 143 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a17793ecd99..5ac562d1663 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -364,7 +364,6 @@ fn add_import( module_path: Vec, kind: ImportKind<'a>, span: Span, - id: NodeId, item: &ast::Item, root_span: Span, root_id: NodeId, @@ -377,7 +376,6 @@ fn add_import( module_path, imported_module: Cell::new(None), span, - id, use_span: item.span, use_span_with_attributes: item.span_with_attributes(), has_attributes: !item.attrs.is_empty(), @@ -574,27 +572,20 @@ fn build_reduced_graph_for_use_tree( }, type_ns_only, nested, + id, additional_ids: (id1, id2), }; - self.add_import( - module_path, - kind, - use_tree.span, - id, - item, - root_span, - item.id, - vis, - ); + self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis); } ast::UseTreeKind::Glob => { let kind = ImportKind::Glob { is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(None), + id, }; self.r.visibilities.insert(self.r.local_def_id(id), vis); - self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis); + self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); } ast::UseTreeKind::Nested(ref items) => { // Ensure there is at most one `self` in the list @@ -881,9 +872,8 @@ fn build_reduced_graph_for_extern_crate( }) .unwrap_or((true, None, self.r.dummy_binding)); let import = self.r.arenas.alloc_import(Import { - kind: ImportKind::ExternCrate { source: orig_name, target: ident }, + kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id }, root_id: item.id, - id: item.id, parent_scope: self.parent_scope, imported_module: Cell::new(module), has_attributes: !item.attrs.is_empty(), @@ -1118,7 +1108,6 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool this.r.arenas.alloc_import(Import { kind: ImportKind::MacroUse, root_id: item.id, - id: item.id, parent_scope: this.parent_scope, imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), use_span_with_attributes: item.span_with_attributes(), diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 01c3801f223..32fb5e18276 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -234,7 +234,7 @@ pub(crate) fn check_unused(&mut self, krate: &ast::Crate) { if !import.span.is_dummy() { self.lint_buffer.buffer_lint( MACRO_USE_EXTERN_CRATE, - import.id, + import.root_id, import.span, "deprecated `#[macro_use]` attribute used to \ import macros should be replaced at use sites \ @@ -244,13 +244,13 @@ pub(crate) fn check_unused(&mut self, krate: &ast::Crate) { } } } - ImportKind::ExternCrate { .. } => { - let def_id = self.local_def_id(import.id); + ImportKind::ExternCrate { id, .. } => { + let def_id = self.local_def_id(id); self.maybe_unused_extern_crates.push((def_id, import.span)); } ImportKind::MacroUse => { let msg = "unused `#[macro_use]` import"; - self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); + self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg); } _ => {} } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5029c339963..bba03a40ed6 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -353,7 +353,7 @@ fn add_suggestion_for_rename_of_use( } } } - ImportKind::ExternCrate { source, target } => { + ImportKind::ExternCrate { source, target, .. } => { suggestion = Some(format!( "extern crate {} as {};", source.unwrap_or(target.name), diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index c40669ac95b..84fa7b89bda 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -57,26 +57,40 @@ fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { while let NameBindingKind::Import { binding: nested_binding, import, .. } = binding.kind { - let mut update = |node_id| self.update( - self.r.local_def_id(node_id), - binding.vis.expect_local(), - prev_parent_id, - level, - ); - // In theory all the import IDs have individual visibilities and effective - // visibilities, but in practice these IDs go straigth to HIR where all - // their few uses assume that their (effective) visibility applies to the - // whole syntactic `use` item. So we update them all to the maximum value - // among the potential individual effective visibilities. Maybe HIR for - // imports shouldn't use three IDs at all. - update(import.id); - if let ImportKind::Single { additional_ids, .. } = import.kind { - update(additional_ids.0); - update(additional_ids.1); + let mut update = |node_id| { + self.update( + self.r.local_def_id(node_id), + binding.vis.expect_local(), + prev_parent_id, + level, + ) + }; + match import.kind { + ImportKind::Single { id, additional_ids, .. } => { + // In theory all the import IDs have individual visibilities and + // effective visibilities, but in practice these IDs go straigth to + // HIR where all their few uses assume that their (effective) + // visibility applies to the whole syntactic `use` item. So we + // update them all to the maximum value among the potential + // individual effective visibilities. Maybe HIR for imports + // shouldn't use three IDs at all. + update(id); + update(additional_ids.0); + update(additional_ids.1); + prev_parent_id = self.r.local_def_id(id); + } + ImportKind::Glob { id, .. } | ImportKind::ExternCrate { id, .. } => { + update(id); + prev_parent_id = self.r.local_def_id(id); + } + ImportKind::MacroUse => { + // In theory we should reset the parent id to something private + // here, but `macro_use` imports always refer to external items, + // so it doesn't matter and we can just do nothing. + } } level = Level::Reexported; - prev_parent_id = self.r.local_def_id(import.id); binding = nested_binding; } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index f2cc50c199f..3b9bf943262 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -44,18 +44,33 @@ pub enum ImportKind<'a> { type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` nested: bool, + /// The ID of the `UseTree` that imported this `Import`. + /// + /// In the case where the `Import` was expanded from a "nested" use tree, + /// this id is the ID of the leaf tree. For example: + /// + /// ```ignore (pacify the merciless tidy) + /// use foo::bar::{a, b} + /// ``` + /// + /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree` + /// for `a` in this field. + id: NodeId, /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement /// (eg. implicit struct constructors) additional_ids: (NodeId, NodeId), }, Glob { is_prelude: bool, - max_vis: Cell>, // The visibility of the greatest re-export. - // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. + // The visibility of the greatest re-export. + // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors. + max_vis: Cell>, + id: NodeId, }, ExternCrate { source: Option, target: Ident, + id: NodeId, }, MacroUse, } @@ -71,6 +86,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ref target, ref type_ns_only, ref nested, + ref id, ref additional_ids, // Ignore the following to avoid an infinite loop while printing. source_bindings: _, @@ -81,17 +97,20 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { .field("target", target) .field("type_ns_only", type_ns_only) .field("nested", nested) + .field("id", id) .field("additional_ids", additional_ids) .finish_non_exhaustive(), - Glob { ref is_prelude, ref max_vis } => f + Glob { ref is_prelude, ref max_vis, ref id } => f .debug_struct("Glob") .field("is_prelude", is_prelude) .field("max_vis", max_vis) + .field("id", id) .finish(), - ExternCrate { ref source, ref target } => f + ExternCrate { ref source, ref target, ref id } => f .debug_struct("ExternCrate") .field("source", source) .field("target", target) + .field("id", id) .finish(), MacroUse => f.debug_struct("MacroUse").finish(), } @@ -103,24 +122,15 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { pub(crate) struct Import<'a> { pub kind: ImportKind<'a>, - /// The ID of the `extern crate`, `UseTree` etc that imported this `Import`. - /// - /// In the case where the `Import` was expanded from a "nested" use tree, - /// this id is the ID of the leaf tree. For example: - /// - /// ```ignore (pacify the merciless tidy) + /// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id` + /// (if it exists) except in the case of "nested" use trees, in which case + /// it will be the ID of the root use tree. e.g., in the example + /// ```ignore (incomplete code) /// use foo::bar::{a, b} /// ``` - /// - /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree` - /// for `a` in this field. - pub id: NodeId, - - /// The `id` of the "root" use-kind -- this is always the same as - /// `id` except in the case of "nested" use trees, in which case - /// it will be the `id` of the root use tree. e.g., in the example - /// from `id`, this would be the ID of the `use foo::bar` - /// `UseTree` node. + /// this would be the ID of the `use foo::bar` `UseTree` node. + /// In case of imports without their own node ID it's the closest node that can be used, + /// for example, for reporting lints. pub root_id: NodeId, /// Span of the entire use statement. @@ -161,6 +171,15 @@ pub fn is_nested(&self) -> bool { pub(crate) fn expect_vis(&self) -> ty::Visibility { self.vis.get().expect("encountered cleared import visibility") } + + pub(crate) fn id(&self) -> Option { + match self.kind { + ImportKind::Single { id, .. } + | ImportKind::Glob { id, .. } + | ImportKind::ExternCrate { id, .. } => Some(id), + ImportKind::MacroUse => None, + } + } } /// Records information about the resolution of a name in a namespace of a module. @@ -368,7 +387,9 @@ fn import_dummy_binding(&mut self, import: &'a Import<'a>) { self.record_use(target, dummy_binding, false); } else if import.imported_module.get().is_none() { import.used.set(true); - self.used_imports.insert(import.id); + if let Some(id) = import.id() { + self.used_imports.insert(id); + } } } } @@ -718,47 +739,51 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option unreachable!(), }; - let (ident, target, source_bindings, target_bindings, type_ns_only) = match import.kind { - ImportKind::Single { - source, - target, - ref source_bindings, - ref target_bindings, - type_ns_only, - .. - } => (source, target, source_bindings, target_bindings, type_ns_only), - ImportKind::Glob { is_prelude, ref max_vis } => { - if import.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 = import.module_path.clone(); - full_path.push(Segment::from_ident(Ident::empty())); - self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None); - } - - if let ModuleOrUniformRoot::Module(module) = module { - if ptr::eq(module, import.parent_scope.module) { - // Importing a module into itself is not allowed. - return Some(UnresolvedImportError { - span: import.span, - label: Some(String::from("cannot glob-import a module into itself")), - note: None, - suggestion: None, - candidate: None, - }); + let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) = + match import.kind { + ImportKind::Single { + source, + target, + ref source_bindings, + ref target_bindings, + type_ns_only, + id, + .. + } => (source, target, source_bindings, target_bindings, type_ns_only, id), + ImportKind::Glob { is_prelude, ref max_vis, id } => { + if import.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 = import.module_path.clone(); + full_path.push(Segment::from_ident(Ident::empty())); + self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None); } - } - if !is_prelude + + if let ModuleOrUniformRoot::Module(module) = module { + if ptr::eq(module, import.parent_scope.module) { + // Importing a module into itself is not allowed. + return Some(UnresolvedImportError { + span: import.span, + label: Some(String::from( + "cannot glob-import a module into itself", + )), + note: None, + suggestion: None, + candidate: None, + }); + } + } + if !is_prelude && let Some(max_vis) = max_vis.get() && !max_vis.is_at_least(import.expect_vis(), &*self.r) { let msg = "glob import doesn't reexport anything because no candidate is public enough"; - self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg); + self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg); } - return None; - } - _ => unreachable!(), - }; + return None; + } + _ => unreachable!(), + }; let mut all_ns_err = true; self.r.per_ns(|this, ns| { @@ -960,7 +985,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option) -> Option>>>, target: Ident, ) { + // This function is only called for single imports. + let ImportKind::Single { id, .. } = import.kind else { unreachable!() }; + // Skip if the import was produced by a macro. if import.parent_scope.expansion != LocalExpnId::ROOT { return; @@ -1094,7 +1122,7 @@ fn check_for_redundant_imports( redundant_spans.dedup(); self.r.lint_buffer.buffer_lint_with_diagnostic( UNUSED_IMPORTS, - import.id, + id, import.span, &format!("the item `{}` is imported redundantly", ident), BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident), @@ -1103,6 +1131,9 @@ fn check_for_redundant_imports( } fn resolve_glob_import(&mut self, import: &'b Import<'b>) { + // This function is only called for glob imports. + let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() }; + let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else { self.r.session.span_err(import.span, "cannot glob-import all possible crates"); return; @@ -1113,7 +1144,7 @@ fn resolve_glob_import(&mut self, import: &'b Import<'b>) { return; } else if ptr::eq(module, import.parent_scope.module) { return; - } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind { + } else if is_prelude { self.r.prelude = Some(module); return; } @@ -1145,7 +1176,7 @@ fn resolve_glob_import(&mut self, import: &'b Import<'b>) { } // Record the destination of this import - self.r.record_partial_res(import.id, PartialRes::new(module.res().unwrap())); + self.r.record_partial_res(id, PartialRes::new(module.res().unwrap())); } // Miscellaneous post-processing, including recording re-exports, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 11b70a38da5..592f24b0b0f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1613,10 +1613,12 @@ fn find_transitive_imports( ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; while let NameBindingKind::Import { import, binding, .. } = kind { - let id = self.local_def_id(import.id); - self.maybe_unused_trait_imports.insert(id); + if let Some(node_id) = import.id() { + let def_id = self.local_def_id(node_id); + self.maybe_unused_trait_imports.insert(def_id); + import_ids.push(def_id); + } self.add_to_glob_map(&import, trait_name); - import_ids.push(id); kind = &binding.kind; } import_ids @@ -1683,7 +1685,9 @@ fn record_use( } used.set(true); import.used.set(true); - self.used_imports.insert(import.id); + if let Some(id) = import.id() { + self.used_imports.insert(id); + } self.add_to_glob_map(&import, ident); self.record_use(ident, binding, false); } @@ -1691,8 +1695,8 @@ fn record_use( #[inline] fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) { - if import.is_glob() { - let def_id = self.local_def_id(import.id); + if let ImportKind::Glob { id, .. } = import.kind { + let def_id = self.local_def_id(id); self.glob_map.entry(def_id).or_default().insert(ident.name); } } From 84317518ffaf8e56524510a2ca634ebb64022249 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Oct 2022 15:55:58 +0400 Subject: [PATCH 2/2] resolve: Turn the binding from `#[macro_export]` into a proper `Import` --- .../rustc_resolve/src/build_reduced_graph.rs | 34 +++++++++---------- compiler/rustc_resolve/src/diagnostics.rs | 34 +++++++++++-------- .../src/effective_visibilities.rs | 12 +++---- compiler/rustc_resolve/src/ident.rs | 8 +++-- compiler/rustc_resolve/src/imports.rs | 9 +++-- compiler/rustc_resolve/src/lib.rs | 25 ++++++++------ src/test/ui/macros/issue-38715.rs | 12 ++++++- src/test/ui/macros/issue-38715.stderr | 15 ++++++-- src/test/ui/privacy/effective_visibilities.rs | 4 +-- .../ui/privacy/effective_visibilities.stderr | 4 +-- 10 files changed, 96 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 5ac562d1663..423c5727533 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -56,21 +56,7 @@ fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> impl<'a, Id: Into> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(self.0, false), - ambiguity: None, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - -struct IsMacroExport; - -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroExport) { - fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { - arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(self.0, true), + kind: NameBindingKind::Res(self.0), ambiguity: None, vis: self.1.to_def_id(), span: self.2, @@ -1267,8 +1253,22 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> { let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); self.r.set_binding_parent_module(binding, parent_scope.module); if is_macro_export { - let module = self.r.graph_root; - self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport)); + let import = self.r.arenas.alloc_import(Import { + kind: ImportKind::MacroExport, + root_id: item.id, + parent_scope: self.parent_scope, + imported_module: Cell::new(None), + has_attributes: false, + use_span_with_attributes: span, + use_span: span, + root_span: span, + span: span, + module_path: Vec::new(), + vis: Cell::new(Some(vis)), + used: Cell::new(true), + }); + let import_binding = self.r.import(binding, import); + self.r.define(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id, &rule_spans); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index bba03a40ed6..d14e01a25c8 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -190,12 +190,12 @@ pub(crate) fn report_conflict<'b>( ModuleKind::Block => "block", }; - let old_noun = match old_binding.is_import() { + let old_noun = match old_binding.is_import_user_facing() { true => "import", false => "definition", }; - let new_participle = match new_binding.is_import() { + let new_participle = match new_binding.is_import_user_facing() { true => "imported", false => "defined", }; @@ -226,7 +226,7 @@ pub(crate) fn report_conflict<'b>( true => struct_span_err!(self.session, span, E0254, "{}", msg), false => struct_span_err!(self.session, span, E0260, "{}", msg), }, - _ => match (old_binding.is_import(), new_binding.is_import()) { + _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) { (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg), (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg), _ => struct_span_err!(self.session, span, E0255, "{}", msg), @@ -248,14 +248,18 @@ pub(crate) fn report_conflict<'b>( // See https://github.com/rust-lang/rust/issues/32354 use NameBindingKind::Import; + let can_suggest = |binding: &NameBinding<'_>, import: &self::Import<'_>| { + !binding.span.is_dummy() + && !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport) + }; let import = match (&new_binding.kind, &old_binding.kind) { // If there are two imports where one or both have attributes then prefer removing the // import without attributes. (Import { import: new, .. }, Import { import: old, .. }) if { - !new_binding.span.is_dummy() - && !old_binding.span.is_dummy() - && (new.has_attributes || old.has_attributes) + (new.has_attributes || old.has_attributes) + && can_suggest(old_binding, old) + && can_suggest(new_binding, new) } => { if old.has_attributes { @@ -265,10 +269,10 @@ pub(crate) fn report_conflict<'b>( } } // Otherwise prioritize the new binding. - (Import { import, .. }, other) if !new_binding.span.is_dummy() => { + (Import { import, .. }, other) if can_suggest(new_binding, import) => { Some((import, new_binding.span, other.is_import())) } - (other, Import { import, .. }) if !old_binding.span.is_dummy() => { + (other, Import { import, .. }) if can_suggest(old_binding, import) => { Some((import, old_binding.span, other.is_import())) } _ => None, @@ -1683,7 +1687,7 @@ fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: b let a = if built_in.is_empty() { res.article() } else { "a" }; format!("{a}{built_in} {thing}{from}", thing = res.descr()) } else { - let introduced = if b.is_import() { "imported" } else { "defined" }; + let introduced = if b.is_import_user_facing() { "imported" } else { "defined" }; format!("the {thing} {introduced} here", thing = res.descr()) } } @@ -1742,10 +1746,10 @@ fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option { - if let NameBindingKind::Res( - Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id), - _, - ) = binding.kind + if let NameBindingKind::Res(Res::Def( + DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), + ctor_def_id, + )) = binding.kind { let def_id = self.parent(ctor_def_id); let fields = self.field_names.get(&def_id)?; @@ -1789,7 +1793,9 @@ fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) { next_ident = source; Some(binding) } - ImportKind::Glob { .. } | ImportKind::MacroUse => Some(binding), + ImportKind::Glob { .. } | ImportKind::MacroUse | ImportKind::MacroExport => { + Some(binding) + } ImportKind::ExternCrate { .. } => None, }, _ => None, diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 84fa7b89bda..17ce854cb43 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -88,6 +88,11 @@ fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) { // here, but `macro_use` imports always refer to external items, // so it doesn't matter and we can just do nothing. } + ImportKind::MacroExport => { + // In theory we should reset the parent id to something public + // here, but it has the same effect as leaving the previous parent, + // so we can just do nothing. + } } level = Level::Reexported; @@ -152,13 +157,6 @@ fn visit_item(&mut self, item: &'ast ast::Item) { self.update(def_id, Visibility::Public, parent_id, Level::Direct); } - // Only exported `macro_rules!` items are public, but they always are - ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { - let parent_id = self.r.local_parent(def_id); - let vis = self.r.visibilities[&def_id]; - self.update(def_id, vis, parent_id, Level::Direct); - } - ast::ItemKind::Mod(..) => { self.set_bindings_effective_visibilities(def_id); visit::walk_item(self, item); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index e0542d5479f..75981885674 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -19,7 +19,7 @@ }; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; -use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak}; @@ -915,7 +915,11 @@ fn resolve_ident_in_module_unadjusted_ext( } if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { - if let NameBindingKind::Res(_, true) = binding.kind { + if let NameBindingKind::Import { + import: Import { kind: ImportKind::MacroExport, .. }, + .. + } = binding.kind + { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 3b9bf943262..bdb852548b8 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -73,6 +73,7 @@ pub enum ImportKind<'a> { id: NodeId, }, MacroUse, + MacroExport, } /// Manually implement `Debug` for `ImportKind` because the `source/target_bindings` @@ -113,6 +114,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { .field("id", id) .finish(), MacroUse => f.debug_struct("MacroUse").finish(), + MacroExport => f.debug_struct("MacroExport").finish(), } } } @@ -177,7 +179,7 @@ pub(crate) fn id(&self) -> Option { ImportKind::Single { id, .. } | ImportKind::Glob { id, .. } | ImportKind::ExternCrate { id, .. } => Some(id), - ImportKind::MacroUse => None, + ImportKind::MacroUse | ImportKind::MacroExport => None, } } } @@ -883,7 +885,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option None, + NameBindingKind::Res(Res::Err) => None, _ => Some(i.name), } } @@ -1014,7 +1016,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option { @@ -1235,5 +1237,6 @@ fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String { ImportKind::Glob { .. } => "*".to_string(), ImportKind::ExternCrate { .. } => "".to_string(), ImportKind::MacroUse => "#[macro_use]".to_string(), + ImportKind::MacroExport => "#[macro_export]".to_string(), } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 592f24b0b0f..201ccdf120b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -646,7 +646,7 @@ fn to_name_binding(self, _: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { #[derive(Clone, Debug)] enum NameBindingKind<'a> { - Res(Res, /* is_macro_export */ bool), + Res(Res), Module(Module<'a>), Import { binding: &'a NameBinding<'a>, import: &'a Import<'a>, used: Cell }, } @@ -745,7 +745,7 @@ fn module(&self) -> Option> { fn res(&self) -> Res { match self.kind { - NameBindingKind::Res(res, _) => res, + NameBindingKind::Res(res) => res, NameBindingKind::Module(module) => module.res().unwrap(), NameBindingKind::Import { binding, .. } => binding.res(), } @@ -762,10 +762,10 @@ fn is_ambiguity(&self) -> bool { fn is_possibly_imported_variant(&self) -> bool { match self.kind { NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(), - NameBindingKind::Res( - Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _), + NameBindingKind::Res(Res::Def( + DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _, - ) => true, + )) => true, NameBindingKind::Res(..) | NameBindingKind::Module(..) => false, } } @@ -788,6 +788,13 @@ fn is_import(&self) -> bool { matches!(self.kind, NameBindingKind::Import { .. }) } + /// The binding introduced by `#[macro_export] macro_rules` is a public import, but it might + /// not be perceived as such by users, so treat it as a non-import in some diagnostics. + fn is_import_user_facing(&self) -> bool { + matches!(self.kind, NameBindingKind::Import { import, .. } + if !matches!(import.kind, ImportKind::MacroExport)) + } + fn is_glob_import(&self) -> bool { match self.kind { NameBindingKind::Import { import, .. } => import.is_glob(), @@ -1283,7 +1290,7 @@ pub fn new( arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Res(Res::Err, false), + kind: NameBindingKind::Res(Res::Err), ambiguity: None, expansion: LocalExpnId::ROOT, span: DUMMY_SP, @@ -1998,11 +2005,7 @@ fn resolve_main(&mut self) { // Items that go to reexport table encoded to metadata and visible through it to other crates. fn is_reexport(&self, binding: &NameBinding<'a>) -> Option> { - // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` - // into the crate root to actual `NameBindingKind::Import`. - if binding.is_import() - || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) - { + if binding.is_import() { let res = binding.res().expect_non_local(); // Ambiguous imports are treated as errors at this point and are // not exposed to other crates (see #36837 for more details). diff --git a/src/test/ui/macros/issue-38715.rs b/src/test/ui/macros/issue-38715.rs index 9a9a501cae1..85ed97663e8 100644 --- a/src/test/ui/macros/issue-38715.rs +++ b/src/test/ui/macros/issue-38715.rs @@ -1,7 +1,17 @@ #[macro_export] -macro_rules! foo { ($i:ident) => {} } +macro_rules! foo { () => {} } #[macro_export] macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times +mod inner1 { + #[macro_export] + macro_rules! bar { () => {} } +} + +mod inner2 { + #[macro_export] + macro_rules! bar { () => {} } //~ ERROR the name `bar` is defined multiple times +} + fn main() {} diff --git a/src/test/ui/macros/issue-38715.stderr b/src/test/ui/macros/issue-38715.stderr index c87d9f7360b..828a7f45930 100644 --- a/src/test/ui/macros/issue-38715.stderr +++ b/src/test/ui/macros/issue-38715.stderr @@ -1,7 +1,7 @@ error[E0428]: the name `foo` is defined multiple times --> $DIR/issue-38715.rs:5:1 | -LL | macro_rules! foo { ($i:ident) => {} } +LL | macro_rules! foo { () => {} } | ---------------- previous definition of the macro `foo` here ... LL | macro_rules! foo { () => {} } @@ -9,6 +9,17 @@ LL | macro_rules! foo { () => {} } | = note: `foo` must be defined only once in the macro namespace of this module -error: aborting due to previous error +error[E0428]: the name `bar` is defined multiple times + --> $DIR/issue-38715.rs:14:5 + | +LL | macro_rules! bar { () => {} } + | ---------------- previous definition of the macro `bar` here +... +LL | macro_rules! bar { () => {} } + | ^^^^^^^^^^^^^^^^ `bar` redefined here + | + = note: `bar` must be defined only once in the macro namespace of this module + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0428`. diff --git a/src/test/ui/privacy/effective_visibilities.rs b/src/test/ui/privacy/effective_visibilities.rs index 1d806a1d1d1..c1f9ee8dfdf 100644 --- a/src/test/ui/privacy/effective_visibilities.rs +++ b/src/test/ui/privacy/effective_visibilities.rs @@ -38,13 +38,13 @@ pub enum Enum { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, R } #[rustc_effective_visibility] - macro_rules! none_macro { //~ Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate) + macro_rules! none_macro { //~ ERROR not in the table () => {}; } #[macro_export] #[rustc_effective_visibility] - macro_rules! public_macro { //~ Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub + macro_rules! public_macro { //~ ERROR Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub () => {}; } diff --git a/src/test/ui/privacy/effective_visibilities.stderr b/src/test/ui/privacy/effective_visibilities.stderr index 1c6201600b6..5a8f7db38fc 100644 --- a/src/test/ui/privacy/effective_visibilities.stderr +++ b/src/test/ui/privacy/effective_visibilities.stderr @@ -64,13 +64,13 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl LL | PubUnion, | ^^^^^^^^ -error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate) +error: not in the table --> $DIR/effective_visibilities.rs:41:5 | LL | macro_rules! none_macro { | ^^^^^^^^^^^^^^^^^^^^^^^ -error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub +error: Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub --> $DIR/effective_visibilities.rs:47:5 | LL | macro_rules! public_macro {