Skip to content

Commit

Permalink
Auto merge of #51496 - petrochenkov:mhelper2, r=nikomatsakis
Browse files Browse the repository at this point in the history
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`).
  • Loading branch information
bors committed Jun 27, 2018
2 parents c208243 + d347270 commit 142c98d
Show file tree
Hide file tree
Showing 19 changed files with 134 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ impl<'a> LoweringContext<'a> {
format: codemap::CompilerDesugaring(reason),
allow_internal_unstable: true,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: codemap::hygiene::default_edition(),
});
span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo {
format,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
edition
});

Expand Down
1 change: 1 addition & 0 deletions src/librustc_allocator/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
format: MacroAttribute(Symbol::intern(name)),
allow_internal_unstable: true,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: hygiene::default_edition(),
});

Expand Down
3 changes: 3 additions & 0 deletions src/librustc_plugin/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl<'a> Registry<'a> {
def_info: _,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition,
} => {
Expand All @@ -117,6 +118,7 @@ impl<'a> Registry<'a> {
def_info: Some((nid, self.krate_span)),
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition,
}
Expand Down Expand Up @@ -152,6 +154,7 @@ impl<'a> Registry<'a> {
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
Expand Down
9 changes: 8 additions & 1 deletion src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,11 +451,18 @@ impl<'a> Resolver<'a> {
kind: MacroKind, force: bool)
-> Result<Def, Determinacy> {
let ast::Path { ref segments, span } = *path;
let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
let invocation = self.invocations[&scope];
let module = invocation.module.get();
self.current_module = if module.is_trait() { module.parent.unwrap() } else { module };

// Possibly apply the macro helper hack
if self.use_extern_macros && kind == MacroKind::Bang && path.len() == 1 &&
path[0].span.ctxt().outer().expn_info().map_or(false, |info| info.local_inner_macros) {
let root = Ident::new(keywords::DollarCrate.name(), path[0].span);
path.insert(0, root);
}

if path.len() > 1 {
if !self.use_extern_macros && self.gated_errors.insert(span) {
let msg = "non-ident macro paths are experimental";
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,9 @@ pub enum SyntaxExtension {
/// Whether the contents of the macro can use `unsafe`
/// without triggering the `unsafe_code` lint.
allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
/// for a given macro.
local_inner_macros: bool,
/// The macro's feature name if it is unstable, and the stability feature
unstable_feature: Option<(Symbol, u32)>,
/// Edition of the crate in which the macro is defined
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/ext/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
allow_internal_unstable: true,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: hygiene::default_edition(),
});

Expand Down
10 changes: 9 additions & 1 deletion src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
allow_internal_unstable: false,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: ext.edition(),
});

Expand Down Expand Up @@ -695,6 +696,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
def_site_span: Option<Span>,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
// can't infer this type
unstable_feature: Option<(Symbol, u32)>,
edition| {
Expand Down Expand Up @@ -729,6 +731,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
format: macro_bang_format(path),
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
edition,
});
Ok(())
Expand All @@ -737,7 +740,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let opt_expanded = match *ext {
DeclMacro(ref expand, def_span, edition) => {
if let Err(dummy_span) = validate_and_set_expn_info(self, def_span.map(|(_, s)| s),
false, false, None,
false, false, false, None,
edition) {
dummy_span
} else {
Expand All @@ -750,12 +753,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
def_info,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition,
} => {
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition) {
dummy_span
Expand All @@ -777,6 +782,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
format: macro_bang_format(path),
allow_internal_unstable,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: hygiene::default_edition(),
});

Expand Down Expand Up @@ -816,6 +822,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
// FIXME probably want to follow macro_rules macros here.
allow_internal_unstable,
allow_internal_unsafe: false,
local_inner_macros: false,
edition,
});

Expand Down Expand Up @@ -890,6 +897,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
format: MacroAttribute(pretty_name),
allow_internal_unstable: false,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: ext.edition(),
};

Expand Down
7 changes: 7 additions & 0 deletions src/libsyntax/ext/tt/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,12 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition:
if body.legacy {
let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");
let mut local_inner_macros = false;
if let Some(macro_export) = attr::find_by_name(&def.attrs, "macro_export") {
if let Some(l) = macro_export.meta_item_list() {
local_inner_macros = attr::list_contains_name(&l, "local_inner_macros");
}
}

let unstable_feature = attr::find_stability(&sess.span_diagnostic,
&def.attrs, def.span).and_then(|stability| {
Expand All @@ -301,6 +307,7 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition:
def_info: Some((def.id, def.span)),
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition,
}
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/std_inject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ fn ignored_span(sp: Span) -> Span {
format: MacroAttribute(Symbol::intern("std_inject")),
allow_internal_unstable: true,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: hygiene::default_edition(),
});
sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ fn generate_test_harness(sess: &ParseSess,
format: MacroAttribute(Symbol::intern("test")),
allow_internal_unstable: true,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: hygiene::default_edition(),
});

Expand Down
2 changes: 2 additions & 0 deletions src/libsyntax_ext/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
Expand Down Expand Up @@ -132,6 +133,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
def_info: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_ext/proc_macro_registrar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
format: MacroAttribute(Symbol::intern("proc_macro")),
allow_internal_unstable: true,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: hygiene::default_edition(),
});
let span = DUMMY_SP.apply_mark(mark);
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax_pos/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,9 @@ pub struct ExpnInfo {
/// Whether the macro is allowed to use `unsafe` internally
/// even if the user crate has `#![forbid(unsafe_code)]`.
pub allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
/// for a given macro.
pub local_inner_macros: bool,
/// Edition of the crate in which the macro is defined.
pub edition: Edition,
}
Expand Down
1 change: 1 addition & 0 deletions src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/hygiene/auxiliary/local_inner_macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[macro_export]
macro_rules! helper1 {
() => ( struct S; )
}

#[macro_export(local_inner_macros)]
macro_rules! helper2 {
() => ( helper1!(); )
}

#[macro_export(local_inner_macros)]
macro_rules! public_macro {
() => ( helper2!(); )
}

#[macro_export(local_inner_macros)]
macro_rules! public_macro_dynamic {
($helper: ident) => ( $helper!(); )
}
31 changes: 31 additions & 0 deletions src/test/ui/hygiene/local_inner_macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-pass
// aux-build:local_inner_macros.rs

#![feature(use_extern_macros)]

extern crate local_inner_macros;

use local_inner_macros::{public_macro, public_macro_dynamic};

public_macro!();

macro_rules! local_helper {
() => ( struct Z; )
}

public_macro_dynamic!(local_helper);

fn main() {
let s = S;
let z = Z;
}
21 changes: 21 additions & 0 deletions src/test/ui/hygiene/local_inner_macros_disabled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// `local_inner_macros` has no effect if `feature(use_extern_macros)` is not enabled

// aux-build:local_inner_macros.rs
// error-pattern: cannot find macro `helper2!` in this scope

#[macro_use(public_macro)]
extern crate local_inner_macros;

public_macro!();

fn main() {}
10 changes: 10 additions & 0 deletions src/test/ui/hygiene/local_inner_macros_disabled.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: cannot find macro `helper2!` in this scope
--> $DIR/local_inner_macros_disabled.rs:19:1
|
LL | public_macro!();
| ^^^^^^^^^^^^^^^^
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error: aborting due to previous error

0 comments on commit 142c98d

Please sign in to comment.