Skip to content

Commit 142c98d

Browse files
committed
Auto merge of #51496 - petrochenkov:mhelper2, r=nikomatsakis
Implement `#[macro_export(local_inner_macros)]` (a solution for the macro helper import problem) Implement a solution for the macro helper issue discussed in #35896 as described in #35896 (comment). Macros exported from libraries can be marked with `#[macro_export(local_inner_macros)]` and this annotation changes how nested macros in them are resolved. If we have a fn-like macro call `ident!(...)` and `ident` comes from a `macro_rules!` macro marked with `#[macro_export(local_inner_macros)]` then it's replaced with `$crate::ident!(...)` and resolved as such (`$crate` gets the same context as `ident`).
2 parents c208243 + d347270 commit 142c98d

File tree

19 files changed

+134
-2
lines changed

19 files changed

+134
-2
lines changed

src/librustc/hir/lowering.rs

+1
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ impl<'a> LoweringContext<'a> {
616616
format: codemap::CompilerDesugaring(reason),
617617
allow_internal_unstable: true,
618618
allow_internal_unsafe: false,
619+
local_inner_macros: false,
619620
edition: codemap::hygiene::default_edition(),
620621
});
621622
span.with_ctxt(SyntaxContext::empty().apply_mark(mark))

src/librustc/ich/impls_syntax.rs

+1
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo {
395395
format,
396396
allow_internal_unstable,
397397
allow_internal_unsafe,
398+
local_inner_macros,
398399
edition
399400
});
400401

src/librustc_allocator/expand.rs

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
103103
format: MacroAttribute(Symbol::intern(name)),
104104
allow_internal_unstable: true,
105105
allow_internal_unsafe: false,
106+
local_inner_macros: false,
106107
edition: hygiene::default_edition(),
107108
});
108109

src/librustc_plugin/registry.rs

+3
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ impl<'a> Registry<'a> {
108108
def_info: _,
109109
allow_internal_unstable,
110110
allow_internal_unsafe,
111+
local_inner_macros,
111112
unstable_feature,
112113
edition,
113114
} => {
@@ -117,6 +118,7 @@ impl<'a> Registry<'a> {
117118
def_info: Some((nid, self.krate_span)),
118119
allow_internal_unstable,
119120
allow_internal_unsafe,
121+
local_inner_macros,
120122
unstable_feature,
121123
edition,
122124
}
@@ -152,6 +154,7 @@ impl<'a> Registry<'a> {
152154
def_info: None,
153155
allow_internal_unstable: false,
154156
allow_internal_unsafe: false,
157+
local_inner_macros: false,
155158
unstable_feature: None,
156159
edition: hygiene::default_edition(),
157160
});

src/librustc_resolve/macros.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -451,11 +451,18 @@ impl<'a> Resolver<'a> {
451451
kind: MacroKind, force: bool)
452452
-> Result<Def, Determinacy> {
453453
let ast::Path { ref segments, span } = *path;
454-
let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
454+
let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
455455
let invocation = self.invocations[&scope];
456456
let module = invocation.module.get();
457457
self.current_module = if module.is_trait() { module.parent.unwrap() } else { module };
458458

459+
// Possibly apply the macro helper hack
460+
if self.use_extern_macros && kind == MacroKind::Bang && path.len() == 1 &&
461+
path[0].span.ctxt().outer().expn_info().map_or(false, |info| info.local_inner_macros) {
462+
let root = Ident::new(keywords::DollarCrate.name(), path[0].span);
463+
path.insert(0, root);
464+
}
465+
459466
if path.len() > 1 {
460467
if !self.use_extern_macros && self.gated_errors.insert(span) {
461468
let msg = "non-ident macro paths are experimental";

src/libsyntax/ext/base.rs

+3
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,9 @@ pub enum SyntaxExtension {
621621
/// Whether the contents of the macro can use `unsafe`
622622
/// without triggering the `unsafe_code` lint.
623623
allow_internal_unsafe: bool,
624+
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
625+
/// for a given macro.
626+
local_inner_macros: bool,
624627
/// The macro's feature name if it is unstable, and the stability feature
625628
unstable_feature: Option<(Symbol, u32)>,
626629
/// Edition of the crate in which the macro is defined

src/libsyntax/ext/derive.rs

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
6464
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
6565
allow_internal_unstable: true,
6666
allow_internal_unsafe: false,
67+
local_inner_macros: false,
6768
edition: hygiene::default_edition(),
6869
});
6970

src/libsyntax/ext/expand.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
542542
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
543543
allow_internal_unstable: false,
544544
allow_internal_unsafe: false,
545+
local_inner_macros: false,
545546
edition: ext.edition(),
546547
});
547548

@@ -695,6 +696,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
695696
def_site_span: Option<Span>,
696697
allow_internal_unstable,
697698
allow_internal_unsafe,
699+
local_inner_macros,
698700
// can't infer this type
699701
unstable_feature: Option<(Symbol, u32)>,
700702
edition| {
@@ -729,6 +731,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
729731
format: macro_bang_format(path),
730732
allow_internal_unstable,
731733
allow_internal_unsafe,
734+
local_inner_macros,
732735
edition,
733736
});
734737
Ok(())
@@ -737,7 +740,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
737740
let opt_expanded = match *ext {
738741
DeclMacro(ref expand, def_span, edition) => {
739742
if let Err(dummy_span) = validate_and_set_expn_info(self, def_span.map(|(_, s)| s),
740-
false, false, None,
743+
false, false, false, None,
741744
edition) {
742745
dummy_span
743746
} else {
@@ -750,12 +753,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
750753
def_info,
751754
allow_internal_unstable,
752755
allow_internal_unsafe,
756+
local_inner_macros,
753757
unstable_feature,
754758
edition,
755759
} => {
756760
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
757761
allow_internal_unstable,
758762
allow_internal_unsafe,
763+
local_inner_macros,
759764
unstable_feature,
760765
edition) {
761766
dummy_span
@@ -777,6 +782,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
777782
format: macro_bang_format(path),
778783
allow_internal_unstable,
779784
allow_internal_unsafe: false,
785+
local_inner_macros: false,
780786
edition: hygiene::default_edition(),
781787
});
782788

@@ -816,6 +822,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
816822
// FIXME probably want to follow macro_rules macros here.
817823
allow_internal_unstable,
818824
allow_internal_unsafe: false,
825+
local_inner_macros: false,
819826
edition,
820827
});
821828

