Skip to content

Commit e94df4a

Browse files
committed
Auto merge of #52234 - petrochenkov:macuse2, r=Mark-Simulacrum
resolve: Modularize crate-local `#[macro_export] macro_rules` Based on #50911, cc #50911 (comment) `#[macro_export] macro_rules` items are collected from the whole crate and are planted into the root module as items, so the external view of the crate is symmetric with its internal view and something like `$crate::my_macro` where `my_macro` is `#[macro_export] macro_rules` works both locally and from other crates. Closes #52726
2 parents f898179 + 4442240 commit e94df4a

14 files changed

+415
-32
lines changed

src/librustc_resolve/build_reduced_graph.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,20 @@ impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) {
5959
impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark) {
6060
fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
6161
arenas.alloc_name_binding(NameBinding {
62-
kind: NameBindingKind::Def(self.0),
62+
kind: NameBindingKind::Def(self.0, false),
63+
vis: self.1,
64+
span: self.2,
65+
expansion: self.3,
66+
})
67+
}
68+
}
69+
70+
pub(crate) struct IsMacroExport;
71+
72+
impl<'a> ToNameBinding<'a> for (Def, ty::Visibility, Span, Mark, IsMacroExport) {
73+
fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
74+
arenas.alloc_name_binding(NameBinding {
75+
kind: NameBindingKind::Def(self.0, true),
6376
vis: self.1,
6477
span: self.2,
6578
expansion: self.3,
@@ -772,6 +785,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
772785
fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
773786
let mark = id.placeholder_to_mark();
774787
self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark);
788+
self.resolver.unresolved_invocations_macro_export.insert(mark);
775789
let invocation = self.resolver.invocations[&mark];
776790
invocation.module.set(self.resolver.current_module);
777791
invocation.legacy_scope.set(self.legacy_scope);

src/librustc_resolve/lib.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,7 @@ impl<'a> ToNameBinding<'a> for &'a NameBinding<'a> {
11181118

11191119
#[derive(Clone, Debug)]
11201120
enum NameBindingKind<'a> {
1121-
Def(Def),
1121+
Def(Def, /* is_macro_export */ bool),
11221122
Module(Module<'a>),
11231123
Import {
11241124
binding: &'a NameBinding<'a>,
@@ -1162,7 +1162,7 @@ impl<'a> NameBinding<'a> {
11621162

11631163
fn def(&self) -> Def {
11641164
match self.kind {
1165-
NameBindingKind::Def(def) => def,
1165+
NameBindingKind::Def(def, _) => def,
11661166
NameBindingKind::Module(module) => module.def().unwrap(),
11671167
NameBindingKind::Import { binding, .. } => binding.def(),
11681168
NameBindingKind::Ambiguity { .. } => Def::Err,
@@ -1192,8 +1192,8 @@ impl<'a> NameBinding<'a> {
11921192

11931193
fn is_variant(&self) -> bool {
11941194
match self.kind {
1195-
NameBindingKind::Def(Def::Variant(..)) |
1196-
NameBindingKind::Def(Def::VariantCtor(..)) => true,
1195+
NameBindingKind::Def(Def::Variant(..), _) |
1196+
NameBindingKind::Def(Def::VariantCtor(..), _) => true,
11971197
_ => false,
11981198
}
11991199
}
@@ -1242,7 +1242,7 @@ impl<'a> NameBinding<'a> {
12421242

12431243
fn is_macro_def(&self) -> bool {
12441244
match self.kind {
1245-
NameBindingKind::Def(Def::Macro(..)) => true,
1245+
NameBindingKind::Def(Def::Macro(..), _) => true,
12461246
_ => false,
12471247
}
12481248
}
@@ -1398,7 +1398,7 @@ pub struct Resolver<'a> {
13981398
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
13991399
macro_defs: FxHashMap<Mark, DefId>,
14001400
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
1401-
macro_exports: Vec<Export>,
1401+
macro_exports: Vec<Export>, // FIXME: Remove when `use_extern_macros` is stabilized
14021402
pub whitelisted_legacy_custom_derives: Vec<Name>,
14031403
pub found_unresolved_macro: bool,
14041404

@@ -1428,6 +1428,9 @@ pub struct Resolver<'a> {
14281428

14291429
/// Only supposed to be used by rustdoc, otherwise should be false.
14301430
pub ignore_extern_prelude_feature: bool,
1431+
1432+
/// Macro invocations in the whole crate that can expand into a `#[macro_export] macro_rules`.
1433+
unresolved_invocations_macro_export: FxHashSet<Mark>,
14311434
}
14321435

14331436
/// Nothing really interesting here, it just provides memory for the rest of the crate.
@@ -1702,7 +1705,7 @@ impl<'a> Resolver<'a> {
17021705

17031706
arenas,
17041707
dummy_binding: arenas.alloc_name_binding(NameBinding {
1705-
kind: NameBindingKind::Def(Def::Err),
1708+
kind: NameBindingKind::Def(Def::Err, false),
17061709
expansion: Mark::root(),
17071710
span: DUMMY_SP,
17081711
vis: ty::Visibility::Public,
@@ -1732,6 +1735,7 @@ impl<'a> Resolver<'a> {
17321735
current_type_ascription: Vec::new(),
17331736
injected_crate: None,
17341737
ignore_extern_prelude_feature: false,
1738+
unresolved_invocations_macro_export: FxHashSet(),
17351739
}
17361740
}
17371741

src/librustc_resolve/macros.rs

+26-14
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use {AmbiguityError, CrateLint, Resolver, ResolutionError, resolve_error};
1212
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult};
1313
use Namespace::{self, MacroNS};
14-
use build_reduced_graph::BuildReducedGraphVisitor;
14+
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
1515
use resolve_imports::ImportResolver;
1616
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
1717
DefIndexAddressSpace};
@@ -193,7 +193,9 @@ impl<'a> base::Resolver for Resolver<'a> {
193193

194194
self.current_module = invocation.module.get();
195195
self.current_module.unresolved_invocations.borrow_mut().remove(&mark);
196+
self.unresolved_invocations_macro_export.remove(&mark);
196197
self.current_module.unresolved_invocations.borrow_mut().extend(derives);
198+
self.unresolved_invocations_macro_export.extend(derives);
197199
for &derive in derives {
198200
self.invocations.insert(derive, invocation);
199201
}
@@ -215,7 +217,7 @@ impl<'a> base::Resolver for Resolver<'a> {
215217
let kind = ext.kind();
216218
self.macro_map.insert(def_id, ext);
217219
let binding = self.arenas.alloc_name_binding(NameBinding {
218-
kind: NameBindingKind::Def(Def::Macro(def_id, kind)),
220+
kind: NameBindingKind::Def(Def::Macro(def_id, kind), false),
219221
span: DUMMY_SP,
220222
vis: ty::Visibility::Invisible,
221223
expansion: Mark::root(),
@@ -711,12 +713,15 @@ impl<'a> Resolver<'a> {
711713

712714
match (legacy_resolution, resolution) {
713715
(Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
714-
let msg1 = format!("`{}` could refer to the macro defined here", ident);
715-
let msg2 = format!("`{}` could also refer to the macro imported here", ident);
716-
self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
717-
.span_note(legacy_binding.span, &msg1)
718-
.span_note(binding.span, &msg2)
719-
.emit();
716+
if legacy_binding.def_id != binding.def_ignoring_ambiguity().def_id() {
717+
let msg1 = format!("`{}` could refer to the macro defined here", ident);
718+
let msg2 =
719+
format!("`{}` could also refer to the macro imported here", ident);
720+
self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident))
721+
.span_note(legacy_binding.span, &msg1)
722+
.span_note(binding.span, &msg2)
723+
.emit();
724+
}
720725
},
721726
(None, Err(_)) => {
722727
assert!(def.is_none());
@@ -850,12 +855,19 @@ impl<'a> Resolver<'a> {
850855
let def = Def::Macro(def_id, MacroKind::Bang);
851856
self.all_macros.insert(ident.name, def);
852857
if attr::contains_name(&item.attrs, "macro_export") {
853-
self.macro_exports.push(Export {
854-
ident: ident.modern(),
855-
def: def,
856-
vis: ty::Visibility::Public,
857-
span: item.span,
858-
});
858+
if self.use_extern_macros {
859+
let module = self.graph_root;
860+
let vis = ty::Visibility::Public;
861+
self.define(module, ident, MacroNS,
862+
(def, vis, item.span, expansion, IsMacroExport));
863+
} else {
864+
self.macro_exports.push(Export {
865+
ident: ident.modern(),
866+
def: def,
867+
vis: ty::Visibility::Public,
868+
span: item.span,
869+
});
870+
}
859871
} else {
860872
self.unused_macros.insert(def_id);
861873
}

src/librustc_resolve/resolve_imports.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ impl<'a> Resolver<'a> {
211211
// if it cannot be shadowed by some new item/import expanded from a macro.
212212
// This happens either if there are no unexpanded macros, or expanded names cannot
213213
// shadow globs (that happens in macro namespace or with restricted shadowing).
214-
let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty();
214+
let unexpanded_macros = !module.unresolved_invocations.borrow().is_empty() ||
215+
(ns == MacroNS && ptr::eq(module, self.graph_root) &&
216+
!self.unresolved_invocations_macro_export.is_empty());
215217
if let Some(binding) = resolution.binding {
216218
if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
217219
return check_usable(self, binding);
@@ -363,6 +365,18 @@ impl<'a> Resolver<'a> {
363365
resolution.binding = Some(binding);
364366
resolution.shadowed_glob = Some(old_binding);
365367
}
368+
} else if let (&NameBindingKind::Def(_, true), &NameBindingKind::Def(_, true)) =
369+
(&old_binding.kind, &binding.kind) {
370+
371+
this.session.buffer_lint_with_diagnostic(
372+
DUPLICATE_MACRO_EXPORTS,
373+
CRATE_NODE_ID,
374+
binding.span,
375+
&format!("a macro named `{}` has already been exported", ident),
376+
BuiltinLintDiagnostics::DuplicatedMacroExports(
377+
ident, old_binding.span, binding.span));
378+
379+
resolution.binding = Some(binding);
366380
} else {
367381
return Err(old_binding);
368382
}
@@ -766,7 +780,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
766780
match binding.kind {
767781
// Never suggest the name that has binding error
768782
// i.e. the name that cannot be previously resolved
769-
NameBindingKind::Def(Def::Err) => return None,
783+
NameBindingKind::Def(Def::Err, _) => return None,
770784
_ => Some(&i.name),
771785
}
772786
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(use_extern_macros)]
12+
#![allow(duplicate_macro_exports)]
13+
14+
#[macro_export]
15+
macro_rules! foo_modern { ($i:ident) => {} }
16+
17+
#[macro_export]
18+
macro_rules! foo_modern { () => {} }

src/test/run-pass/issue-38715.rs

+4
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@
99
// except according to those terms.
1010

1111
// aux-build:issue_38715.rs
12+
// aux-build:issue_38715-modern.rs
1213

1314
// Test that `#[macro_export] macro_rules!` shadow earlier `#[macro_export] macro_rules!`
1415

1516
#[macro_use]
1617
extern crate issue_38715;
18+
#[macro_use]
19+
extern crate issue_38715_modern;
1720

1821
fn main() {
1922
foo!();
23+
foo_modern!();
2024
}

src/test/ui/duplicate-check-macro-exports.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@
1313
pub use std::panic;
1414

1515
#[macro_export]
16-
macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported
16+
macro_rules! panic { () => {} } //~ ERROR the name `panic` is defined multiple times
1717

1818
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1-
error: a macro named `panic` has already been exported
1+
error[E0255]: the name `panic` is defined multiple times
22
--> $DIR/duplicate-check-macro-exports.rs:16:1
33
|
4-
LL | macro_rules! panic { () => {} } //~ ERROR a macro named `panic` has already been exported
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `panic` already exported
4+
LL | pub use std::panic;
5+
| ---------- previous import of the macro `panic` here
6+
...
7+
LL | macro_rules! panic { () => {} } //~ ERROR the name `panic` is defined multiple times
8+
| ^^^^^^^^^^^^^^^^^^ `panic` redefined here
69
|
7-
note: previous macro export here
8-
--> $DIR/duplicate-check-macro-exports.rs:13:9
10+
= note: `panic` must be defined only once in the macro namespace of this module
11+
help: You can use `as` to change the binding name of the import
912
|
10-
LL | pub use std::panic;
11-
| ^^^^^^^^^^
13+
LL | pub use std::panic as other_panic;
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
1215

1316
error: aborting due to previous error
1417

18+
For more information about this error, try `rustc --explain E0255`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(decl_macro)]
12+
13+
macro_rules! define_exported { () => {
14+
#[macro_export]
15+
macro_rules! exported {
16+
() => ()
17+
}
18+
}}
19+
macro_rules! define_panic { () => {
20+
#[macro_export]
21+
macro_rules! panic {
22+
() => ()
23+
}
24+
}}
25+
macro_rules! define_include { () => {
26+
#[macro_export]
27+
macro_rules! include {
28+
() => ()
29+
}
30+
}}
31+
32+
use inner1::*;
33+
34+
mod inner1 {
35+
pub macro exported() {}
36+
}
37+
38+
exported!(); //~ ERROR `exported` is ambiguous
39+
40+
mod inner2 {
41+
define_exported!();
42+
}
43+
44+
fn main() {
45+
panic!(); //~ ERROR `panic` is ambiguous
46+
//~^ ERROR `panic` is ambiguous
47+
}
48+
49+
mod inner3 {
50+
define_panic!();
51+
}
52+
53+
mod inner4 {
54+
define_include!();
55+
}
56+
57+
include!(); //~ ERROR `include` is ambiguous

0 commit comments

Comments
 (0)