Rollup merge of #103760 - petrochenkov:macimp, r=cjgillot

resolve: Turn the binding from `#[macro_export]` into a proper `Import`

Continuation of https://github.com/rust-lang/rust/pull/91795.

```rust
#[macro_export]
macro_rules! m { /*...*/ }
```
is desugared to something like
```rust
macro_rules! m { /*...*/ } // Non-modularized macro_rules item

pub use m; // It's modularized reexport
```

This PR adjusts the internal representation to better match this model.
This commit is contained in:
Dylan DPC 2022-11-01 22:01:36 +05:30 committed by GitHub
commit 68afa32985
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 238 additions and 165 deletions

View File

@ -56,21 +56,7 @@ fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a>
impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, 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,
@ -364,7 +350,6 @@ fn add_import(
module_path: Vec<Segment>,
kind: ImportKind<'a>,
span: Span,
id: NodeId,
item: &ast::Item,
root_span: Span,
root_id: NodeId,
@ -377,7 +362,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 +558,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 +858,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 +1094,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(),
@ -1278,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);

View File

@ -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);
}
_ => {}
}

View File

@ -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,
@ -353,7 +357,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),
@ -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<Span> {
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,

View File

@ -57,26 +57,45 @@ 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.
}
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;
prev_parent_id = self.r.local_def_id(import.id);
binding = nested_binding;
}
}
@ -138,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);

View File

@ -17,7 +17,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};
@ -860,7 +860,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));
}
}

View File

@ -44,20 +44,36 @@ 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<Option<ty::Visibility>>, // 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<Option<ty::Visibility>>,
id: NodeId,
},
ExternCrate {
source: Option<Symbol>,
target: Ident,
id: NodeId,
},
MacroUse,
MacroExport,
}
/// Manually implement `Debug` for `ImportKind` because the `source/target_bindings`
@ -71,6 +87,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,19 +98,23 @@ 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(),
MacroExport => f.debug_struct("MacroExport").finish(),
}
}
}
@ -103,24 +124,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 +173,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<NodeId> {
match self.kind {
ImportKind::Single { id, .. }
| ImportKind::Glob { id, .. }
| ImportKind::ExternCrate { id, .. } => Some(id),
ImportKind::MacroUse | ImportKind::MacroExport => None,
}
}
}
/// Records information about the resolution of a name in a namespace of a module.
@ -368,7 +389,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 +741,51 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
PathResult::Indeterminate => 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| {
@ -858,7 +885,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
match binding.kind {
// Never suggest the name that has binding error
// i.e., the name that cannot be previously resolved
NameBindingKind::Res(Res::Err, _) => None,
NameBindingKind::Res(Res::Err) => None,
_ => Some(i.name),
}
}
@ -960,7 +987,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
);
self.r.lint_buffer.buffer_lint(
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
import.id,
import_id,
import.span,
&msg,
);
@ -989,7 +1016,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
let mut err =
struct_span_err!(self.r.session, import.span, E0364, "{error_msg}");
match binding.kind {
NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id), _)
NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id))
// exclude decl_macro
if self.r.get_macro_by_def_id(def_id).macro_rules =>
{
@ -1029,7 +1056,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
// purposes it's good enough to just favor one over the other.
self.r.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
this.import_res_map.entry(import.id).or_default()[ns] = Some(binding.res());
this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res());
}
});
@ -1047,6 +1074,9 @@ fn check_for_redundant_imports(
target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>,
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 +1124,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 +1133,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 +1146,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 +1178,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,
@ -1204,5 +1237,6 @@ fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String {
ImportKind::Glob { .. } => "*".to_string(),
ImportKind::ExternCrate { .. } => "<extern crate>".to_string(),
ImportKind::MacroUse => "#[macro_use]".to_string(),
ImportKind::MacroExport => "#[macro_export]".to_string(),
}
}

View File

@ -644,7 +644,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<bool> },
}
@ -743,7 +743,7 @@ fn module(&self) -> Option<Module<'a>> {
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(),
}
@ -760,10 +760,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,
}
}
@ -786,6 +786,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(),
@ -1281,7 +1288,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,
@ -1611,10 +1618,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
@ -1681,7 +1690,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);
}
@ -1689,8 +1700,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);
}
}
@ -1992,11 +2003,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<def::Res<!>> {
// 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).

View File

@ -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() {}

View File

@ -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`.

View File

@ -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
() => {};
}

View File

@ -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 {