Auto merge of #40220 - jseyfried:ast_macro_def, r=nrc
syntax: add `ast::ItemKind::MacroDef`, simplify hygiene info This PR - adds a new variant `MacroDef` to `ast::ItemKind` for `macro_rules!` and eventually `macro` items, - [breaking-change] forbids macro defs without a name (`macro_rules! { () => {} }` compiles today), - removes `ast::MacroDef`, and - no longer uses `Mark` and `Invocation` to identify and characterize macro definitions. - We used to apply (at least) two `Mark`s to an expanded identifier's `SyntaxContext` -- the definition mark(s) and the expansion mark(s). We now only apply the latter. r? @nrc
This commit is contained in:
commit
1b19284ad9
@ -79,6 +79,7 @@ pub struct LoweringContext<'a> {
|
||||
trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
|
||||
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
|
||||
bodies: BTreeMap<hir::BodyId, hir::Body>,
|
||||
exported_macros: Vec<hir::MacroDef>,
|
||||
|
||||
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
||||
trait_default_impl: BTreeMap<DefId, NodeId>,
|
||||
@ -121,6 +122,7 @@ pub fn lower_crate(sess: &Session,
|
||||
bodies: BTreeMap::new(),
|
||||
trait_impls: BTreeMap::new(),
|
||||
trait_default_impl: BTreeMap::new(),
|
||||
exported_macros: Vec::new(),
|
||||
loop_scopes: Vec::new(),
|
||||
is_in_loop_condition: false,
|
||||
type_def_lifetime_params: DefIdMap(),
|
||||
@ -170,9 +172,10 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> {
|
||||
fn visit_item(&mut self, item: &'lcx Item) {
|
||||
let hir_item = self.lctx.lower_item(item);
|
||||
self.lctx.items.insert(item.id, hir_item);
|
||||
visit::walk_item(self, item);
|
||||
if let Some(hir_item) = self.lctx.lower_item(item) {
|
||||
self.lctx.items.insert(item.id, hir_item);
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
|
||||
@ -195,14 +198,13 @@ impl<'a> LoweringContext<'a> {
|
||||
|
||||
let module = self.lower_mod(&c.module);
|
||||
let attrs = self.lower_attrs(&c.attrs);
|
||||
let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
|
||||
let body_ids = body_ids(&self.bodies);
|
||||
|
||||
hir::Crate {
|
||||
module: module,
|
||||
attrs: attrs,
|
||||
span: c.span,
|
||||
exported_macros: exported_macros,
|
||||
exported_macros: hir::HirVec::from(self.exported_macros),
|
||||
items: self.items,
|
||||
trait_items: self.trait_items,
|
||||
impl_items: self.impl_items,
|
||||
@ -1134,7 +1136,7 @@ impl<'a> LoweringContext<'a> {
|
||||
bounds,
|
||||
items)
|
||||
}
|
||||
ItemKind::Mac(_) => panic!("Shouldn't still be around"),
|
||||
ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1256,42 +1258,45 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_macro_def(&mut self, m: &MacroDef) -> hir::MacroDef {
|
||||
hir::MacroDef {
|
||||
name: m.ident.name,
|
||||
attrs: self.lower_attrs(&m.attrs),
|
||||
id: m.id,
|
||||
span: m.span,
|
||||
body: m.body.clone().into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_item_id(&mut self, i: &Item) -> SmallVector<hir::ItemId> {
|
||||
if let ItemKind::Use(ref view_path) = i.node {
|
||||
if let ViewPathList(_, ref imports) = view_path.node {
|
||||
return iter::once(i.id).chain(imports.iter().map(|import| import.node.id))
|
||||
.map(|id| hir::ItemId { id: id }).collect();
|
||||
match i.node {
|
||||
ItemKind::Use(ref view_path) => {
|
||||
if let ViewPathList(_, ref imports) = view_path.node {
|
||||
return iter::once(i.id).chain(imports.iter().map(|import| import.node.id))
|
||||
.map(|id| hir::ItemId { id: id }).collect();
|
||||
}
|
||||
}
|
||||
ItemKind::MacroDef(..) => return SmallVector::new(),
|
||||
_ => {}
|
||||
}
|
||||
SmallVector::one(hir::ItemId { id: i.id })
|
||||
}
|
||||
|
||||
pub fn lower_item(&mut self, i: &Item) -> hir::Item {
|
||||
pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item> {
|
||||
let mut name = i.ident.name;
|
||||
let attrs = self.lower_attrs(&i.attrs);
|
||||
let mut vis = self.lower_visibility(&i.vis);
|
||||
if let ItemKind::MacroDef(ref tts) = i.node {
|
||||
if i.attrs.iter().any(|attr| attr.name() == "macro_export") {
|
||||
self.exported_macros.push(hir::MacroDef {
|
||||
name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(),
|
||||
});
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
let node = self.with_parent_def(i.id, |this| {
|
||||
this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node)
|
||||
});
|
||||
|
||||
hir::Item {
|
||||
Some(hir::Item {
|
||||
id: i.id,
|
||||
name: name,
|
||||
attrs: attrs,
|
||||
node: node,
|
||||
vis: vis,
|
||||
span: i.span,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem {
|
||||
|
@ -108,7 +108,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
||||
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
|
||||
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
|
||||
DefPathData::ValueNs(i.ident.name.as_str()),
|
||||
ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder
|
||||
ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()),
|
||||
ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
|
||||
ItemKind::Use(ref view_path) => {
|
||||
match view_path.node {
|
||||
@ -269,10 +269,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
|
||||
self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str()));
|
||||
}
|
||||
|
||||
fn visit_macro_def(&mut self, macro_def: &'a MacroDef) {
|
||||
self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str()));
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &'a Stmt) {
|
||||
match stmt.node {
|
||||
StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false),
|
||||
|
@ -136,7 +136,7 @@ pub struct NativeLibrary {
|
||||
}
|
||||
|
||||
pub enum LoadedMacro {
|
||||
MacroRules(ast::MacroDef),
|
||||
MacroDef(ast::Item),
|
||||
ProcMacro(Rc<SyntaxExtension>),
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@ use super::Compilation;
|
||||
use serialize::json;
|
||||
|
||||
use std::env;
|
||||
use std::mem;
|
||||
use std::ffi::{OsString, OsStr};
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
@ -708,8 +707,6 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
|
||||
krate
|
||||
});
|
||||
|
||||
krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new());
|
||||
|
||||
krate = time(time_passes, "maybe building test harness", || {
|
||||
syntax::test::modify_for_testing(&sess.parse_sess,
|
||||
&mut resolver,
|
||||
|
@ -414,12 +414,13 @@ impl CrateStore for cstore::CStore {
|
||||
sess.imported_macro_spans.borrow_mut()
|
||||
.insert(local_span, (name.to_string(), data.get_span(id.index, sess)));
|
||||
|
||||
LoadedMacro::MacroRules(ast::MacroDef {
|
||||
LoadedMacro::MacroDef(ast::Item {
|
||||
ident: ast::Ident::with_empty_ctxt(name),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: local_span,
|
||||
attrs: attrs,
|
||||
body: body.into(),
|
||||
node: ast::ItemKind::MacroDef(body.into()),
|
||||
vis: ast::Visibility::Inherited,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -375,9 +375,4 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
|
||||
self.record("Attribute", Id::None, attr);
|
||||
}
|
||||
|
||||
fn visit_macro_def(&mut self, macro_def: &'v ast::MacroDef) {
|
||||
self.record("MacroDef", Id::None, macro_def);
|
||||
ast_visit::walk_macro_def(self, macro_def)
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
|
||||
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax::ext::base::Determinacy::Undetermined;
|
||||
use syntax::ext::expand::mark_tts;
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::parse::token;
|
||||
@ -373,7 +372,7 @@ impl<'a> Resolver<'a> {
|
||||
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
|
||||
self.current_module = module;
|
||||
}
|
||||
ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"),
|
||||
ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,6 +492,16 @@ impl<'a> Resolver<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
|
||||
let def_id = self.macro_defs[&expansion];
|
||||
if let Some(id) = self.definitions.as_local_node_id(def_id) {
|
||||
self.local_macro_def_scopes[&id]
|
||||
} else {
|
||||
let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
|
||||
self.get_extern_crate_root(module_def_id.krate)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_macro(&mut self, def: Def) -> Rc<SyntaxExtension> {
|
||||
let def_id = match def {
|
||||
Def::Macro(def_id, ..) => def_id,
|
||||
@ -502,22 +511,12 @@ impl<'a> Resolver<'a> {
|
||||
return ext.clone();
|
||||
}
|
||||
|
||||
let mut macro_rules = match self.session.cstore.load_macro(def_id, &self.session) {
|
||||
LoadedMacro::MacroRules(macro_rules) => macro_rules,
|
||||
let macro_def = match self.session.cstore.load_macro(def_id, &self.session) {
|
||||
LoadedMacro::MacroDef(macro_def) => macro_def,
|
||||
LoadedMacro::ProcMacro(ext) => return ext,
|
||||
};
|
||||
|
||||
let mark = Mark::fresh();
|
||||
let invocation = self.arenas.alloc_invocation_data(InvocationData {
|
||||
module: Cell::new(self.get_extern_crate_root(def_id.krate)),
|
||||
def_index: CRATE_DEF_INDEX,
|
||||
const_expr: false,
|
||||
legacy_scope: Cell::new(LegacyScope::Empty),
|
||||
expansion: Cell::new(LegacyScope::Empty),
|
||||
});
|
||||
self.invocations.insert(mark, invocation);
|
||||
macro_rules.body = mark_tts(macro_rules.stream(), mark).into();
|
||||
let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_rules));
|
||||
let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_def));
|
||||
self.macro_map.insert(def_id, ext.clone());
|
||||
ext
|
||||
}
|
||||
@ -707,12 +706,12 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
|
||||
|
||||
fn visit_item(&mut self, item: &'a Item) {
|
||||
let macro_use = match item.node {
|
||||
ItemKind::Mac(ref mac) => {
|
||||
if mac.node.path.segments.is_empty() {
|
||||
self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
|
||||
} else {
|
||||
self.resolver.define_macro(item, &mut self.legacy_scope);
|
||||
}
|
||||
ItemKind::MacroDef(..) => {
|
||||
self.resolver.define_macro(item, &mut self.legacy_scope);
|
||||
return
|
||||
}
|
||||
ItemKind::Mac(..) => {
|
||||
self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
|
||||
return
|
||||
}
|
||||
ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
|
||||
|
@ -779,8 +779,8 @@ enum RibKind<'a> {
|
||||
// We passed through a module.
|
||||
ModuleRibKind(Module<'a>),
|
||||
|
||||
// We passed through a `macro_rules!` statement with the given expansion
|
||||
MacroDefinition(Mark),
|
||||
// We passed through a `macro_rules!` statement
|
||||
MacroDefinition(DefId),
|
||||
|
||||
// All bindings in this rib are type parameters that can't be used
|
||||
// from the default of a type parameter because they're not declared
|
||||
@ -997,14 +997,18 @@ impl<'a> NameBinding<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc<SyntaxExtension> {
|
||||
fn def_ignoring_ambiguity(&self) -> Def {
|
||||
match self.kind {
|
||||
NameBindingKind::Import { binding, .. } => binding.get_macro(resolver),
|
||||
NameBindingKind::Ambiguity { b1, .. } => b1.get_macro(resolver),
|
||||
_ => resolver.get_macro(self.def()),
|
||||
NameBindingKind::Import { binding, .. } => binding.def_ignoring_ambiguity(),
|
||||
NameBindingKind::Ambiguity { b1, .. } => b1.def_ignoring_ambiguity(),
|
||||
_ => self.def(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc<SyntaxExtension> {
|
||||
resolver.get_macro(self.def_ignoring_ambiguity())
|
||||
}
|
||||
|
||||
// We sometimes need to treat variants as `pub` for backwards compatibility
|
||||
fn pseudo_vis(&self) -> ty::Visibility {
|
||||
if self.is_variant() { ty::Visibility::Public } else { self.vis }
|
||||
@ -1092,10 +1096,6 @@ pub struct Resolver<'a> {
|
||||
|
||||
pub definitions: Definitions,
|
||||
|
||||
// Maps the node id of a statement to the expansions of the `macro_rules!`s
|
||||
// immediately above the statement (if appropriate).
|
||||
macros_at_scope: FxHashMap<NodeId, Vec<Mark>>,
|
||||
|
||||
graph_root: Module<'a>,
|
||||
|
||||
prelude: Option<Module<'a>>,
|
||||
@ -1171,12 +1171,13 @@ pub struct Resolver<'a> {
|
||||
dummy_binding: &'a NameBinding<'a>,
|
||||
use_extern_macros: bool, // true if `#![feature(use_extern_macros)]`
|
||||
|
||||
pub exported_macros: Vec<ast::MacroDef>,
|
||||
crate_loader: &'a mut CrateLoader,
|
||||
macro_names: FxHashSet<Name>,
|
||||
builtin_macros: FxHashMap<Name, &'a NameBinding<'a>>,
|
||||
lexical_macro_resolutions: Vec<(Name, &'a Cell<LegacyScope<'a>>)>,
|
||||
macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
|
||||
macro_defs: FxHashMap<Mark, DefId>,
|
||||
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
|
||||
macro_exports: Vec<Export>,
|
||||
pub whitelisted_legacy_custom_derives: Vec<Name>,
|
||||
pub found_unresolved_macro: bool,
|
||||
@ -1305,11 +1306,13 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
let features = session.features.borrow();
|
||||
|
||||
let mut macro_defs = FxHashMap();
|
||||
macro_defs.insert(Mark::root(), root_def_id);
|
||||
|
||||
Resolver {
|
||||
session: session,
|
||||
|
||||
definitions: definitions,
|
||||
macros_at_scope: FxHashMap(),
|
||||
|
||||
// The outermost module has def ID 0; this is not reflected in the
|
||||
// AST.
|
||||
@ -1365,7 +1368,6 @@ impl<'a> Resolver<'a> {
|
||||
// `#![feature(proc_macro)]` implies `#[feature(extern_macros)]`
|
||||
use_extern_macros: features.use_extern_macros || features.proc_macro,
|
||||
|
||||
exported_macros: Vec::new(),
|
||||
crate_loader: crate_loader,
|
||||
macro_names: FxHashSet(),
|
||||
builtin_macros: FxHashMap(),
|
||||
@ -1373,6 +1375,8 @@ impl<'a> Resolver<'a> {
|
||||
macro_map: FxHashMap(),
|
||||
macro_exports: Vec::new(),
|
||||
invocations: invocations,
|
||||
macro_defs: macro_defs,
|
||||
local_macro_def_scopes: FxHashMap(),
|
||||
name_already_seen: FxHashMap(),
|
||||
whitelisted_legacy_custom_derives: Vec::new(),
|
||||
proc_macro_enabled: features.proc_macro,
|
||||
@ -1510,12 +1514,12 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if let MacroDefinition(mac) = self.ribs[ns][i].kind {
|
||||
if let MacroDefinition(def) = self.ribs[ns][i].kind {
|
||||
// If an invocation of this macro created `ident`, give up on `ident`
|
||||
// and switch to `ident`'s source from the macro definition.
|
||||
let (source_ctxt, source_macro) = ident.ctxt.source();
|
||||
if source_macro == mac {
|
||||
ident.ctxt = source_ctxt;
|
||||
let ctxt_data = ident.ctxt.data();
|
||||
if def == self.macro_defs[&ctxt_data.outer_mark] {
|
||||
ident.ctxt = ctxt_data.prev_ctxt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1523,11 +1527,12 @@ impl<'a> Resolver<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_crate_var(&mut self, mut crate_var_ctxt: SyntaxContext) -> Module<'a> {
|
||||
while crate_var_ctxt.source().0 != SyntaxContext::empty() {
|
||||
crate_var_ctxt = crate_var_ctxt.source().0;
|
||||
fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext) -> Module<'a> {
|
||||
let mut ctxt_data = crate_var_ctxt.data();
|
||||
while ctxt_data.prev_ctxt != SyntaxContext::empty() {
|
||||
ctxt_data = ctxt_data.prev_ctxt.data();
|
||||
}
|
||||
let module = self.invocations[&crate_var_ctxt.source().1].module.get();
|
||||
let module = self.macro_def_scope(ctxt_data.outer_mark);
|
||||
if module.is_local() { self.graph_root } else { module }
|
||||
}
|
||||
|
||||
@ -1579,12 +1584,12 @@ impl<'a> Resolver<'a> {
|
||||
NormalRibKind => {
|
||||
// Continue
|
||||
}
|
||||
MacroDefinition(mac) => {
|
||||
MacroDefinition(def) => {
|
||||
// If an invocation of this macro created `ident`, give up on `ident`
|
||||
// and switch to `ident`'s source from the macro definition.
|
||||
let (source_ctxt, source_macro) = ident.ctxt.source();
|
||||
if source_macro == mac {
|
||||
ident.ctxt = source_ctxt;
|
||||
let ctxt_data = ident.ctxt.data();
|
||||
if def == self.macro_defs[&ctxt_data.outer_mark] {
|
||||
ident.ctxt = ctxt_data.prev_ctxt;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -1696,7 +1701,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
ItemKind::ExternCrate(_) => {
|
||||
ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => {
|
||||
// do nothing, these are just around to be encoded
|
||||
}
|
||||
|
||||
@ -2031,11 +2036,12 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
// Descend into the block.
|
||||
for stmt in &block.stmts {
|
||||
if let Some(marks) = self.macros_at_scope.remove(&stmt.id) {
|
||||
num_macro_definition_ribs += marks.len() as u32;
|
||||
for mark in marks {
|
||||
self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark)));
|
||||
self.label_ribs.push(Rib::new(MacroDefinition(mark)));
|
||||
if let ast::StmtKind::Item(ref item) = stmt.node {
|
||||
if let ast::ItemKind::MacroDef(..) = item.node {
|
||||
num_macro_definition_ribs += 1;
|
||||
let def = self.definitions.local_def_id(item.id);
|
||||
self.ribs[ValueNS].push(Rib::new(MacroDefinition(def)));
|
||||
self.label_ribs.push(Rib::new(MacroDefinition(def)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,25 +17,26 @@ use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}
|
||||
use rustc::hir::def::{Def, Export};
|
||||
use rustc::hir::map::{self, DefCollector};
|
||||
use rustc::ty;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::{self, Name, Ident};
|
||||
use syntax::attr;
|
||||
use syntax::attr::{self, HasAttrs};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
|
||||
use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension};
|
||||
use syntax::ext::base::MacroKind;
|
||||
use syntax::ext::expand::{Expansion, mark_tts};
|
||||
use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator};
|
||||
use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
|
||||
use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::ext::placeholders::placeholder;
|
||||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
|
||||
use syntax::fold::{self, Folder};
|
||||
use syntax::ptr::P;
|
||||
use syntax::symbol::{Symbol, keywords};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InvocationData<'a> {
|
||||
pub module: Cell<Module<'a>>,
|
||||
@ -73,7 +74,7 @@ pub enum LegacyScope<'a> {
|
||||
pub struct LegacyBinding<'a> {
|
||||
pub parent: Cell<LegacyScope<'a>>,
|
||||
pub name: ast::Name,
|
||||
ext: Rc<SyntaxExtension>,
|
||||
def_id: DefId,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
@ -151,7 +152,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
invocation.expansion.set(visitor.legacy_scope);
|
||||
}
|
||||
|
||||
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
|
||||
fn add_builtin(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
|
||||
let def_id = DefId {
|
||||
krate: BUILTIN_MACROS_CRATE,
|
||||
index: DefIndex::new(self.macro_map.len()),
|
||||
@ -167,10 +168,6 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
self.builtin_macros.insert(ident.name, binding);
|
||||
}
|
||||
|
||||
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
|
||||
self.macros_at_scope.insert(id, macros);
|
||||
}
|
||||
|
||||
fn resolve_imports(&mut self) {
|
||||
ImportResolver { resolver: self }.resolve_imports()
|
||||
}
|
||||
@ -240,8 +237,83 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind,
|
||||
force: bool) -> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
|
||||
-> Result<Option<Rc<SyntaxExtension>>, Determinacy> {
|
||||
let def = match invoc.kind {
|
||||
InvocationKind::Attr { attr: None, .. } => return Ok(None),
|
||||
_ => match self.resolve_invoc_to_def(invoc, scope, force) {
|
||||
Ok(def) => def,
|
||||
Err(determinacy) => return Err(determinacy),
|
||||
},
|
||||
};
|
||||
self.macro_defs.insert(invoc.expansion_data.mark, def.def_id());
|
||||
Ok(Some(self.get_macro(def)))
|
||||
}
|
||||
|
||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
self.resolve_macro_to_def(scope, path, kind, force).map(|def| self.get_macro(def))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
|
||||
-> Result<Def, Determinacy> {
|
||||
let (attr, traits, item) = match invoc.kind {
|
||||
InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item),
|
||||
InvocationKind::Bang { ref mac, .. } => {
|
||||
return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force);
|
||||
}
|
||||
InvocationKind::Derive { name, span, .. } => {
|
||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
||||
return self.resolve_macro_to_def(scope, &path, MacroKind::Derive, force);
|
||||
}
|
||||
};
|
||||
|
||||
let (attr_name, path) = {
|
||||
let attr = attr.as_ref().unwrap();
|
||||
(attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name())))
|
||||
};
|
||||
|
||||
let mut determined = true;
|
||||
match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) {
|
||||
Ok(def) => return Ok(def),
|
||||
Err(Determinacy::Undetermined) => determined = false,
|
||||
Err(Determinacy::Determined) if force => return Err(Determinacy::Determined),
|
||||
Err(Determinacy::Determined) => {}
|
||||
}
|
||||
|
||||
for &(name, span) in traits {
|
||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
||||
match self.resolve_macro(scope, &path, MacroKind::Derive, force) {
|
||||
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
|
||||
if inert_attrs.contains(&attr_name) {
|
||||
// FIXME(jseyfried) Avoid `mem::replace` here.
|
||||
let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
|
||||
.make_items().pop().unwrap();
|
||||
let dummy_item = Annotatable::Item(dummy_item);
|
||||
*item = mem::replace(item, dummy_item).map_attrs(|mut attrs| {
|
||||
let inert_attr = attr.take().unwrap();
|
||||
attr::mark_known(&inert_attr);
|
||||
if self.proc_macro_enabled {
|
||||
*attr = find_attr_invoc(&mut attrs);
|
||||
}
|
||||
attrs.push(inert_attr);
|
||||
attrs
|
||||
});
|
||||
}
|
||||
return Err(Determinacy::Undetermined);
|
||||
},
|
||||
Err(Determinacy::Undetermined) => determined = false,
|
||||
Err(Determinacy::Determined) => {}
|
||||
}
|
||||
}
|
||||
|
||||
Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined })
|
||||
}
|
||||
|
||||
fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
|
||||
-> Result<Def, Determinacy> {
|
||||
let ast::Path { ref segments, span } = *path;
|
||||
if segments.iter().any(|segment| segment.parameters.is_some()) {
|
||||
let kind =
|
||||
@ -264,10 +336,10 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
return Err(Determinacy::Determined);
|
||||
}
|
||||
|
||||
let ext = match self.resolve_path(&path, Some(MacroNS), None) {
|
||||
let def = match self.resolve_path(&path, Some(MacroNS), None) {
|
||||
PathResult::NonModule(path_res) => match path_res.base_def() {
|
||||
Def::Err => Err(Determinacy::Determined),
|
||||
def @ _ => Ok(self.get_macro(def)),
|
||||
def @ _ => Ok(def),
|
||||
},
|
||||
PathResult::Module(..) => unreachable!(),
|
||||
PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined),
|
||||
@ -278,15 +350,15 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
};
|
||||
self.current_module.macro_resolutions.borrow_mut()
|
||||
.push((path.into_boxed_slice(), span));
|
||||
return ext;
|
||||
return def;
|
||||
}
|
||||
|
||||
let name = path[0].name;
|
||||
let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) {
|
||||
Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()),
|
||||
Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)),
|
||||
Some(MacroBinding::Legacy(binding)) => Ok(Def::Macro(binding.def_id, MacroKind::Bang)),
|
||||
Some(MacroBinding::Modern(binding)) => Ok(binding.def_ignoring_ambiguity()),
|
||||
None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) {
|
||||
Ok(binding) => Ok(binding.get_macro(self)),
|
||||
Ok(binding) => Ok(binding.def_ignoring_ambiguity()),
|
||||
Err(Determinacy::Undetermined) if !force =>
|
||||
return Err(Determinacy::Undetermined),
|
||||
Err(_) => {
|
||||
@ -301,9 +373,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
// Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`)
|
||||
pub fn resolve_lexical_macro_path_segment(&mut self,
|
||||
ident: Ident,
|
||||
@ -544,45 +614,23 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) {
|
||||
let tts = match item.node {
|
||||
ast::ItemKind::Mac(ref mac) => mac.node.stream(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if item.ident.name == "macro_rules" {
|
||||
self.local_macro_def_scopes.insert(item.id, self.current_module);
|
||||
let ident = item.ident;
|
||||
if ident.name == "macro_rules" {
|
||||
self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`");
|
||||
}
|
||||
|
||||
let mark = Mark::from_placeholder_id(item.id);
|
||||
let invocation = self.invocations[&mark];
|
||||
invocation.module.set(self.current_module);
|
||||
|
||||
let mut def = ast::MacroDef {
|
||||
ident: item.ident,
|
||||
attrs: item.attrs.clone(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span: item.span,
|
||||
body: mark_tts(tts, mark).into(),
|
||||
};
|
||||
|
||||
let def_id = self.definitions.local_def_id(item.id);
|
||||
let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, item));
|
||||
self.macro_map.insert(def_id, ext);
|
||||
*legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
|
||||
parent: Cell::new(*legacy_scope),
|
||||
name: def.ident.name,
|
||||
ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
|
||||
span: def.span,
|
||||
parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span,
|
||||
}));
|
||||
self.macro_names.insert(def.ident.name);
|
||||
self.macro_names.insert(ident.name);
|
||||
|
||||
if attr::contains_name(&def.attrs, "macro_export") {
|
||||
def.id = self.next_node_id();
|
||||
DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| {
|
||||
collector.visit_macro_def(&def)
|
||||
});
|
||||
self.macro_exports.push(Export {
|
||||
name: def.ident.name,
|
||||
def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang),
|
||||
});
|
||||
self.exported_macros.push(def);
|
||||
if attr::contains_name(&item.attrs, "macro_export") {
|
||||
let def = Def::Macro(def_id, MacroKind::Bang);
|
||||
self.macro_exports.push(Export { name: ident.name, def: def });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ use std::mem;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::tokenstream::TokenStream;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc::hir::map as hir_map;
|
||||
@ -205,14 +206,17 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
}
|
||||
let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate);
|
||||
let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) {
|
||||
LoadedMacro::MacroRules(macro_rules) => macro_rules,
|
||||
LoadedMacro::MacroDef(macro_def) => macro_def,
|
||||
// FIXME(jseyfried): document proc macro reexports
|
||||
LoadedMacro::ProcMacro(..) => continue,
|
||||
};
|
||||
|
||||
// FIXME(jseyfried) merge with `self.visit_macro()`
|
||||
let tts = def.stream().trees().collect::<Vec<_>>();
|
||||
let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect();
|
||||
let matchers = if let ast::ItemKind::MacroDef(ref tokens) = def.node {
|
||||
let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect();
|
||||
tts.chunks(4).map(|arm| arm[0].span()).collect()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
om.macros.push(Macro {
|
||||
def_id: def_id,
|
||||
attrs: def.attrs.clone().into(),
|
||||
|
@ -414,7 +414,6 @@ pub struct Crate {
|
||||
pub module: Mod,
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub span: Span,
|
||||
pub exported_macros: Vec<MacroDef>,
|
||||
}
|
||||
|
||||
/// A spanned compile-time attribute list item.
|
||||
@ -1855,10 +1854,13 @@ pub enum ItemKind {
|
||||
Option<TraitRef>, // (optional) trait this impl implements
|
||||
P<Ty>, // self
|
||||
Vec<ImplItem>),
|
||||
/// A macro invocation (which includes macro definition).
|
||||
/// A macro invocation.
|
||||
///
|
||||
/// E.g. `macro_rules! foo { .. }` or `foo!(..)`
|
||||
Mac(Mac),
|
||||
|
||||
/// A macro definition.
|
||||
MacroDef(ThinTokenStream),
|
||||
}
|
||||
|
||||
impl ItemKind {
|
||||
@ -1877,6 +1879,7 @@ impl ItemKind {
|
||||
ItemKind::Union(..) => "union",
|
||||
ItemKind::Trait(..) => "trait",
|
||||
ItemKind::Mac(..) |
|
||||
ItemKind::MacroDef(..) |
|
||||
ItemKind::Impl(..) |
|
||||
ItemKind::DefaultImpl(..) => "item"
|
||||
}
|
||||
@ -1912,24 +1915,6 @@ impl ForeignItemKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// A macro definition, in this crate or imported from another.
|
||||
///
|
||||
/// Not parsed directly, but created on macro import or `macro_rules!` expansion.
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub struct MacroDef {
|
||||
pub ident: Ident,
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub id: NodeId,
|
||||
pub span: Span,
|
||||
pub body: ThinTokenStream,
|
||||
}
|
||||
|
||||
impl MacroDef {
|
||||
pub fn stream(&self) -> TokenStream {
|
||||
self.body.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serialize;
|
||||
|
@ -15,7 +15,7 @@ use attr::HasAttrs;
|
||||
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
|
||||
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
|
||||
use errors::{DiagnosticBuilder, FatalError};
|
||||
use ext::expand::{self, Expansion};
|
||||
use ext::expand::{self, Expansion, Invocation};
|
||||
use ext::hygiene::Mark;
|
||||
use fold::{self, Folder};
|
||||
use parse::{self, parser, DirectoryOwnership};
|
||||
@ -552,14 +552,15 @@ pub trait Resolver {
|
||||
fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool;
|
||||
|
||||
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]);
|
||||
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
|
||||
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
|
||||
fn add_builtin(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
|
||||
|
||||
fn resolve_imports(&mut self);
|
||||
// Resolves attribute and derive legacy macros from `#![plugin(..)]`.
|
||||
fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
|
||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind,
|
||||
force: bool) -> Result<Rc<SyntaxExtension>, Determinacy>;
|
||||
fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
|
||||
-> Result<Option<Rc<SyntaxExtension>>, Determinacy>;
|
||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
|
||||
-> Result<Rc<SyntaxExtension>, Determinacy>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -577,11 +578,14 @@ impl Resolver for DummyResolver {
|
||||
fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false }
|
||||
|
||||
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {}
|
||||
fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
|
||||
fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
|
||||
fn add_builtin(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
|
||||
|
||||
fn resolve_imports(&mut self) {}
|
||||
fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
|
||||
fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool)
|
||||
-> Result<Option<Rc<SyntaxExtension>>, Determinacy> {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _kind: MacroKind,
|
||||
_force: bool) -> Result<Rc<SyntaxExtension>, Determinacy> {
|
||||
Err(Determinacy::Determined)
|
||||
|
@ -154,7 +154,7 @@ impl ExpansionKind {
|
||||
pub struct Invocation {
|
||||
pub kind: InvocationKind,
|
||||
expansion_kind: ExpansionKind,
|
||||
expansion_data: ExpansionData,
|
||||
pub expansion_data: ExpansionData,
|
||||
}
|
||||
|
||||
pub enum InvocationKind {
|
||||
@ -251,7 +251,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
|
||||
let scope =
|
||||
if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
|
||||
let ext = match self.resolve_invoc(&mut invoc, scope, force) {
|
||||
let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) {
|
||||
Ok(ext) => Some(ext),
|
||||
Err(Determinacy::Determined) => None,
|
||||
Err(Determinacy::Undetermined) => {
|
||||
@ -364,64 +364,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
result
|
||||
}
|
||||
|
||||
fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
|
||||
-> Result<Option<Rc<SyntaxExtension>>, Determinacy> {
|
||||
let (attr, traits, item) = match invoc.kind {
|
||||
InvocationKind::Bang { ref mac, .. } => {
|
||||
return self.cx.resolver.resolve_macro(scope, &mac.node.path,
|
||||
MacroKind::Bang, force).map(Some);
|
||||
}
|
||||
InvocationKind::Attr { attr: None, .. } => return Ok(None),
|
||||
InvocationKind::Derive { name, span, .. } => {
|
||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
||||
return self.cx.resolver.resolve_macro(scope, &path,
|
||||
MacroKind::Derive, force).map(Some)
|
||||
}
|
||||
InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item),
|
||||
};
|
||||
|
||||
let (attr_name, path) = {
|
||||
let attr = attr.as_ref().unwrap();
|
||||
(attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name())))
|
||||
};
|
||||
|
||||
let mut determined = true;
|
||||
match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Attr, force) {
|
||||
Ok(ext) => return Ok(Some(ext)),
|
||||
Err(Determinacy::Undetermined) => determined = false,
|
||||
Err(Determinacy::Determined) if force => return Err(Determinacy::Determined),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
for &(name, span) in traits {
|
||||
let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name));
|
||||
match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Derive, force) {
|
||||
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
|
||||
if inert_attrs.contains(&attr_name) {
|
||||
// FIXME(jseyfried) Avoid `mem::replace` here.
|
||||
let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
|
||||
.make_items().pop().unwrap();
|
||||
*item = mem::replace(item, Annotatable::Item(dummy_item))
|
||||
.map_attrs(|mut attrs| {
|
||||
let inert_attr = attr.take().unwrap();
|
||||
attr::mark_known(&inert_attr);
|
||||
if self.cx.ecfg.proc_macro_enabled() {
|
||||
*attr = find_attr_invoc(&mut attrs);
|
||||
}
|
||||
attrs.push(inert_attr);
|
||||
attrs
|
||||
});
|
||||
}
|
||||
return Err(Determinacy::Undetermined);
|
||||
},
|
||||
Err(Determinacy::Undetermined) => determined = false,
|
||||
Err(Determinacy::Determined) => {}
|
||||
}
|
||||
}
|
||||
|
||||
Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined })
|
||||
}
|
||||
|
||||
fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
|
||||
match invoc.kind {
|
||||
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
|
||||
@ -502,7 +444,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
|
||||
let extname = path.segments.last().unwrap().identifier.name;
|
||||
let ident = ident.unwrap_or(keywords::Invalid.ident());
|
||||
let marked_tts = mark_tts(mac.node.stream(), mark);
|
||||
let marked_tts =
|
||||
noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None });
|
||||
let opt_expanded = match *ext {
|
||||
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
|
||||
if ident.name != keywords::Invalid.name() {
|
||||
@ -814,7 +757,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
|
||||
pub fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
|
||||
for i in 0 .. attrs.len() {
|
||||
if !attr::is_known(&attrs[i]) && !is_builtin_attr(&attrs[i]) {
|
||||
return Some(attrs.remove(i));
|
||||
@ -960,17 +903,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
match item.node {
|
||||
ast::ItemKind::Mac(..) => {
|
||||
self.check_attributes(&item.attrs);
|
||||
let is_macro_def = if let ItemKind::Mac(ref mac) = item.node {
|
||||
mac.node.path.segments[0].identifier.name == "macro_rules"
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
item.and_then(|mut item| match item.node {
|
||||
ItemKind::Mac(_) if is_macro_def => {
|
||||
item.id = Mark::fresh().as_placeholder_id();
|
||||
SmallVector::one(P(item))
|
||||
}
|
||||
item.and_then(|item| match item.node {
|
||||
ItemKind::Mac(mac) => {
|
||||
self.collect(ExpansionKind::Items, InvocationKind::Bang {
|
||||
mac: mac,
|
||||
@ -1090,7 +1023,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
|
||||
}
|
||||
|
||||
fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
|
||||
noop_fold_item_kind(self.cfg.configure_item_kind(item), self)
|
||||
match item {
|
||||
ast::ItemKind::MacroDef(..) => item,
|
||||
_ => noop_fold_item_kind(self.cfg.configure_item_kind(item), self),
|
||||
}
|
||||
}
|
||||
|
||||
fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
|
||||
@ -1171,8 +1107,3 @@ impl Folder for Marker {
|
||||
span
|
||||
}
|
||||
}
|
||||
|
||||
// apply a given mark to the given token trees. Used prior to expansion of a macro.
|
||||
pub fn mark_tts(tts: TokenStream, m: Mark) -> TokenStream {
|
||||
noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None})
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ pub struct SyntaxContextData {
|
||||
}
|
||||
|
||||
/// A mark is a unique id associated with a macro expansion.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)]
|
||||
pub struct Mark(u32);
|
||||
|
||||
impl Mark {
|
||||
@ -118,13 +118,6 @@ impl SyntaxContext {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// If `ident` is macro expanded, return the source ident from the macro definition
|
||||
/// and the mark of the expansion that created the macro definition.
|
||||
pub fn source(self) -> (Self /* source context */, Mark /* source macro */) {
|
||||
let macro_def_ctxt = self.data().prev_ctxt.data();
|
||||
(macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SyntaxContext {
|
||||
|
@ -21,7 +21,6 @@ use util::move_map::MoveMap;
|
||||
use util::small_vector::SmallVector;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
|
||||
pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
|
||||
fn mac_placeholder() -> ast::Mac {
|
||||
@ -174,20 +173,11 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
|
||||
|
||||
fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
|
||||
noop_fold_block(block, self).map(|mut block| {
|
||||
let mut macros = Vec::new();
|
||||
let mut remaining_stmts = block.stmts.len();
|
||||
|
||||
block.stmts = block.stmts.move_flat_map(|mut stmt| {
|
||||
remaining_stmts -= 1;
|
||||
|
||||
// `macro_rules!` macro definition
|
||||
if let ast::StmtKind::Item(ref item) = stmt.node {
|
||||
if let ast::ItemKind::Mac(_) = item.node {
|
||||
macros.push(Mark::from_placeholder_id(item.id));
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
match stmt.node {
|
||||
// Avoid wasting a node id on a trailing expression statement,
|
||||
// which shares a HIR node with the expression itself.
|
||||
@ -201,11 +191,6 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.monotonic && !macros.is_empty() {
|
||||
let macros = mem::replace(&mut macros, Vec::new());
|
||||
self.cx.resolver.add_expansions_at_stmt(stmt.id, macros);
|
||||
}
|
||||
|
||||
Some(stmt)
|
||||
});
|
||||
|
||||
|
@ -153,7 +153,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
||||
// Holy self-referential!
|
||||
|
||||
/// Converts a `macro_rules!` invocation into a syntax extension.
|
||||
pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
|
||||
pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension {
|
||||
let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
|
||||
let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
|
||||
|
||||
@ -183,7 +183,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension {
|
||||
];
|
||||
|
||||
// Parse the macro_rules! invocation
|
||||
let argument_map = match parse(sess, def.body.clone().into(), &argument_gram, None) {
|
||||
let body = match def.node {
|
||||
ast::ItemKind::MacroDef(ref body) => body.clone().into(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let argument_map = match parse(sess, body, &argument_gram, None) {
|
||||
Success(m) => m,
|
||||
Failure(sp, tok) => {
|
||||
let s = parse_failure_msg(tok);
|
||||
|
@ -899,6 +899,7 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
|
||||
items.move_flat_map(|item| folder.fold_trait_item(item)),
|
||||
),
|
||||
ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
|
||||
ItemKind::MacroDef(tts) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -959,7 +960,7 @@ pub fn noop_fold_mod<T: Folder>(Mod {inner, items}: Mod, folder: &mut T) -> Mod
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, mut exported_macros, span}: Crate,
|
||||
pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, span}: Crate,
|
||||
folder: &mut T) -> Crate {
|
||||
let mut items = folder.fold_item(P(ast::Item {
|
||||
ident: keywords::Invalid.ident(),
|
||||
@ -987,14 +988,9 @@ pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, mut exported_macros, spa
|
||||
}, vec![], span)
|
||||
};
|
||||
|
||||
for def in &mut exported_macros {
|
||||
def.id = folder.new_id(def.id);
|
||||
}
|
||||
|
||||
Crate {
|
||||
module: module,
|
||||
attrs: attrs,
|
||||
exported_macros: exported_macros,
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
@ -1387,6 +1383,6 @@ mod tests {
|
||||
matches_codepattern,
|
||||
"matches_codepattern",
|
||||
pprust::to_string(|s| fake_print_crate(s, &folded_crate)),
|
||||
"zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string());
|
||||
"macro_rules! zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string());
|
||||
}
|
||||
}
|
||||
|
@ -1048,7 +1048,7 @@ impl<'a> Parser<'a> {
|
||||
self.expected_tokens.clear();
|
||||
}
|
||||
|
||||
pub fn look_ahead<R, F>(&mut self, dist: usize, f: F) -> R where
|
||||
pub fn look_ahead<R, F>(&self, dist: usize, f: F) -> R where
|
||||
F: FnOnce(&token::Token) -> R,
|
||||
{
|
||||
if dist == 0 {
|
||||
@ -3699,11 +3699,41 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn is_union_item(&mut self) -> bool {
|
||||
fn is_union_item(&self) -> bool {
|
||||
self.token.is_keyword(keywords::Union) &&
|
||||
self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword())
|
||||
}
|
||||
|
||||
fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility)
|
||||
-> PResult<'a, Option<P<Item>>> {
|
||||
let lo = self.span.lo;
|
||||
match self.token {
|
||||
token::Ident(ident) if ident.name == "macro_rules" => {
|
||||
if self.look_ahead(1, |t| *t == token::Not) {
|
||||
let prev_span = self.prev_span;
|
||||
self.complain_if_pub_macro(vis, prev_span);
|
||||
self.bump();
|
||||
self.bump();
|
||||
}
|
||||
}
|
||||
_ => return Ok(None),
|
||||
};
|
||||
|
||||
let id = self.parse_ident()?;
|
||||
let (delim, tts) = self.expect_delimited_token_tree()?;
|
||||
if delim != token::Brace {
|
||||
if !self.eat(&token::Semi) {
|
||||
let msg = "macros that expand to items must either be surrounded with braces \
|
||||
or followed by a semicolon";
|
||||
self.span_err(self.prev_span, msg);
|
||||
}
|
||||
}
|
||||
|
||||
let hi = self.prev_span.hi;
|
||||
let kind = ItemKind::MacroDef(tts);
|
||||
Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned())))
|
||||
}
|
||||
|
||||
fn parse_stmt_without_recovery(&mut self,
|
||||
macro_legacy_warnings: bool)
|
||||
-> PResult<'a, Option<Stmt>> {
|
||||
@ -3718,6 +3748,12 @@ impl<'a> Parser<'a> {
|
||||
node: StmtKind::Local(self.parse_local(attrs.into())?),
|
||||
span: mk_sp(lo, self.prev_span.hi),
|
||||
}
|
||||
} else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? {
|
||||
Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: StmtKind::Item(macro_def),
|
||||
span: mk_sp(lo, self.prev_span.hi),
|
||||
}
|
||||
// Starts like a simple path, but not a union item.
|
||||
} else if self.token.is_path_start() &&
|
||||
!self.token.is_qpath_start() &&
|
||||
@ -5767,6 +5803,10 @@ impl<'a> Parser<'a> {
|
||||
maybe_append(attrs, extra_attrs));
|
||||
return Ok(Some(item));
|
||||
}
|
||||
if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility)? {
|
||||
return Ok(Some(macro_def));
|
||||
}
|
||||
|
||||
self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility)
|
||||
}
|
||||
|
||||
@ -5948,7 +5988,6 @@ impl<'a> Parser<'a> {
|
||||
attrs: self.parse_inner_attributes()?,
|
||||
module: self.parse_mod_items(&token::Eof, lo)?,
|
||||
span: mk_sp(lo, self.span.lo),
|
||||
exported_macros: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1318,7 +1318,6 @@ impl<'a> State<'a> {
|
||||
self.bclose(item.span)?;
|
||||
}
|
||||
ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
|
||||
self.print_visibility(&item.vis)?;
|
||||
self.print_path(&node.path, false, 0, false)?;
|
||||
word(&mut self.s, "! ")?;
|
||||
self.print_ident(item.ident)?;
|
||||
@ -1329,6 +1328,16 @@ impl<'a> State<'a> {
|
||||
word(&mut self.s, ";")?;
|
||||
self.end()?;
|
||||
}
|
||||
ast::ItemKind::MacroDef(ref tts) => {
|
||||
word(&mut self.s, "macro_rules! ")?;
|
||||
self.print_ident(item.ident)?;
|
||||
self.cbox(INDENT_UNIT)?;
|
||||
self.popen()?;
|
||||
self.print_tts(tts.clone().into())?;
|
||||
self.pclose()?;
|
||||
word(&mut self.s, ";")?;
|
||||
self.end()?;
|
||||
}
|
||||
}
|
||||
self.ann.post(self, NodeItem(item))
|
||||
}
|
||||
|
@ -148,9 +148,4 @@ impl<'ast> Visitor<'ast> for NodeCounter {
|
||||
fn visit_attribute(&mut self, _attr: &Attribute) {
|
||||
self.count += 1;
|
||||
}
|
||||
fn visit_macro_def(&mut self, macro_def: &MacroDef) {
|
||||
self.count += 1;
|
||||
walk_macro_def(self, macro_def)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -125,9 +125,6 @@ pub trait Visitor<'ast>: Sized {
|
||||
walk_assoc_type_binding(self, type_binding)
|
||||
}
|
||||
fn visit_attribute(&mut self, _attr: &'ast Attribute) {}
|
||||
fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
|
||||
walk_macro_def(self, macro_def)
|
||||
}
|
||||
fn visit_vis(&mut self, vis: &'ast Visibility) {
|
||||
walk_vis(self, vis)
|
||||
}
|
||||
@ -176,12 +173,6 @@ pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, ident: Ident)
|
||||
pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) {
|
||||
visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
|
||||
walk_list!(visitor, visit_attribute, &krate.attrs);
|
||||
walk_list!(visitor, visit_macro_def, &krate.exported_macros);
|
||||
}
|
||||
|
||||
pub fn walk_macro_def<'a, V: Visitor<'a>>(visitor: &mut V, macro_def: &'a MacroDef) {
|
||||
visitor.visit_ident(macro_def.span, macro_def.ident);
|
||||
walk_list!(visitor, visit_attribute, ¯o_def.attrs);
|
||||
}
|
||||
|
||||
pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) {
|
||||
@ -295,6 +286,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
walk_list!(visitor, visit_trait_item, methods);
|
||||
}
|
||||
ItemKind::Mac(ref mac) => visitor.visit_mac(mac),
|
||||
ItemKind::MacroDef(..) => {},
|
||||
}
|
||||
walk_list!(visitor, visit_attribute, &item.attrs);
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ macro_rules! derive_traits {
|
||||
|
||||
pub fn register_builtin_derives(resolver: &mut Resolver) {
|
||||
$(
|
||||
resolver.add_ext(
|
||||
resolver.add_builtin(
|
||||
ast::Ident::with_empty_ctxt(Symbol::intern($name)),
|
||||
Rc::new(SyntaxExtension::BuiltinDerive($func))
|
||||
);
|
||||
|
@ -59,7 +59,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
|
||||
deriving::register_builtin_derives(resolver);
|
||||
|
||||
let mut register = |name, ext| {
|
||||
resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
|
||||
resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
|
||||
};
|
||||
|
||||
macro_rules! register {
|
||||
|
@ -90,12 +90,7 @@ pub fn modify(sess: &ParseSess,
|
||||
|
||||
krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros));
|
||||
|
||||
if krate.exported_macros.len() > 0 {
|
||||
handler.err("cannot export macro_rules! macros from a `proc-macro` \
|
||||
crate type currently");
|
||||
}
|
||||
|
||||
return krate
|
||||
krate
|
||||
}
|
||||
|
||||
fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
|
||||
@ -251,6 +246,15 @@ impl<'a> CollectProcMacros<'a> {
|
||||
|
||||
impl<'a> Visitor<'a> for CollectProcMacros<'a> {
|
||||
fn visit_item(&mut self, item: &'a ast::Item) {
|
||||
if let ast::ItemKind::MacroDef(..) = item.node {
|
||||
if self.is_proc_macro_crate &&
|
||||
item.attrs.iter().any(|attr| attr.name() == "macro_export") {
|
||||
let msg =
|
||||
"cannot export macro_rules! macros from a `proc-macro` crate type currently";
|
||||
self.handler.span_err(item.span, msg);
|
||||
}
|
||||
}
|
||||
|
||||
// First up, make sure we're checking a bare function. If we're not then
|
||||
// we're just not interested in this item.
|
||||
//
|
||||
|
@ -12,6 +12,7 @@
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
|
||||
macro_rules! foo /* 60#0 */(( $ x : ident ) => { y + $ x });
|
||||
|
||||
fn bar /* 62#0 */() { let x /* 59#2 */ = 1; y /* 61#4 */ + x /* 59#5 */ }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user