Skip to content

Commit 53642ee

Browse files
committed
make walk/visit_mac opt-in only
macros can expand into arbitrary items, exprs, etc. This means that using a default walker or folder on an AST before macro expansion is complete will miss things (the things that the macros expand into). As a partial fence against this, this commit moves the default traversal of macros into a separate procedure, and makes the default trait implementation signal an error. This means that Folders and Visitors can traverse macros if they want to, but they need to explicitly add an impl that calls the walk_mac or fold_mac procedure This should prevent problems down the road.
1 parent f1ad425 commit 53642ee

File tree

6 files changed

+71
-14
lines changed

6 files changed

+71
-14
lines changed

src/librustc/front/config.rs

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use syntax::codemap;
1414

1515
use std::gc::{Gc, GC};
1616

17+
/// A folder that strips out items that do not belong in the current
18+
/// configuration.
1719
struct Context<'a> {
1820
in_cfg: |attrs: &[ast::Attribute]|: 'a -> bool,
1921
}
@@ -41,6 +43,9 @@ impl<'a> fold::Folder for Context<'a> {
4143
fn fold_expr(&mut self, expr: Gc<ast::Expr>) -> Gc<ast::Expr> {
4244
fold_expr(self, expr)
4345
}
46+
fn fold_mac(&mut self, mac: &ast::Mac) -> ast::Mac {
47+
fold::fold_mac(mac, self)
48+
}
4449
}
4550

4651
pub fn strip_items(krate: ast::Crate,

src/librustc/plugin/load.rs

+5
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate) -> Plugins {
7272
loader.plugins
7373
}
7474

75+
// note that macros aren't expanded yet, and therefore macros can't add plugins.
7576
impl<'a> Visitor<()> for PluginLoader<'a> {
7677
fn visit_view_item(&mut self, vi: &ast::ViewItem, _: ()) {
7778
match vi.node {
@@ -109,6 +110,10 @@ impl<'a> Visitor<()> for PluginLoader<'a> {
109110
_ => (),
110111
}
111112
}
113+
fn visit_mac(&mut self, _: &ast::Mac, _:()) {
114+
// bummer... can't see plugins inside macros.
115+
// do nothing.
116+
}
112117
}
113118

114119
impl<'a> PluginLoader<'a> {

src/libsyntax/ast_map.rs

+9
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ pub enum Node {
112112
NodeLifetime(Gc<Lifetime>),
113113
}
114114

115+
/// Represents an entry and its parent Node ID
115116
/// The odd layout is to bring down the total size.
116117
#[deriving(Clone)]
117118
enum MapEntry {
@@ -184,6 +185,8 @@ impl MapEntry {
184185
}
185186
}
186187

188+
/// Represents a mapping from Node IDs to AST elements and their parent
189+
/// Node IDs
187190
pub struct Map {
188191
/// NodeIds are sequential integers from 0, so we can be
189192
/// super-compact by storing them in a vector. Not everything with
@@ -430,6 +433,8 @@ pub trait FoldOps {
430433
}
431434
}
432435

436+
/// A Folder that walks over an AST and constructs a Node ID Map. Its
437+
/// fold_ops argument has the opportunity to replace Node IDs and spans.
433438
pub struct Ctx<'a, F> {
434439
map: &'a Map,
435440
/// The node in which we are currently mapping (an item or a method).
@@ -584,6 +589,10 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
584589
self.insert(lifetime.id, EntryLifetime(self.parent, box(GC) lifetime));
585590
lifetime
586591
}
592+
593+
fn fold_mac(&mut self, mac: &Mac) -> Mac {
594+
fold::fold_mac(mac, self)
595+
}
587596
}
588597

589598
pub fn map_crate<F: FoldOps>(krate: Crate, fold_ops: F) -> (Crate, Map) {

src/libsyntax/ext/expand.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,6 @@ impl Visitor<()> for PatIdentFinder {
753753
_ => visit::walk_pat(self, pattern, ())
754754
}
755755
}
756-
757756
}
758757

759758
/// find the PatIdent paths in a pattern
@@ -902,6 +901,9 @@ impl<'a> Folder for IdentRenamer<'a> {
902901
ctxt: mtwt::apply_renames(self.renames, id.ctxt),
903902
}
904903
}
904+
fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
905+
fold::fold_mac(macro, self)
906+
}
905907
}
906908