@@ -890,6 +897,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
890897
format: MacroAttribute(pretty_name),
891898
allow_internal_unstable: false,
892899
allow_internal_unsafe: false,
900+
local_inner_macros: false,
893901
edition: ext.edition(),
894902
};
895903

src/libsyntax/ext/tt/macro_rules.rs

+7
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,12 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition:
286286
if body.legacy {
287287
let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
288288
let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");
289+
let mut local_inner_macros = false;
290+
if let Some(macro_export) = attr::find_by_name(&def.attrs, "macro_export") {
291+
if let Some(l) = macro_export.meta_item_list() {
292+
local_inner_macros = attr::list_contains_name(&l, "local_inner_macros");
293+
}
294+
}
289295

290296
let unstable_feature = attr::find_stability(&sess.span_diagnostic,
291297
&def.attrs, def.span).and_then(|stability| {
@@ -301,6 +307,7 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition:
301307
def_info: Some((def.id, def.span)),
302308
allow_internal_unstable,
303309
allow_internal_unsafe,
310+
local_inner_macros,
304311
unstable_feature,
305312
edition,
306313
}

src/libsyntax/std_inject.rs

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ fn ignored_span(sp: Span) -> Span {
2929
format: MacroAttribute(Symbol::intern("std_inject")),
3030
allow_internal_unstable: true,
3131
allow_internal_unsafe: false,
32+
local_inner_macros: false,
3233
edition: hygiene::default_edition(),
3334
});
3435
sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))

src/libsyntax/test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ fn generate_test_harness(sess: &ParseSess,
311311
format: MacroAttribute(Symbol::intern("test")),
312312
allow_internal_unstable: true,
313313
allow_internal_unsafe: false,
314+
local_inner_macros: false,
314315
edition: hygiene::default_edition(),
315316
});
316317

src/libsyntax_ext/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
7676
def_info: None,
7777
allow_internal_unstable: false,
7878
allow_internal_unsafe: false,
79+
local_inner_macros: false,
7980
unstable_feature: None,
8081
edition: hygiene::default_edition(),
8182
});
@@ -132,6 +133,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
132133
def_info: None,
133134
allow_internal_unstable: true,
134135
allow_internal_unsafe: false,
136+
local_inner_macros: false,
135137
unstable_feature: None,
136138
edition: hygiene::default_edition(),
137139
});

src/libsyntax_ext/proc_macro_registrar.rs

+1
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
368368
format: MacroAttribute(Symbol::intern("proc_macro")),
369369
allow_internal_unstable: true,
370370
allow_internal_unsafe: false,
371+
local_inner_macros: false,
371372
edition: hygiene::default_edition(),
372373
});
373374
let span = DUMMY_SP.apply_mark(mark);

src/libsyntax_pos/hygiene.rs

+3
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,9 @@ pub struct ExpnInfo {
496496
/// Whether the macro is allowed to use `unsafe` internally
497497
/// even if the user crate has `#![forbid(unsafe_code)]`.
498498
pub allow_internal_unsafe: bool,
499+
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
500+
/// for a given macro.
501+
pub local_inner_macros: bool,
499502
/// Edition of the crate in which the macro is defined.
500503
pub edition: Edition,
501504
}

src/test/run-pass-fulldeps/auxiliary/plugin_args.rs

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
5454
def_info: None,
5555
allow_internal_unstable: false,
5656
allow_internal_unsafe: false,
57+
local_inner_macros: false,
5758
unstable_feature: None,
5859
edition: hygiene::default_edition(),
5960
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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+
#[macro_export]
12+
macro_rules! helper1 {
13+
() => ( struct S; )
14+
}
15+
16+
#[macro_export(local_inner_macros)]
17+
macro_rules! helper2 {
18+
() => ( helper1!(); )
19+
}
20+
21+
#[macro_export(local_inner_macros)]
22+
macro_rules! public_macro {
23+
() => ( helper2!(); )
24+
}
25+
26+
#[macro_export(local_inner_macros)]
27+
macro_rules! public_macro_dynamic {
28+
($helper: ident) => ( $helper!(); )
29+
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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+
// compile-pass
12+
// aux-build:local_inner_macros.rs
13+
14+
#![feature(use_extern_macros)]
15+
16+
extern crate local_inner_macros;
17+
18+
use local_inner_macros::{public_macro, public_macro_dynamic};
19+
20+
public_macro!();
21+
22+
macro_rules! local_helper {
23+
() => ( struct Z; )
24+
}
25+
26+
public_macro_dynamic!(local_helper);
27+
28+
fn main() {
29+
let s = S;
30+
let z = Z;
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
// `local_inner_macros` has no effect if `feature(use_extern_macros)` is not enabled
12+
13+
// aux-build:local_inner_macros.rs
14+
// error-pattern: cannot find macro `helper2!` in this scope
15+
16+
#[macro_use(public_macro)]
17+
extern crate local_inner_macros;
18+
19+
public_macro!();
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: cannot find macro `helper2!` in this scope
2+
--> $DIR/local_inner_macros_disabled.rs:19:1
3+
|
4+
LL | public_macro!();
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)