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))
format,
allow_internal_unstable,
allow_internal_unsafe,
+ local_inner_macros,
edition
});
format: MacroAttribute(Symbol::intern(name)),
allow_internal_unstable: true,
allow_internal_unsafe: false,
+ local_inner_macros: false,
edition: hygiene::default_edition(),
});
def_info: _,
allow_internal_unstable,
allow_internal_unsafe,
+ local_inner_macros,
unstable_feature,
edition,
} => {
def_info: Some((nid, self.krate_span)),
allow_internal_unstable,
allow_internal_unsafe,
+ local_inner_macros,
unstable_feature,
edition,
}
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
+ local_inner_macros: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
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";
/// 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
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
allow_internal_unstable: true,
allow_internal_unsafe: false,
+ local_inner_macros: false,
edition: hygiene::default_edition(),
});
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
allow_internal_unstable: false,
allow_internal_unsafe: false,
+ local_inner_macros: false,
edition: ext.edition(),
});
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| {
format: macro_bang_format(path),
allow_internal_unstable,
allow_internal_unsafe,
+ local_inner_macros,
edition,
});
Ok(())
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 {
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
format: macro_bang_format(path),
allow_internal_unstable,
allow_internal_unsafe: false,
+ local_inner_macros: false,
edition: hygiene::default_edition(),
});
// FIXME probably want to follow macro_rules macros here.
allow_internal_unstable,
allow_internal_unsafe: false,
+ local_inner_macros: false,
edition,
});
format: MacroAttribute(pretty_name),
allow_internal_unstable: false,
allow_internal_unsafe: false,
+ local_inner_macros: false,
edition: ext.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| {
def_info: Some((def.id, def.span)),
allow_internal_unstable,
allow_internal_unsafe,
+ local_inner_macros,
unstable_feature,
edition,
}
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))
format: MacroAttribute(Symbol::intern("test")),
allow_internal_unstable: true,
allow_internal_unsafe: false,
+ local_inner_macros: false,
edition: hygiene::default_edition(),
});
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
+ local_inner_macros: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
def_info: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
+ local_inner_macros: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
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);
/// 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,
}
def_info: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
+ local_inner_macros: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
--- /dev/null
+// 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!(); )
+}
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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() {}
--- /dev/null
+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
+