about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libsyntax/ext/base.rs8
-rw-r--r--src/libsyntax/ext/expand.rs24
-rw-r--r--src/libsyntax/ext/placeholders.rs10
-rw-r--r--src/libsyntax/test.rs4
-rw-r--r--src/libsyntax_ext/rustc_macro_registrar.rs2
5 files changed, 32 insertions, 16 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 1e8f8ef9ddd..fb4816d3847 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -549,7 +549,13 @@ impl<'a> ExtCtxt<'a> {
 
     /// Returns a `Folder` for deeply expanding all macros in an AST node.
     pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
-        expand::MacroExpander::new(self, false, false)
+        expand::MacroExpander::new(self, false)
+    }
+
+    /// Returns a `Folder` that deeply expands all macros and assigns all node ids in an AST node.
+    /// Once node ids are assigned, the node may not be expanded, removed, or otherwise modified.
+    pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
+        expand::MacroExpander::new(self, true)
     }
 
     pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree])
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 0eb9d4bc0c2..62e299684b7 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -175,16 +175,16 @@ pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
     pub single_step: bool,
     pub keep_macs: bool,
+    monotonic: bool, // c.f. `cx.monotonic_expander()`
 }
 
 impl<'a, 'b> MacroExpander<'a, 'b> {
-    pub fn new(cx: &'a mut ExtCtxt<'b>,
-               single_step: bool,
-               keep_macs: bool) -> MacroExpander<'a, 'b> {
+    pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
         MacroExpander {
             cx: cx,
-            single_step: single_step,
-            keep_macs: keep_macs
+            monotonic: monotonic,
+            single_step: false,
+            keep_macs: false,
         }
     }
 
@@ -245,7 +245,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
         self.cx.current_expansion = orig_expansion_data;
 
-        let mut placeholder_expander = PlaceholderExpander::new(self.cx);
+        let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
                 let expansion = expansion.fold_with(&mut placeholder_expander);
@@ -268,6 +268,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 },
                 cx: self.cx,
                 invocations: Vec::new(),
+                monotonic: self.monotonic,
             };
             (expansion.fold_with(&mut collector), collector.invocations)
         };
@@ -450,6 +451,7 @@ struct InvocationCollector<'a, 'b: 'a> {
     cx: &'a mut ExtCtxt<'b>,
     cfg: StripUnconfigured<'a>,
     invocations: Vec<Invocation>,
+    monotonic: bool,
 }
 
 macro_rules! fully_configure {
@@ -709,8 +711,12 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     }
 
     fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
-        assert_eq!(id, ast::DUMMY_NODE_ID);
-        self.cx.resolver.next_node_id()
+        if self.monotonic {
+            assert_eq!(id, ast::DUMMY_NODE_ID);
+            self.cx.resolver.next_node_id()
+        } else {
+            id
+        }
     }
 }
 
@@ -763,7 +769,7 @@ pub fn expand_crate(cx: &mut ExtCtxt,
                     user_exts: Vec<NamedSyntaxExtension>,
                     c: Crate) -> Crate {
     cx.initialize(user_exts, &c);
-    cx.expander().expand_crate(c)
+    cx.monotonic_expander().expand_crate(c)
 }
 
 // Expands crate using supplied MacroExpander - allows for
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 7635705daa0..47f366a8876 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -75,13 +75,15 @@ pub fn macro_scope_placeholder() -> Expansion {
 pub struct PlaceholderExpander<'a, 'b: 'a> {
     expansions: HashMap<ast::NodeId, Expansion>,
     cx: &'a mut ExtCtxt<'b>,
+    monotonic: bool,
 }
 
 impl<'a, 'b> PlaceholderExpander<'a, 'b> {
-    pub fn new(cx: &'a mut ExtCtxt<'b>) -> Self {
+    pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
         PlaceholderExpander {
             cx: cx,
             expansions: HashMap::new(),
+            monotonic: monotonic,
         }
     }
 
@@ -182,13 +184,15 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
                     // which shares a HIR node with the expression itself.
                     ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id,
 
-                    _ => {
+                    _ if self.monotonic => {
                         assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
                         stmt.id = self.cx.resolver.next_node_id();
                     }
+
+                    _ => {}
                 }
 
-                if !macros.is_empty() {
+                if self.monotonic && !macros.is_empty() {
                     let macros = mem::replace(&mut macros, Vec::new());
                     self.cx.resolver.add_expansions_at_stmt(stmt.id, macros);
                 }
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 46c9a4606cc..6327e8f71bc 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -257,7 +257,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
     };
 
     let sym = token::gensym_ident("__test_reexports");
-    let it = cx.ext_cx.expander().fold_item(P(ast::Item {
+    let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item {
         ident: sym.clone(),
         attrs: Vec::new(),
         id: ast::DUMMY_NODE_ID,
@@ -512,7 +512,7 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P<ast::Item>, Option<P<ast::Item>>) {
     let item_ = ast::ItemKind::Mod(testmod);
     let mod_ident = token::gensym_ident("__test");
 
-    let mut expander = cx.ext_cx.expander();
+    let mut expander = cx.ext_cx.monotonic_expander();
     let item = expander.fold_item(P(ast::Item {
         id: ast::DUMMY_NODE_ID,
         ident: mod_ident,
diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs
index c07e7917939..ce3e53cdf97 100644
--- a/src/libsyntax_ext/rustc_macro_registrar.rs
+++ b/src/libsyntax_ext/rustc_macro_registrar.rs
@@ -273,5 +273,5 @@ fn mk_registrar(cx: &mut ExtCtxt,
         i
     });
 
-    cx.expander().fold_item(module).pop().unwrap()
+    cx.monotonic_expander().fold_item(module).pop().unwrap()
 }