907909
/// A tree-folder that applies every rename in its list to
@@ -931,6 +933,9 @@ impl<'a> Folder for PatIdentRenamer<'a> {
931933
_ => noop_fold_pat(pat, self)
932934
}
933935
}
936+
fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
937+
fold::fold_mac(macro, self)
938+
}
934939
}
935940

936941
// expand a method

src/libsyntax/fold.rs

+35-11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
//! A Folder represents an AST->AST fold; it accepts an AST piece,
12+
//! and returns a piece of the same type. So, for instance, macro
13+
//! expansion is a Folder that walks over an AST and produces another
14+
//! AST.
15+
//!
16+
//! Note: using a Folder (other than the MacroExpander Folder) on
17+
//! an AST before macro expansion is probably a bad idea. For instance,
18+
//! a folder renaming item names in a module will miss all of those
19+
//! that are created by the expansion of a macro.
20+
1121
use ast::*;
1222
use ast;
1323
use ast_util;
@@ -299,17 +309,13 @@ pub trait Folder {
299309
}
300310
}
301311

302-
fn fold_mac(&mut self, macro: &Mac) -> Mac {
303-
Spanned {
304-
node: match macro.node {
305-
MacInvocTT(ref p, ref tts, ctxt) => {
306-
MacInvocTT(self.fold_path(p),
307-
fold_tts(tts.as_slice(), self),
308-
ctxt)
309-
}
310-
},
311-
span: self.new_span(macro.span)
312-
}
312+
fn fold_mac(&mut self, _macro: &Mac) -> Mac {
313+
fail!("fold_mac disabled by default");
314+
// NB: see note about macros above.
315+
// if you really want a folder that
316+
// works on macros, use this
317+
// definition in your trait impl:
318+
// fold::fold_mac(_macro, self)
313319
}
314320

315321
fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
@@ -361,6 +367,20 @@ pub trait Folder {
361367

362368
}
363369

370+
371+
pub fn fold_mac<T: Folder>(macro: &Mac, fld: &mut T) -> Mac {
372+
Spanned {
373+
node: match macro.node {
374+
MacInvocTT(ref p, ref tts, ctxt) => {
375+
MacInvocTT(fld.fold_path(p),
376+
fold_tts(tts.as_slice(), fld),
377+
ctxt)
378+
}
379+
},
380+
span: fld.new_span(macro.span)
381+
}
382+
}
383+
364384
/* some little folds that probably aren't useful to have in Folder itself*/
365385

366386
//used in noop_fold_item and noop_fold_crate and noop_fold_crate_directive
@@ -986,6 +1006,7 @@ mod test {
9861006
use util::parser_testing::{string_to_crate, matches_codepattern};
9871007
use parse::token;
9881008
use print::pprust;
1009+
use fold;
9891010
use super::*;
9901011

9911012
// this version doesn't care about getting comments or docstrings in.
@@ -1001,6 +1022,9 @@ mod test {
10011022
fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident {
10021023
token::str_to_ident("zz")
10031024
}
1025+
fn fold_mac(&mut self, macro: &ast::Mac) -> ast::Mac {
1026+
fold::fold_mac(macro, self)
1027+
}
10041028
}
10051029

10061030
// maybe add to expand.rs...

src/libsyntax/visit.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
//! execute before AST node B, then A is visited first. The borrow checker in
2121
//! particular relies on this property.
2222
//!
23+
//! Note: walking an AST before macro expansion is probably a bad idea. For
24+
//! instance, a walker looking for item names in a module will miss all of
25+
//! those that are created by the expansion of a macro.
26+
2327
use abi::Abi;
2428
use ast::*;
2529
use ast;
@@ -124,8 +128,13 @@ pub trait Visitor<E: Clone> {
124128
fn visit_explicit_self(&mut self, es: &ExplicitSelf, e: E) {
125129
walk_explicit_self(self, es, e)
126130
}
127-
fn visit_mac(&mut self, macro: &Mac, e: E) {
128-
walk_mac(self, macro, e)
131+
fn visit_mac(&mut self, _macro: &Mac, _e: E) {
132+
fail!("visit_mac disabled by default");
133+
// NB: see note about macros above.
134+
// if you really want a visitor that
135+
// works on macros, use this
136+
// definition in your trait impl:
137+
// visit::walk_mac(self, _macro, _e)
129138
}
130139
fn visit_path(&mut self, path: &Path, _id: ast::NodeId, e: E) {
131140
walk_path(self, path, e)

0 commit comments

Comments
 (0)