Rollup merge of #61898 - petrochenkov:sekind, r=eddyb

syntax: Factor out common fields from `SyntaxExtension` variants

And some other related cleanups.

Continuation of https://github.com/rust-lang/rust/pull/61606.
This will also help to unblock https://github.com/rust-lang/rust/pull/61877.
This commit is contained in:
Mazdak Farrokhzad
2019-06-19 01:52:10 +02:00
committed by GitHub
26 changed files with 379 additions and 513 deletions
@@ -132,7 +132,7 @@ The advantages over a simple `fn(&str) -> u32` are:
In addition to procedural macros, you can define new
[`derive`](../../reference/attributes/derive.md)-like attributes and other kinds
of extensions. See `Registry::register_syntax_extension` and the
`SyntaxExtension` enum. For a more involved macro example, see
`SyntaxExtension` struct. For a more involved macro example, see
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
+14 -13
View File
@@ -62,14 +62,14 @@
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned};
use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned};
use syntax::source_map::CompilerDesugaringKind::IfTemporary;
use syntax::std_inject;
use syntax::symbol::{kw, sym, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::parse::token::{self, Token};
use syntax::visit::{self, Visitor};
use syntax_pos::{DUMMY_SP, edition, Span};
use syntax_pos::{DUMMY_SP, Span};
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
@@ -142,6 +142,9 @@ pub struct LoweringContext<'a> {
current_hir_id_owner: Vec<(DefIndex, u32)>,
item_local_id_counters: NodeMap<u32>,
node_id_to_hir_id: IndexVec<NodeId, hir::HirId>,
allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
}
pub trait Resolver {
@@ -267,6 +270,8 @@ pub fn lower_crate(
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
allow_try_trait: Some([sym::try_trait][..].into()),
allow_gen_future: Some([sym::gen_future][..].into()),
}.lower_crate(krate)
}
@@ -848,14 +853,10 @@ fn mark_span_with_reason(
allow_internal_unstable: Option<Lrc<[Symbol]>>,
) -> Span {
let mark = Mark::fresh(Mark::root());
mark.set_expn_info(source_map::ExpnInfo {
call_site: span,
mark.set_expn_info(ExpnInfo {
def_site: Some(span),
format: source_map::CompilerDesugaring(reason),
allow_internal_unstable,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: edition::Edition::from_session(),
..ExpnInfo::default(source_map::CompilerDesugaring(reason), span, self.sess.edition())
});
span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
}
@@ -1156,7 +1157,7 @@ fn make_async_expr(
let unstable_span = self.mark_span_with_reason(
CompilerDesugaringKind::Async,
span,
Some(vec![sym::gen_future].into()),
self.allow_gen_future.clone(),
);
let gen_future = self.expr_std_path(
unstable_span, &[sym::future, sym::from_generator], None, ThinVec::new());
@@ -4382,7 +4383,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
let unstable_span = this.mark_span_with_reason(
CompilerDesugaringKind::TryBlock,
body.span,
Some(vec![sym::try_trait].into()),
this.allow_try_trait.clone(),
);
let mut block = this.lower_block(body, true).into_inner();
let tail = block.expr.take().map_or_else(
@@ -4968,13 +4969,13 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
let unstable_span = self.mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
e.span,
Some(vec![sym::try_trait].into()),
self.allow_try_trait.clone(),
);
let try_span = self.sess.source_map().end_point(e.span);
let try_span = self.mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
try_span,
Some(vec![sym::try_trait].into()),
self.allow_try_trait.clone(),
);
// `Try::into_result(<expr>)`
@@ -5776,7 +5777,7 @@ fn lower_await(
let gen_future_span = self.mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
Some(vec![sym::gen_future].into()),
self.allow_gen_future.clone(),
);
// let mut pinned = <expr>;
+8 -1
View File
@@ -391,10 +391,17 @@ fn hash_stable<W: StableHasherResult>(&self,
NameValue(lit)
});
impl_stable_hash_for!(enum ::syntax_pos::hygiene::Transparency {
Transparent,
SemiTransparent,
Opaque,
});
impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo {
call_site,
def_site,
format,
def_site,
default_transparency,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
+7 -14
View File
@@ -19,7 +19,7 @@
mut_visit::{self, MutVisitor},
parse::ParseSess,
ptr::P,
symbol::{kw, sym, Symbol}
symbol::{kw, sym}
};
use syntax_pos::Span;
@@ -58,11 +58,10 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
fn flat_map_item(&mut self, item: P<Item>) -> SmallVec<[P<Item>; 1]> {
debug!("in submodule {}", self.in_submod);
let name = if attr::contains_name(&item.attrs, sym::global_allocator) {
"global_allocator"
} else {
if !attr::contains_name(&item.attrs, sym::global_allocator) {
return mut_visit::noop_flat_map_item(item, self);
};
}
match item.node {
ItemKind::Static(..) => {}
_ => {
@@ -87,15 +86,9 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
// Create a fresh Mark for the new macro expansion we are about to do
let mark = Mark::fresh(Mark::root());
mark.set_expn_info(ExpnInfo {
call_site: item.span, // use the call site of the static
def_site: None,
format: MacroAttribute(Symbol::intern(name)),
allow_internal_unstable: Some(vec![sym::rustc_attrs].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: self.sess.edition,
});
mark.set_expn_info(ExpnInfo::with_unstable(
MacroAttribute(sym::global_allocator), item.span, self.sess.edition, &[sym::rustc_attrs]
));
// Tie the span to the macro expansion info we just created
let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
+24 -26
View File
@@ -26,7 +26,7 @@
use syntax::ast;
use syntax::attr;
use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use syntax::symbol::{Symbol, sym};
use syntax::visit;
use syntax::{span_err, span_fatal};
@@ -611,33 +611,31 @@ fn load_derive_macros(&mut self, root: &CrateRoot<'_>, dylib: Option<PathBuf>, s
};
let extensions = decls.iter().map(|&decl| {
match decl {
let (name, kind, helper_attrs) = match decl {
ProcMacro::CustomDerive { trait_name, attributes, client } => {
let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
(trait_name, SyntaxExtension::Derive(
Box::new(ProcMacroDerive {
client,
attrs: attrs.clone(),
}),
attrs,
root.edition,
))
let helper_attrs =
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
(
trait_name,
SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive {
client, attrs: helper_attrs.clone()
})),
helper_attrs,
)
}
ProcMacro::Attr { name, client } => {
(name, SyntaxExtension::Attr(
Box::new(AttrProcMacro { client }),
root.edition,
))
}
ProcMacro::Bang { name, client } => {
(name, SyntaxExtension::Bang {
expander: Box::new(BangProcMacro { client }),
allow_internal_unstable: None,
edition: root.edition,
})
}
}
}).map(|(name, ext)| (Symbol::intern(name), Lrc::new(ext))).collect();
ProcMacro::Attr { name, client } => (
name, SyntaxExtensionKind::Attr(Box::new(AttrProcMacro { client })), Vec::new()
),
ProcMacro::Bang { name, client } => (
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
)
};
(Symbol::intern(name), Lrc::new(SyntaxExtension {
helper_attrs,
..SyntaxExtension::default(kind, root.edition)
}))
}).collect();
// Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long.
+6 -7
View File
@@ -30,9 +30,11 @@
use syntax::attr;
use syntax::source_map;
use syntax::edition::Edition;
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use syntax::parse::source_file_to_stream;
use syntax::parse::parser::emit_unclosed_delims;
use syntax::symbol::{Symbol, sym};
use syntax_ext::proc_macro_impl::BangProcMacro;
use syntax_pos::{Span, NO_EXPANSION, FileName};
use rustc_data_structures::bit_set::BitSet;
@@ -427,14 +429,11 @@ pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
if let Some(ref proc_macros) = data.proc_macros {
return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
} else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote {
use syntax::ext::base::SyntaxExtension;
use syntax_ext::proc_macro_impl::BangProcMacro;
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
let ext = SyntaxExtension::Bang {
expander: Box::new(BangProcMacro { client }),
allow_internal_unstable: Some(vec![sym::proc_macro_def_site].into()),
edition: data.root.edition,
let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }));
let ext = SyntaxExtension {
allow_internal_unstable: Some([sym::proc_macro_def_site][..].into()),
..SyntaxExtension::default(kind, data.root.edition)
};
return LoadedMacro::ProcMacro(Lrc::new(ext));
}
+4 -3
View File
@@ -509,8 +509,9 @@ pub fn def_kind(&self, index: DefIndex) -> Option<DefKind> {
if !self.is_proc_macro(index) {
self.entry(index).kind.def_kind()
} else {
let kind = self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.kind();
Some(DefKind::Macro(kind))
Some(DefKind::Macro(
self.proc_macros.as_ref().unwrap()[index.to_proc_macro_index()].1.macro_kind()
))
}
}
@@ -737,7 +738,7 @@ pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Sessio
if id == CRATE_DEF_INDEX {
for (id, &(name, ref ext)) in proc_macros.iter().enumerate() {
let res = Res::Def(
DefKind::Macro(ext.kind()),
DefKind::Macro(ext.macro_kind()),
self.local_def_id(DefIndex::from_proc_macro_index(id)),
);
let ident = Ident::with_empty_ctxt(name);
+7 -15
View File
@@ -4,9 +4,8 @@
use rustc::session::Session;
use rustc::util::nodemap::FxHashMap;
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension};
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, NamedSyntaxExtension};
use syntax::ext::base::MacroExpanderFn;
use syntax::ext::hygiene::Transparency;
use syntax::symbol::{Symbol, sym};
use syntax::ast;
use syntax::feature_gate::AttributeType;
@@ -89,8 +88,8 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: Synt
if name == sym::macro_rules {
panic!("user-defined macros may not be named `macro_rules`");
}
if let SyntaxExtension::LegacyBang { def_info: ref mut def_info @ None, .. } = extension {
*def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
if extension.def_info.is_none() {
extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
}
self.syntax_exts.push((name, extension));
}
@@ -98,19 +97,12 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: Synt
/// Register a macro of the usual kind.
///
/// This is a convenience wrapper for `register_syntax_extension`.
/// It builds for you a `SyntaxExtension::LegacyBang` that calls `expander`,
/// It builds for you a `SyntaxExtensionKind::LegacyBang` that calls `expander`,
/// and also takes care of interning the macro's name.
pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
self.register_syntax_extension(Symbol::intern(name), SyntaxExtension::LegacyBang {
expander: Box::new(expander),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition: self.sess.edition(),
});
let kind = SyntaxExtensionKind::LegacyBang(Box::new(expander));
let ext = SyntaxExtension::default(kind, self.sess.edition());
self.register_syntax_extension(Symbol::intern(name), ext);
}
/// Register a compiler lint pass.
+2 -3
View File
@@ -772,9 +772,8 @@ pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
pub fn get_macro(&mut self, res: Res) -> Lrc<SyntaxExtension> {
let def_id = match res {
Res::Def(DefKind::Macro(..), def_id) => def_id,
Res::NonMacroAttr(attr_kind) => return Lrc::new(SyntaxExtension::NonMacroAttr {
mark_used: attr_kind == NonMacroAttrKind::Tool,
}),
Res::NonMacroAttr(attr_kind) =>
return self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool),
_ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"),
};
if let Some(ext) = self.macro_map.get(&def_id) {
+11 -1
View File
@@ -41,7 +41,7 @@
use syntax::source_map::SourceMap;
use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext};
use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::base::MacroKind;
use syntax::symbol::{Symbol, kw, sym};
@@ -1668,6 +1668,7 @@ pub struct Resolver<'a> {
macro_use_prelude: FxHashMap<Name, &'a NameBinding<'a>>,
pub all_macros: FxHashMap<Name, Res>,
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
non_macro_attrs: [Lrc<SyntaxExtension>; 2],
macro_defs: FxHashMap<Mark, DefId>,
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
@@ -1941,6 +1942,10 @@ pub fn new(session: &'a Session,
let mut macro_defs = FxHashMap::default();
macro_defs.insert(Mark::root(), root_def_id);
let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::default(
SyntaxExtensionKind::NonMacroAttr { mark_used }, session.edition()
));
Resolver {
session,
@@ -2014,6 +2019,7 @@ pub fn new(session: &'a Session,
macro_use_prelude: FxHashMap::default(),
all_macros: FxHashMap::default(),
macro_map: FxHashMap::default(),
non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
invocations,
macro_defs,
local_macro_def_scopes: FxHashMap::default(),
@@ -2030,6 +2036,10 @@ pub fn arenas() -> ResolverArenas<'a> {
Default::default()
}
fn non_macro_attr(&self, mark_used: bool) -> Lrc<SyntaxExtension> {
self.non_macro_attrs[mark_used as usize].clone()
}
/// Runs the function on each namespace.
fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) {
f(self, TypeNS);
+34 -23
View File
@@ -114,6 +114,22 @@ enum SubNS { Bang, AttrLike }
candidate.is_none() || requirement.is_none() || candidate == requirement
}
// We don't want to format a path using pretty-printing,
// `format!("{}", path)`, because that tries to insert
// line-breaks and is slow.
fn fast_print_path(path: &ast::Path) -> String {
let mut path_str = String::with_capacity(64);
for (i, segment) in path.segments.iter().enumerate() {
if i != 0 {
path_str.push_str("::");
}
if segment.ident.name != kw::PathRoot {
path_str.push_str(&segment.ident.as_str())
}
}
path_str
}
impl<'a> base::Resolver for Resolver<'a> {
fn next_node_id(&mut self) -> ast::NodeId {
self.session.next_node_id()
@@ -174,7 +190,7 @@ fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
krate: CrateNum::BuiltinMacros,
index: DefIndex::from(self.macro_map.len()),
};
let kind = ext.kind();
let kind = ext.macro_kind();
self.macro_map.insert(def_id, ext);
let binding = self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Res(Res::Def(DefKind::Macro(kind), def_id), false),
@@ -209,14 +225,19 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force
let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) {
Ok((res, ext)) => (res, ext),
Err(Determinacy::Determined) if kind == MacroKind::Attr => {
// Replace unresolved attributes with used inert attributes for better recovery.
return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr { mark_used: true })));
}
// Replace unresolved attributes with used inert attributes for better recovery.
Err(Determinacy::Determined) if kind == MacroKind::Attr =>
(Res::Err, self.non_macro_attr(true)),
Err(determinacy) => return Err(determinacy),
};
if let Res::Def(DefKind::Macro(_), def_id) = res {
let format = match kind {
MacroKind::Derive => format!("derive({})", fast_print_path(path)),
_ => fast_print_path(path),
};
invoc.expansion_data.mark.set_expn_info(ext.expn_info(invoc.span(), &format));
if let Res::Def(_, def_id) = res {
if after_derive {
self.session.span_err(invoc.span(),
"macro attributes must be placed before `#[derive]`");
@@ -226,7 +247,6 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force
self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id;
self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.mark,
normal_module_def_id);
invoc.expansion_data.mark.set_default_transparency(ext.default_transparency());
}
Ok(Some(ext))
@@ -241,11 +261,7 @@ fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Ma
fn check_unused_macros(&self) {
for did in self.unused_macros.iter() {
let id_span = match *self.macro_map[did] {
SyntaxExtension::LegacyBang { def_info, .. } => def_info,
_ => None,
};
if let Some((id, span)) = id_span {
if let Some((id, span)) = self.macro_map[did].def_info {
let lint = lint::builtin::UNUSED_MACROS;
let msg = "unused macro definition";
self.session.buffer_lint(lint, id, span, msg);
@@ -585,17 +601,12 @@ struct Flags: u8 {
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
match self.resolve_macro_to_res(derive, MacroKind::Derive,
&parent_scope, true, force) {
Ok((_, ext)) => {
if let SyntaxExtension::Derive(_, helpers, _) = &*ext {
if helpers.contains(&ident.name) {
let binding =
(Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
ty::Visibility::Public, derive.span, Mark::root())
.to_name_binding(self.arenas);
result = Ok((binding, Flags::empty()));
break;
}
}
Ok((_, ext)) => if ext.helper_attrs.contains(&ident.name) {
let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
ty::Visibility::Public, derive.span, Mark::root())
.to_name_binding(self.arenas);
result = Ok((binding, Flags::empty()));
break;
}
Err(Determinacy::Determined) => {}
Err(Determinacy::Undetermined) =>
+3 -9
View File
@@ -3,7 +3,7 @@
use std::iter::once;
use syntax::ast;
use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::base::MacroKind;
use syntax::symbol::sym;
use syntax_pos::Span;
@@ -470,18 +470,12 @@ fn build_macro(cx: &DocContext<'_>, did: DefId, name: ast::Name) -> clean::ItemE
})
}
LoadedMacro::ProcMacro(ext) => {
let helpers = match &*ext {
&SyntaxExtension::Derive(_, ref syms, ..) => { syms.clean(cx) }
_ => Vec::new(),
};
clean::ProcMacroItem(clean::ProcMacro {
kind: ext.kind(),
helpers,
kind: ext.macro_kind(),
helpers: ext.helper_attrs.clean(cx),
})
}
}
}
/// A trait's generics clause actually contains all of the predicates for all of
@@ -423,7 +423,7 @@ fn fold_crate(&mut self, mut c: Crate) -> Crate {
/// Resolves a string as a macro.
fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::base::{MacroKind, SyntaxExtensionKind};
let segment = ast::PathSegment::from_ident(Ident::from_str(path_str));
let path = ast::Path { segments: vec![segment], span: DUMMY_SP };
cx.enter_resolver(|resolver| {
@@ -433,7 +433,7 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
if let Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) = res {
// skip proc-macro stubs, they'll cause `get_macro` to crash
} else {
if let SyntaxExtension::LegacyBang { .. } = *resolver.get_macro(res) {
if let SyntaxExtensionKind::LegacyBang(..) = resolver.get_macro(res).kind {
return Some(res.map_id(|_| panic!("unexpected id")));
}
}
+88 -86
View File
@@ -15,6 +15,7 @@
use errors::{DiagnosticBuilder, DiagnosticId};
use smallvec::{smallvec, SmallVec};
use syntax_pos::{Span, MultiSpan, DUMMY_SP};
use syntax_pos::hygiene::{ExpnInfo, ExpnFormat};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{self, Lrc};
@@ -548,37 +549,19 @@ pub fn article(self) -> &'static str {
}
}
/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
/// A syntax extension kind.
pub enum SyntaxExtensionKind {
/// A token-based function-like macro.
Bang {
Bang(
/// An expander with signature TokenStream -> TokenStream.
expander: Box<dyn ProcMacro + sync::Sync + sync::Send>,
/// Whitelist of unstable features that are treated as stable inside this macro.
allow_internal_unstable: Option<Lrc<[Symbol]>>,
/// Edition of the crate in which this macro is defined.
edition: Edition,
},
Box<dyn ProcMacro + sync::Sync + sync::Send>,
),
/// An AST-based function-like macro.
LegacyBang {
LegacyBang(
/// An expander with signature TokenStream -> AST.
expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
/// Some info about the macro's definition point.
def_info: Option<(ast::NodeId, Span)>,
/// Hygienic properties of identifiers produced by this macro.
transparency: Transparency,
/// Whitelist of unstable features that are treated as stable inside this macro.
allow_internal_unstable: Option<Lrc<[Symbol]>>,
/// Suppresses the `unsafe_code` lint for code produced by this macro.
allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
local_inner_macros: bool,
/// The macro's feature name and tracking issue number if it is unstable.
unstable_feature: Option<(Symbol, u32)>,
/// Edition of the crate in which this macro is defined.
edition: Edition,
},
Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
),
/// A token-based attribute macro.
Attr(
@@ -586,8 +569,6 @@ pub enum SyntaxExtension {
/// The first TokenSteam is the attribute itself, the second is the annotated item.
/// The produced TokenSteam replaces the input TokenSteam.
Box<dyn AttrProcMacro + sync::Sync + sync::Send>,
/// Edition of the crate in which this macro is defined.
Edition,
),
/// An AST-based attribute macro.
@@ -599,7 +580,8 @@ pub enum SyntaxExtension {
),
/// A trivial attribute "macro" that does nothing,
/// only keeps the attribute and marks it as known.
/// only keeps the attribute and marks it as inert,
/// thus making it ineligible for further expansion.
NonMacroAttr {
/// Suppresses the `unused_attributes` lint for this attribute.
mark_used: bool,
@@ -610,10 +592,6 @@ pub enum SyntaxExtension {
/// An expander with signature TokenStream -> TokenStream (not yet).
/// The produced TokenSteam is appended to the input TokenSteam.
Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
/// Names of helper attributes registered by this macro.
Vec<Symbol>,
/// Edition of the crate in which this macro is defined.
Edition,
),
/// An AST-based derive macro.
@@ -624,42 +602,91 @@ pub enum SyntaxExtension {
),
}
/// A struct representing a macro definition in "lowered" form ready for expansion.
pub struct SyntaxExtension {
/// A syntax extension kind.
pub kind: SyntaxExtensionKind,
/// Some info about the macro's definition point.
pub def_info: Option<(ast::NodeId, Span)>,
/// Hygienic properties of spans produced by this macro by default.
pub default_transparency: Transparency,
/// Whitelist of unstable features that are treated as stable inside this macro.
pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
/// Suppresses the `unsafe_code` lint for code produced by this macro.
pub allow_internal_unsafe: bool,
/// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
pub local_inner_macros: bool,
/// The macro's feature name and tracking issue number if it is unstable.
pub unstable_feature: Option<(Symbol, u32)>,
/// Names of helper attributes registered by this macro.
pub helper_attrs: Vec<Symbol>,
/// Edition of the crate in which this macro is defined.
pub edition: Edition,
}
impl SyntaxExtensionKind {
/// When a syntax extension is constructed,
/// its transparency can often be inferred from its kind.
fn default_transparency(&self) -> Transparency {
match self {
SyntaxExtensionKind::Bang(..) |
SyntaxExtensionKind::Attr(..) |
SyntaxExtensionKind::Derive(..) |
SyntaxExtensionKind::NonMacroAttr { .. } => Transparency::Opaque,
SyntaxExtensionKind::LegacyBang(..) |
SyntaxExtensionKind::LegacyAttr(..) |
SyntaxExtensionKind::LegacyDerive(..) => Transparency::SemiTransparent,
}
}
}
impl SyntaxExtension {
/// Returns which kind of macro calls this syntax extension.
pub fn kind(&self) -> MacroKind {
match *self {
SyntaxExtension::Bang { .. } |
SyntaxExtension::LegacyBang { .. } => MacroKind::Bang,
SyntaxExtension::Attr(..) |
SyntaxExtension::LegacyAttr(..) |
SyntaxExtension::NonMacroAttr { .. } => MacroKind::Attr,
SyntaxExtension::Derive(..) |
SyntaxExtension::LegacyDerive(..) => MacroKind::Derive,
pub fn macro_kind(&self) -> MacroKind {
match self.kind {
SyntaxExtensionKind::Bang(..) |
SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
SyntaxExtensionKind::Attr(..) |
SyntaxExtensionKind::LegacyAttr(..) |
SyntaxExtensionKind::NonMacroAttr { .. } => MacroKind::Attr,
SyntaxExtensionKind::Derive(..) |
SyntaxExtensionKind::LegacyDerive(..) => MacroKind::Derive,
}
}
pub fn default_transparency(&self) -> Transparency {
match *self {
SyntaxExtension::LegacyBang { transparency, .. } => transparency,
SyntaxExtension::Bang { .. } |
SyntaxExtension::Attr(..) |
SyntaxExtension::Derive(..) |
SyntaxExtension::NonMacroAttr { .. } => Transparency::Opaque,
SyntaxExtension::LegacyAttr(..) |
SyntaxExtension::LegacyDerive(..) => Transparency::SemiTransparent,
/// Constructs a syntax extension with default properties.
pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension {
SyntaxExtension {
def_info: None,
default_transparency: kind.default_transparency(),
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
helper_attrs: Vec::new(),
edition,
kind,
}
}
pub fn edition(&self, default_edition: Edition) -> Edition {
match *self {
SyntaxExtension::Bang { edition, .. } |
SyntaxExtension::LegacyBang { edition, .. } |
SyntaxExtension::Attr(.., edition) |
SyntaxExtension::Derive(.., edition) => edition,
// Unstable legacy stuff
SyntaxExtension::NonMacroAttr { .. } |
SyntaxExtension::LegacyAttr(..) |
SyntaxExtension::LegacyDerive(..) => default_edition,
fn expn_format(&self, symbol: Symbol) -> ExpnFormat {
match self.kind {
SyntaxExtensionKind::Bang(..) |
SyntaxExtensionKind::LegacyBang(..) => ExpnFormat::MacroBang(symbol),
_ => ExpnFormat::MacroAttribute(symbol),
}
}
pub fn expn_info(&self, call_site: Span, format: &str) -> ExpnInfo {
ExpnInfo {
call_site,
format: self.expn_format(Symbol::intern(format)),
def_site: self.def_info.map(|(_, span)| span),
default_transparency: self.default_transparency,
allow_internal_unstable: self.allow_internal_unstable.clone(),
allow_internal_unsafe: self.allow_internal_unsafe,
local_inner_macros: self.local_inner_macros,
edition: self.edition,
}
}
}
@@ -699,31 +726,6 @@ pub fn determined(determined: bool) -> Determinacy {
}
}
pub struct DummyResolver;
impl Resolver for DummyResolver {
fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
fn resolve_dollar_crates(&mut self, _fragment: &AstFragment) {}
fn visit_ast_fragment_with_placeholders(&mut self, _invoc: Mark, _fragment: &AstFragment,
_derives: &[Mark]) {}
fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {}
fn resolve_imports(&mut self) {}
fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _invoc_id: Mark, _force: bool)
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
Err(Determinacy::Determined)
}
fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _invoc_id: Mark,
_derives_in_scope: Vec<ast::Path>, _force: bool)
-> Result<Lrc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
}
fn check_unused_macros(&self) {}
}
#[derive(Clone)]
pub struct ModuleData {
pub mod_path: Vec<ast::Ident>,
+4 -9
View File
@@ -60,15 +60,10 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P
}
pretty_name.push(')');
cx.current_expansion.mark.set_expn_info(ExpnInfo {
call_site: span,
def_site: None,
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
allow_internal_unstable: Some(vec![sym::rustc_attrs, sym::structural_match].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: cx.parse_sess.edition,
});
cx.current_expansion.mark.set_expn_info(ExpnInfo::with_unstable(
ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), span, cx.parse_sess.edition,
&[sym::rustc_attrs, sym::structural_match],
));
let span = span.with_ctxt(cx.backtrace());
item.visit_attrs(|attrs| {
+35 -145
View File
@@ -1,7 +1,7 @@
use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path};
use crate::ast::{MacStmtStyle, StmtKind, ItemKind};
use crate::attr::{self, HasAttrs};
use crate::source_map::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan};
use crate::source_map::{dummy_spanned, respan};
use crate::config::StripUnconfigured;
use crate::ext::base::*;
use crate::ext::derive::{add_derived_markers, collect_derives};
@@ -22,7 +22,6 @@
use errors::{Applicability, FatalError};
use smallvec::{smallvec, SmallVec};
use syntax_pos::{Span, DUMMY_SP, FileName};
use syntax_pos::hygiene::ExpnFormat;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
@@ -189,23 +188,6 @@ fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(self, items: I)
}
}
fn macro_bang_format(path: &ast::Path) -> ExpnFormat {
// We don't want to format a path using pretty-printing,
// `format!("{}", path)`, because that tries to insert
// line-breaks and is slow.
let mut path_str = String::with_capacity(64);
for (i, segment) in path.segments.iter().enumerate() {
if i != 0 {
path_str.push_str("::");
}
if segment.ident.name != kw::PathRoot {
path_str.push_str(&segment.ident.as_str())
}
}
MacroBang(Symbol::intern(&path_str))
}
pub struct Invocation {
pub kind: InvocationKind,
fragment_kind: AstFragmentKind,
@@ -388,8 +370,8 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
derives.push(mark);
let item = match self.cx.resolver.resolve_macro_path(
path, MacroKind::Derive, Mark::root(), Vec::new(), false) {
Ok(ext) => match *ext {
SyntaxExtension::LegacyDerive(..) => item_with_markers.clone(),
Ok(ext) => match ext.kind {
SyntaxExtensionKind::LegacyDerive(..) => item_with_markers.clone(),
_ => item.clone(),
},
_ => item.clone(),
@@ -509,7 +491,7 @@ fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option<AstFragment> {
if invoc.fragment_kind == AstFragmentKind::ForeignItems &&
!self.cx.ecfg.macros_in_extern_enabled() {
if let SyntaxExtension::NonMacroAttr { .. } = *ext {} else {
if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else {
emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
invoc.span(), GateIssue::Language,
"macro invocations in `extern {}` blocks are experimental");
@@ -548,34 +530,22 @@ fn expand_attr_invoc(&mut self,
_ => unreachable!(),
};
if let SyntaxExtension::NonMacroAttr { mark_used: false } = *ext {} else {
// Macro attrs are always used when expanded,
// non-macro attrs are considered used when the field says so.
attr::mark_used(&attr);
}
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: attr.span,
def_site: None,
format: MacroAttribute(Symbol::intern(&attr.path.to_string())),
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: ext.edition(self.cx.parse_sess.edition),
});
match *ext {
SyntaxExtension::NonMacroAttr { .. } => {
match &ext.kind {
SyntaxExtensionKind::NonMacroAttr { mark_used } => {
attr::mark_known(&attr);
if *mark_used {
attr::mark_used(&attr);
}
item.visit_attrs(|attrs| attrs.push(attr));
Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
}
SyntaxExtension::LegacyAttr(ref mac) => {
SyntaxExtensionKind::LegacyAttr(expander) => {
let meta = attr.parse_meta(self.cx.parse_sess)
.map_err(|mut e| { e.emit(); }).ok()?;
let item = mac.expand(self.cx, attr.span, &meta, item);
let item = expander.expand(self.cx, attr.span, &meta, item);
Some(invoc.fragment_kind.expect_from_annotatables(item))
}
SyntaxExtension::Attr(ref mac, ..) => {
SyntaxExtensionKind::Attr(expander) => {
self.gate_proc_macro_attr_item(attr.span, &item);
let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item {
Annotatable::Item(item) => token::NtItem(item),
@@ -586,13 +556,13 @@ fn expand_attr_invoc(&mut self,
Annotatable::Expr(expr) => token::NtExpr(expr),
})), DUMMY_SP).into();
let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span);
let tok_result = mac.expand(self.cx, attr.span, input, item_tok);
let tok_result = expander.expand(self.cx, attr.span, input, item_tok);
let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind,
&attr.path, attr.span);
self.gate_proc_macro_expansion(attr.span, &res);
res
}
SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path));
self.cx.trace_macros_diag();
invoc.fragment_kind.dummy(attr.span)
@@ -693,7 +663,7 @@ fn expand_bang_invoc(&mut self,
invoc: Invocation,
ext: &SyntaxExtension)
-> Option<AstFragment> {
let (mark, kind) = (invoc.expansion_data.mark, invoc.fragment_kind);
let kind = invoc.fragment_kind;
let (mac, ident, span) = match invoc.kind {
InvocationKind::Bang { mac, ident, span } => (mac, ident, span),
_ => unreachable!(),
@@ -701,21 +671,13 @@ fn expand_bang_invoc(&mut self,
let path = &mac.node.path;
let ident = ident.unwrap_or_else(|| Ident::invalid());
let validate_and_set_expn_info = |this: &mut Self, // arg instead of capture
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| {
let validate = |this: &mut Self| {
// feature-gate the macro invocation
if let Some((feature, issue)) = unstable_feature {
if let Some((feature, issue)) = ext.unstable_feature {
let crate_span = this.cx.current_expansion.crate_span.unwrap();
// don't stability-check macros in the same crate
// (the only time this is null is for syntax extensions registered as macros)
if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span))
if ext.def_info.map_or(false, |(_, def_span)| !crate_span.contains(def_span))
&& !span.allows_unstable(feature)
&& this.cx.ecfg.features.map_or(true, |feats| {
// macro features will count as lib features
@@ -734,62 +696,39 @@ fn expand_bang_invoc(&mut self,
this.cx.trace_macros_diag();
return Err(kind.dummy(span));
}
mark.set_expn_info(ExpnInfo {
call_site: span,
def_site: def_site_span,
format: macro_bang_format(path),
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
edition,
});
Ok(())
};
let opt_expanded = match *ext {
SyntaxExtension::LegacyBang {
ref expander,
def_info,
ref 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.clone(),
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
edition) {
let opt_expanded = match &ext.kind {
SyntaxExtensionKind::LegacyBang(expander) => {
if let Err(dummy_span) = validate(self) {
dummy_span
} else {
kind.make_from(expander.expand(
self.cx,
span,
mac.node.stream(),
def_info.map(|(_, s)| s),
ext.def_info.map(|(_, s)| s),
))
}
}
SyntaxExtension::Attr(..) |
SyntaxExtension::LegacyAttr(..) |
SyntaxExtension::NonMacroAttr { .. } => {
SyntaxExtensionKind::Attr(..) |
SyntaxExtensionKind::LegacyAttr(..) |
SyntaxExtensionKind::NonMacroAttr { .. } => {
self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path));
self.cx.trace_macros_diag();
kind.dummy(span)
}
SyntaxExtension::Derive(..) | SyntaxExtension::LegacyDerive(..) => {
SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
self.cx.span_err(path.span, &format!("`{}` is a derive macro", path));
self.cx.trace_macros_diag();
kind.dummy(span)
}
SyntaxExtension::Bang { ref expander, ref allow_internal_unstable, edition } => {
SyntaxExtensionKind::Bang(expander) => {
if ident.name != kw::Invalid {
let msg =
format!("macro {}! expects no ident argument, given '{}'", path, ident);
@@ -798,19 +737,6 @@ fn expand_bang_invoc(&mut self,
kind.dummy(span)
} else {
self.gate_proc_macro_expansion_kind(span, kind);
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: span,
// FIXME procedural macros do not have proper span info
// yet, when they do, we should use it here.
def_site: None,
format: macro_bang_format(path),
// FIXME probably want to follow macro_rules macros here.
allow_internal_unstable: allow_internal_unstable.clone(),
allow_internal_unsafe: false,
local_inner_macros: false,
edition,
});
let tok_result = expander.expand(self.cx, span, mac.node.stream());
let result = self.parse_ast_fragment(tok_result, kind, path, span);
self.gate_proc_macro_expansion(span, &result);
@@ -867,55 +793,19 @@ fn expand_derive_invoc(&mut self,
return None;
}
let pretty_name = Symbol::intern(&format!("derive({})", path));
let span = path.span;
let attr = ast::Attribute {
path, span,
tokens: TokenStream::empty(),
// irrelevant:
id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false,
};
let mut expn_info = ExpnInfo {
call_site: span,
def_site: None,
format: MacroAttribute(pretty_name),
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
edition: ext.edition(self.cx.parse_sess.edition),
};
match ext {
SyntaxExtension::Derive(expander, ..) | SyntaxExtension::LegacyDerive(expander) => {
let meta = match ext {
SyntaxExtension::Derive(..) => ast::MetaItem { // FIXME(jseyfried) avoid this
path: Path::from_ident(Ident::invalid()),
span: DUMMY_SP,
node: ast::MetaItemKind::Word,
},
_ => {
expn_info.allow_internal_unstable = Some(vec![
sym::rustc_attrs,
Symbol::intern("derive_clone_copy"),
Symbol::intern("derive_eq"),
// RustcDeserialize and RustcSerialize
Symbol::intern("libstd_sys_internals"),
].into());
attr.meta()?
}
};
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = span.with_ctxt(self.cx.backtrace());
match &ext.kind {
SyntaxExtensionKind::Derive(expander) |
SyntaxExtensionKind::LegacyDerive(expander) => {
let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path };
let span = meta.span.with_ctxt(self.cx.backtrace());
let items = expander.expand(self.cx, span, &meta, item);
Some(invoc.fragment_kind.expect_from_annotatables(items))
}
_ => {
let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
self.cx.span_err(span, msg);
let msg = &format!("macro `{}` may not be used for derive attributes", path);
self.cx.span_err(path.span, msg);
self.cx.trace_macros_diag();
invoc.fragment_kind.dummy(span)
invoc.fragment_kind.dummy(path.span)
}
}
}
+7 -5
View File
@@ -1,6 +1,7 @@
use crate::{ast, attr};
use crate::edition::Edition;
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension, TTMacroExpander};
use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
use crate::ext::expand::{AstFragment, AstFragmentKind};
use crate::ext::hygiene::Transparency;
use crate::ext::tt::macro_parser::{Success, Error, Failure};
@@ -376,7 +377,7 @@ pub fn compile(
valid,
});
let transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
let default_transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
Transparency::Transparent
} else if body.legacy {
Transparency::SemiTransparent
@@ -426,14 +427,15 @@ pub fn compile(
}
});
SyntaxExtension::LegacyBang {
expander,
SyntaxExtension {
kind: SyntaxExtensionKind::LegacyBang(expander),
def_info: Some((def.id, def.span)),
transparency,
default_transparency,
allow_internal_unstable,
allow_internal_unsafe,
local_inner_macros,
unstable_feature,
helper_attrs: Vec::new(),
edition,
}
}
+3 -9
View File
@@ -16,15 +16,9 @@
/// The expanded code uses the unstable `#[prelude_import]` attribute.
fn ignored_span(sp: Span, edition: Edition) -> Span {
let mark = Mark::fresh(Mark::root());
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
format: MacroAttribute(Symbol::intern("std_inject")),
allow_internal_unstable: Some(vec![sym::prelude_import].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition,
});
mark.set_expn_info(ExpnInfo::with_unstable(
MacroAttribute(Symbol::intern("std_inject")), sp, edition, &[sym::prelude_import]
));
sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
}
+4 -9
View File
@@ -280,15 +280,10 @@ fn generate_test_harness(sess: &ParseSess,
test_runner
};
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
format: MacroAttribute(sym::test_case),
allow_internal_unstable: Some(vec![sym::main, sym::test, sym::rustc_attrs].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: sess.edition,
});
mark.set_expn_info(ExpnInfo::with_unstable(
MacroAttribute(sym::test_case), DUMMY_SP, sess.edition,
&[sym::main, sym::test, sym::rustc_attrs],
));
TestHarnessGenerator {
cx,
+21 -19
View File
@@ -2,9 +2,10 @@
use rustc_data_structures::sync::Lrc;
use syntax::ast::{self, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver, MultiItemModifier};
use syntax::edition::Edition;
use syntax::ext::base::{Annotatable, ExtCtxt, Resolver, MultiItemModifier};
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use syntax::ext::build::AstBuilder;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ptr::P;
use syntax::symbol::{Symbol, sym};
use syntax_pos::Span;
@@ -67,11 +68,25 @@ pub fn is_builtin_trait(name: ast::Name) -> bool {
}
}
pub fn register_builtin_derives(resolver: &mut dyn Resolver) {
pub fn register_builtin_derives(resolver: &mut dyn Resolver, edition: Edition) {
let allow_internal_unstable = Some([
sym::core_intrinsics,
sym::rustc_attrs,
Symbol::intern("derive_clone_copy"),
Symbol::intern("derive_eq"),
Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
][..].into());
$(
resolver.add_builtin(
ast::Ident::with_empty_ctxt(Symbol::intern($name)),
Lrc::new(SyntaxExtension::LegacyDerive(Box::new(BuiltinDerive($func))))
Lrc::new(SyntaxExtension {
allow_internal_unstable: allow_internal_unstable.clone(),
..SyntaxExtension::default(
SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($func))),
edition,
)
}),
);
)*
}
@@ -148,24 +163,11 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt<'_>,
mut span: Span,
span: Span,
intrinsic: &str,
args: Vec<P<ast::Expr>>)
-> P<ast::Expr> {
let intrinsic_allowed_via_allow_internal_unstable = cx
.current_expansion.mark.expn_info().unwrap()
.allow_internal_unstable.map_or(false, |features| features.iter().any(|&s|
s == sym::core_intrinsics
));
if intrinsic_allowed_via_allow_internal_unstable {
span = span.with_ctxt(cx.backtrace());
} else { // Avoid instability errors with user defined curstom derives, cc #36316
let mut info = cx.current_expansion.mark.expn_info().unwrap();
info.allow_internal_unstable = Some(vec![sym::core_intrinsics].into());
let mark = Mark::fresh(Mark::root());
mark.set_expn_info(info);
span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
}
let span = span.with_ctxt(cx.backtrace());
let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
let call = cx.expr_call_global(span, path, args);
+31 -39
View File
@@ -43,32 +43,31 @@
use rustc_data_structures::sync::Lrc;
use syntax::ast;
use syntax::ext::base::{MacroExpanderFn, NamedSyntaxExtension, SyntaxExtension};
use syntax::ext::hygiene::Transparency;
use syntax::ext::base::MacroExpanderFn;
use syntax::ext::base::{NamedSyntaxExtension, SyntaxExtension, SyntaxExtensionKind};
use syntax::edition::Edition;
use syntax::symbol::{sym, Symbol};
pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
user_exts: Vec<NamedSyntaxExtension>,
edition: Edition) {
deriving::register_builtin_derives(resolver);
deriving::register_builtin_derives(resolver, edition);
let mut register = |name, ext| {
resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Lrc::new(ext));
};
macro_rules! register {
($( $name:ident: $f:expr, )*) => { $(
register(Symbol::intern(stringify!($name)),
SyntaxExtension::LegacyBang {
expander: Box::new($f as MacroExpanderFn),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition,
});
register(Symbol::intern(stringify!($name)), SyntaxExtension::default(
SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)), edition
));
)* }
}
macro_rules! register_attr {
($( $name:ident: $f:expr, )*) => { $(
register(Symbol::intern(stringify!($name)), SyntaxExtension::default(
SyntaxExtensionKind::LegacyAttr(Box::new($f)), edition
));
)* }
}
@@ -97,33 +96,26 @@ macro_rules! register {
assert: assert::expand_assert,
}
register(sym::test_case, SyntaxExtension::LegacyAttr(Box::new(test_case::expand)));
register(sym::test, SyntaxExtension::LegacyAttr(Box::new(test::expand_test)));
register(sym::bench, SyntaxExtension::LegacyAttr(Box::new(test::expand_bench)));
register_attr! {
test_case: test_case::expand,
test: test::expand_test,
bench: test::expand_bench,
}
// format_args uses `unstable` things internally.
register(Symbol::intern("format_args"),
SyntaxExtension::LegacyBang {
expander: Box::new(format::expand_format_args),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition,
});
register(sym::format_args_nl,
SyntaxExtension::LegacyBang {
expander: Box::new(format::expand_format_args_nl),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: Some(vec![sym::fmt_internals].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition,
});
let allow_internal_unstable = Some([sym::fmt_internals][..].into());
register(Symbol::intern("format_args"), SyntaxExtension {
allow_internal_unstable: allow_internal_unstable.clone(),
..SyntaxExtension::default(
SyntaxExtensionKind::LegacyBang(Box::new(format::expand_format_args)), edition
)
});
register(sym::format_args_nl, SyntaxExtension {
allow_internal_unstable,
..SyntaxExtension::default(
SyntaxExtensionKind::LegacyBang(Box::new(format::expand_format_args_nl)), edition
)
});
for (name, ext) in user_exts {
register(name, ext);
+4 -12
View File
@@ -347,18 +347,10 @@ fn mk_decls(
custom_macros: &[ProcMacroDef],
) -> P<ast::Item> {
let mark = Mark::fresh(Mark::root());
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
format: MacroAttribute(sym::proc_macro),
allow_internal_unstable: Some(vec![
sym::rustc_attrs,
Symbol::intern("proc_macro_internals"),
].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: cx.parse_sess.edition,
});
mark.set_expn_info(ExpnInfo::with_unstable(
MacroAttribute(sym::proc_macro), DUMMY_SP, cx.parse_sess.edition,
&[sym::rustc_attrs, Symbol::intern("proc_macro_internals")],
));
let span = DUMMY_SP.apply_mark(mark);
let hidden = cx.meta_list_item_word(span, sym::hidden);
+5 -10
View File
@@ -8,7 +8,7 @@
use syntax::ast;
use syntax::print::pprust;
use syntax::symbol::{Symbol, sym};
use syntax_pos::{DUMMY_SP, Span};
use syntax_pos::Span;
use syntax::source_map::{ExpnInfo, MacroAttribute};
use std::iter;
@@ -62,15 +62,10 @@ pub fn expand_test_or_bench(
let (sp, attr_sp) = {
let mark = Mark::fresh(Mark::root());
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
format: MacroAttribute(sym::test),
allow_internal_unstable: Some(vec![sym::rustc_attrs, sym::test].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: cx.parse_sess.edition,
});
mark.set_expn_info(ExpnInfo::with_unstable(
MacroAttribute(sym::test), attr_sp, cx.parse_sess.edition,
&[sym::rustc_attrs, sym::test],
));
(item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)),
attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)))
};
+5 -10
View File
@@ -15,7 +15,7 @@
use syntax::ast;
use syntax::source_map::respan;
use syntax::symbol::sym;
use syntax_pos::{DUMMY_SP, Span};
use syntax_pos::Span;
use syntax::source_map::{ExpnInfo, MacroAttribute};
use syntax::feature_gate;
@@ -37,15 +37,10 @@ pub fn expand(
let sp = {
let mark = Mark::fresh(Mark::root());
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
def_site: None,
format: MacroAttribute(sym::test_case),
allow_internal_unstable: Some(vec![sym::test, sym::rustc_attrs].into()),
allow_internal_unsafe: false,
local_inner_macros: false,
edition: ecx.parse_sess.edition,
});
mark.set_expn_info(ExpnInfo::with_unstable(
MacroAttribute(sym::test_case), attr_sp, ecx.parse_sess.edition,
&[sym::test, sym::rustc_attrs],
));
attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
};
+44 -29
View File
@@ -59,13 +59,12 @@ struct SyntaxContextData {
#[derive(Clone, Debug)]
struct MarkData {
parent: Mark,
default_transparency: Transparency,
expn_info: Option<ExpnInfo>,
}
/// A property of a macro expansion that determines how identifiers
/// produced by that expansion are resolved.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum Transparency {
/// Identifier produced by a transparent expansion is always resolved at call-site.
/// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
@@ -85,12 +84,7 @@ pub enum Transparency {
impl Mark {
pub fn fresh(parent: Mark) -> Self {
HygieneData::with(|data| {
data.marks.push(MarkData {
parent,
// By default expansions behave like `macro_rules`.
default_transparency: Transparency::SemiTransparent,
expn_info: None,
});
data.marks.push(MarkData { parent, expn_info: None });
Mark(data.marks.len() as u32 - 1)
})
}
@@ -118,7 +112,7 @@ pub fn parent(self) -> Mark {
#[inline]
pub fn expn_info(self) -> Option<ExpnInfo> {
HygieneData::with(|data| data.expn_info(self))
HygieneData::with(|data| data.expn_info(self).cloned())
}
#[inline]
@@ -126,12 +120,6 @@ pub fn set_expn_info(self, info: ExpnInfo) {
HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info))
}
#[inline]
pub fn set_default_transparency(self, transparency: Transparency) {
assert_ne!(self, Mark::root());
HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency)
}
pub fn is_descendant_of(self, ancestor: Mark) -> bool {
HygieneData::with(|data| data.is_descendant_of(self, ancestor))
}
@@ -172,9 +160,8 @@ pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark {
#[inline]
pub fn looks_like_proc_macro_derive(self) -> bool {
HygieneData::with(|data| {
let mark_data = &data.marks[self.0 as usize];
if mark_data.default_transparency == Transparency::Opaque {
if let Some(expn_info) = &mark_data.expn_info {
if data.default_transparency(self) == Transparency::Opaque {
if let Some(expn_info) = &data.marks[self.0 as usize].expn_info {
if let ExpnFormat::MacroAttribute(name) = expn_info.format {
if name.as_str().starts_with("derive(") {
return true;
@@ -199,9 +186,6 @@ impl HygieneData {
HygieneData {
marks: vec![MarkData {
parent: Mark::root(),
// If the root is opaque, then loops searching for an opaque mark
// will automatically stop after reaching it.
default_transparency: Transparency::Opaque,
expn_info: None,
}],
syntax_contexts: vec![SyntaxContextData {
@@ -220,8 +204,8 @@ fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut()))
}
fn expn_info(&self, mark: Mark) -> Option<ExpnInfo> {
self.marks[mark.0 as usize].expn_info.clone()
fn expn_info(&self, mark: Mark) -> Option<&ExpnInfo> {
self.marks[mark.0 as usize].expn_info.as_ref()
}
fn is_descendant_of(&self, mut mark: Mark, ancestor: Mark) -> bool {
@@ -235,7 +219,9 @@ fn is_descendant_of(&self, mut mark: Mark, ancestor: Mark) -> bool {
}
fn default_transparency(&self, mark: Mark) -> Transparency {
self.marks[mark.0 as usize].default_transparency
self.marks[mark.0 as usize].expn_info.as_ref().map_or(
Transparency::SemiTransparent, |einfo| einfo.default_transparency
)
}
fn modern(&self, ctxt: SyntaxContext) -> SyntaxContext {
@@ -427,7 +413,6 @@ pub fn allocate_directly(expansion_info: ExpnInfo) -> Self {
HygieneData::with(|data| {
data.marks.push(MarkData {
parent: Mark::root(),
default_transparency: Transparency::SemiTransparent,
expn_info: Some(expansion_info),
});
@@ -613,7 +598,7 @@ pub fn outer(self) -> Mark {
/// `ctxt.outer().expn_info()`.
#[inline]
pub fn outer_expn_info(self) -> Option<ExpnInfo> {
HygieneData::with(|data| data.expn_info(data.outer(self)))
HygieneData::with(|data| data.expn_info(data.outer(self)).cloned())
}
/// `ctxt.outer_and_expn_info()` is equivalent to but faster than
@@ -622,7 +607,7 @@ pub fn outer_expn_info(self) -> Option<ExpnInfo> {
pub fn outer_and_expn_info(self) -> (Mark, Option<ExpnInfo>) {
HygieneData::with(|data| {
let outer = data.outer(self);
(outer, data.expn_info(outer))
(outer, data.expn_info(outer).cloned())
})
}
@@ -651,6 +636,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// Extra information for tracking spans of macro and syntax sugar expansion
#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct ExpnInfo {
// --- The part unique to each expansion.
/// The location of the actual macro invocation or syntax sugar , e.g.
/// `let x = foo!();` or `if let Some(y) = x {}`
///
@@ -661,13 +647,18 @@ pub struct ExpnInfo {
/// call_site span would have its own ExpnInfo, with the call_site
/// pointing to the `foo!` invocation.
pub call_site: Span,
/// The format with which the macro was invoked.
pub format: ExpnFormat,
// --- The part specific to the macro/desugaring definition.
// --- FIXME: Share it between expansions with the same definition.
/// The span of the macro definition itself. The macro may not
/// have a sensible definition span (e.g., something defined
/// completely inside libsyntax) in which case this is None.
/// This span serves only informational purpose and is not used for resolution.
pub def_site: Option<Span>,
/// The format with which the macro was invoked.
pub format: ExpnFormat,
/// Transparency used by `apply_mark` for mark with this expansion info by default.
pub default_transparency: Transparency,
/// List of #[unstable]/feature-gated features that the macro is allowed to use
/// internally without forcing the whole crate to opt-in
/// to them.
@@ -682,6 +673,30 @@ pub struct ExpnInfo {
pub edition: Edition,
}
impl ExpnInfo {
/// Constructs an expansion info with default properties.
pub fn default(format: ExpnFormat, call_site: Span, edition: Edition) -> ExpnInfo {
ExpnInfo {
call_site,
format,
def_site: None,
default_transparency: Transparency::SemiTransparent,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
edition,
}
}
pub fn with_unstable(format: ExpnFormat, call_site: Span, edition: Edition,
allow_internal_unstable: &[Symbol]) -> ExpnInfo {
ExpnInfo {
allow_internal_unstable: Some(allow_internal_unstable.into()),
..ExpnInfo::default(format, call_site, edition)
}
}
}
/// The source of expansion.
#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum ExpnFormat {
@@ -11,8 +11,8 @@
use std::borrow::ToOwned;
use syntax::ast;
use syntax::ext::build::AstBuilder;
use syntax::ext::base::{SyntaxExtension, TTMacroExpander, ExtCtxt, MacResult, MacEager};
use syntax::ext::hygiene::Transparency;
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager};
use syntax::print::pprust;
use syntax::symbol::Symbol;
use syntax_pos::Span;
@@ -38,15 +38,7 @@ fn expand<'cx>(&self,
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
let args = reg.args().to_owned();
reg.register_syntax_extension(Symbol::intern("plugin_args"),
SyntaxExtension::LegacyBang {
expander: Box::new(Expander { args: args, }),
def_info: None,
transparency: Transparency::SemiTransparent,
allow_internal_unstable: None,
allow_internal_unsafe: false,
local_inner_macros: false,
unstable_feature: None,
edition: reg.sess.edition(),
});
reg.register_syntax_extension(Symbol::intern("plugin_args"), SyntaxExtension::default(
SyntaxExtensionKind::LegacyBang(Box::new(Expander { args })), reg.sess.edition()
));
}