From b54e1e399741579612f13e2df98a25ea9447989d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 05:42:45 +0000 Subject: [PATCH] Differentiate between monotonic and non-monotonic expansion and only assign node ids during monotonic expansion. --- src/libsyntax/ext/base.rs | 8 +++++++- src/libsyntax/ext/expand.rs | 24 ++++++++++++++-------- src/libsyntax/ext/placeholders.rs | 10 ++++++--- src/libsyntax/test.rs | 4 ++-- src/libsyntax_ext/rustc_macro_registrar.rs | 2 +- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1e8f8ef9ddd6c..fb4816d3847ed 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 0eb9d4bc0c2f7..62e299684b760 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, + 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, 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 7635705daa052..47f366a88768e 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, 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 46c9a4606ccef..6327e8f71bcd5 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -257,7 +257,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, }; 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, Option>) { 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 c07e79179398e..ce3e53cdf97f4 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() }