about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-09-06 05:42:45 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-09-13 09:40:28 +0000
commitb54e1e399741579612f13e2df98a25ea9447989d (patch)
tree6663013cac173001b1d084c95730675bd57b4fcd /src/libsyntax/ext
parent78c00398780db6f59ebf43e765fa9368dad436d2 (diff)
downloadrust-b54e1e399741579612f13e2df98a25ea9447989d.tar.gz
rust-b54e1e399741579612f13e2df98a25ea9447989d.zip
Differentiate between monotonic and non-monotonic expansion and
only assign node ids during monotonic expansion.
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/base.rs8
-rw-r--r--src/libsyntax/ext/expand.rs24
-rw-r--r--src/libsyntax/ext/placeholders.rs10
3 files changed, 29 insertions, 13 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);
                 }