diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 257cdb960d529..aa6614b0af4f7 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -79,6 +79,7 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, bodies: BTreeMap, + exported_macros: Vec, trait_impls: BTreeMap>, trait_default_impl: BTreeMap, @@ -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 { - 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 { 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 { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index ccaf663c7ad2a..f15e063e81e33 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -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), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4a7027b8997a5..e9fb4632fa178 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -136,7 +136,7 @@ pub struct NativeLibrary { } pub enum LoadedMacro { - MacroRules(ast::MacroDef), + MacroDef(ast::Item), ProcMacro(Rc), } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..e458d45bbd6e8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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}; @@ -705,8 +704,6 @@ pub fn phase_2_configure_and_expand(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, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cf2219e0e3df5..2a67b79eaa52e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -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, }) } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 65a60732fc807..749146fe49672 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -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) - } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index da08d1b7c78e2..03c61067d64c2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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 { 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), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d51ec268ec217..0958748ed092f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 { + 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 { + 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>, - graph_root: Module<'a>, prelude: Option>, @@ -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, crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, builtin_macros: FxHashMap>, lexical_macro_resolutions: Vec<(Name, &'a Cell>)>, macro_map: FxHashMap>, + macro_defs: FxHashMap, + local_macro_def_scopes: FxHashMap>, macro_exports: Vec, pub whitelisted_legacy_custom_derives: Vec, 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))); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 720d616e007d2..7ad122d1c31d8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -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>, @@ -73,7 +74,7 @@ pub enum LegacyScope<'a> { pub struct LegacyBinding<'a> { pub parent: Cell>, pub name: ast::Name, - ext: Rc, + 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) { + fn add_builtin(&mut self, ident: ast::Ident, ext: Rc) { 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) { - 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, Determinacy> { + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result>, 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, 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 { + 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 { 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 }); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 42928427233d7..b80de3cc50546 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -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::>(); - 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(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9cc754cbf4d19..981667337d59a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -414,7 +414,6 @@ pub struct Crate { pub module: Mod, pub attrs: Vec, pub span: Span, - pub exported_macros: Vec, } /// A spanned compile-time attribute list item. @@ -1855,10 +1854,13 @@ pub enum ItemKind { Option, // (optional) trait this impl implements P, // self Vec), - /// 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, - 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; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e242cf2777fe5..dc7e7673eb03c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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); - fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); + fn add_builtin(&mut self, ident: ast::Ident, ext: Rc); fn resolve_imports(&mut self); // Resolves attribute and derive legacy macros from `#![plugin(..)]`. fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec) -> Option; - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, - force: bool) -> Result, Determinacy>; + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result>, Determinacy>; + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, 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) {} - fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} + fn add_builtin(&mut self, _ident: ast::Ident, _ext: Rc) {} fn resolve_imports(&mut self) {} fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } + fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool) + -> Result>, Determinacy> { + Err(Determinacy::Determined) + } fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _kind: MacroKind, _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f1662284a8820..96fcea7148bfa 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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>, 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) -> Expansion { match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), @@ -490,7 +432,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() { @@ -802,7 +745,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } -fn find_attr_invoc(attrs: &mut Vec) -> Option { +pub fn find_attr_invoc(attrs: &mut Vec) -> Option { for i in 0 .. attrs.len() { if !attr::is_known(&attrs[i]) && !is_builtin_attr(&attrs[i]) { return Some(attrs.remove(i)); @@ -948,17 +891,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, @@ -1078,7 +1011,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 { @@ -1159,8 +1095,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}) -} diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 2af5c2ea9995e..57f5ab73d3706 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -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 { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index e2fb1946e90db..f60b1d17a5e2f 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -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) -> P { 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) }); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 1d386c1a3ac93..7aa1230f9aeea 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -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); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4242b0f8b9803..fb4eb19be2b15 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -899,6 +899,7 @@ pub fn noop_fold_item_kind(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(Mod {inner, items}: Mod, folder: &mut T) -> Mod } } -pub fn noop_fold_crate(Crate {module, attrs, mut exported_macros, span}: Crate, +pub fn noop_fold_crate(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(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()); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..6446d38e5ef70 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1048,7 +1048,7 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } - pub fn look_ahead(&mut self, dist: usize, f: F) -> R where + pub fn look_ahead(&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>> { + 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> { @@ -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(), }) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 53ef8e8dfa49c..3efadbd00d1e0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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)) } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index b90802d1e7eb8..9d9957a0f4534 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -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) - } - } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 013632141dee6..ee7dd18247b21 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -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); } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 3bceb02f3d6c5..b51591bf89d5e 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -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)) ); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index f92cde4019f67..1e9b112b6df56 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -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 { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 9c96ad547e1ae..5adaf470f2374 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -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. // diff --git a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs index 0717af98b30b4..3d2dd380e488e 100644 --- a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs +++ b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs @@ -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 */ }