Skip to content

Commit 02887c8

Browse files
committed
macros: Do not try and re-expand if depth has exceeded recursion limit
We need to limit the amount of times that macro get expanded recursively during macro-expansion. This limits the amount of times an ASTFragment can be visited by simply incrementing the depth when setting a fragment, and decreasing it when taking one. This way, recursive expansion which happens at the expansion level (instead of the matching level) will still get caught
1 parent 41f402f commit 02887c8

File tree

4 files changed

+33
-38
lines changed

4 files changed

+33
-38
lines changed

gcc/rust/expand/rust-attribute-visitor.cc

+14-35
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,6 @@ AttrVisitor::visit (AST::MacroInvocation &macro_invoc)
315315
// I don't think any macro token trees can be stripped in any way
316316

317317
// TODO: maybe have cfg! macro stripping behaviour here?
318-
319318
if (macro_invoc.has_semicolon ())
320319
expander.expand_invoc_semi (macro_invoc);
321320
else
@@ -532,23 +531,17 @@ AttrVisitor::visit (AST::ArithmeticOrLogicalExpr &expr)
532531
* with outer expr */
533532
auto &l_expr = expr.get_left_expr ();
534533
l_expr->accept_vis (*this);
535-
auto l_fragment = expander.take_expanded_fragment ();
534+
auto l_fragment = expander.take_expanded_fragment (*this);
536535
if (l_fragment.should_expand ())
537-
{
538-
l_fragment.accept_vis (*this);
539-
l_expr = l_fragment.take_expression_fragment ();
540-
}
536+
l_expr = l_fragment.take_expression_fragment ();
541537

542538
/* should syntactically not have outer attributes, though this may
543539
* not have worked in practice */
544540
auto &r_expr = expr.get_right_expr ();
545541
r_expr->accept_vis (*this);
546-
auto r_fragment = expander.take_expanded_fragment ();
542+
auto r_fragment = expander.take_expanded_fragment (*this);
547543
if (r_fragment.should_expand ())
548-
{
549-
r_fragment.accept_vis (*this);
550-
r_expr = r_fragment.take_expression_fragment ();
551-
}
544+
r_expr = r_fragment.take_expression_fragment ();
552545

553546
// ensure that they are not marked for strip
554547
if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -666,23 +659,17 @@ AttrVisitor::visit (AST::CompoundAssignmentExpr &expr)
666659
* with outer expr */
667660
auto &l_expr = expr.get_left_expr ();
668661
l_expr->accept_vis (*this);
669-
auto l_frag = expander.take_expanded_fragment ();
662+
auto l_frag = expander.take_expanded_fragment (*this);
670663
if (l_frag.should_expand ())
671-
{
672-
l_frag.accept_vis (*this);
673-
l_expr = l_frag.take_expression_fragment ();
674-
}
664+
l_expr = l_frag.take_expression_fragment ();
675665

676666
/* should syntactically not have outer attributes, though this may
677667
* not have worked in practice */
678668
auto &r_expr = expr.get_right_expr ();
679669
r_expr->accept_vis (*this);
680-
auto r_frag = expander.take_expanded_fragment ();
670+
auto r_frag = expander.take_expanded_fragment (*this);
681671
if (r_frag.should_expand ())
682-
{
683-
r_frag.accept_vis (*this);
684-
r_expr = r_frag.take_expression_fragment ();
685-
}
672+
r_expr = r_frag.take_expression_fragment ();
686673

687674
// ensure that they are not marked for strip
688675
if (expr.get_left_expr ()->is_marked_for_strip ())
@@ -1033,10 +1020,9 @@ AttrVisitor::visit (AST::CallExpr &expr)
10331020

10341021
stmt->accept_vis (*this);
10351022

1036-
auto fragment = expander.take_expanded_fragment ();
1023+
auto fragment = expander.take_expanded_fragment (*this);
10371024
if (fragment.should_expand ())
10381025
{
1039-
fragment.accept_vis (*this);
10401026
// Remove the current expanded invocation
10411027
it = params.erase (it);
10421028
for (auto &node : fragment.get_nodes ())
@@ -1157,10 +1143,9 @@ AttrVisitor::visit (AST::BlockExpr &expr)
11571143

11581144
stmt->accept_vis (*this);
11591145

1160-
auto fragment = expander.take_expanded_fragment ();
1146+
auto fragment = expander.take_expanded_fragment (*this);
11611147
if (fragment.should_expand ())
11621148
{
1163-
fragment.accept_vis (*this);
11641149
// Remove the current expanded invocation
11651150
it = stmts.erase (it);
11661151
for (auto &node : fragment.get_nodes ())
@@ -1182,12 +1167,9 @@ AttrVisitor::visit (AST::BlockExpr &expr)
11821167
auto &tail_expr = expr.get_tail_expr ();
11831168

11841169
tail_expr->accept_vis (*this);
1185-
auto fragment = expander.take_expanded_fragment ();
1170+
auto fragment = expander.take_expanded_fragment (*this);
11861171
if (fragment.should_expand ())
1187-
{
1188-
fragment.accept_vis (*this);
1189-
tail_expr = fragment.take_expression_fragment ();
1190-
}
1172+
tail_expr = fragment.take_expression_fragment ();
11911173

11921174
if (tail_expr->is_marked_for_strip ())
11931175
expr.strip_tail_expr ();
@@ -3031,12 +3013,9 @@ AttrVisitor::visit (AST::LetStmt &stmt)
30313013
"cannot strip expression in this position - outer "
30323014
"attributes not allowed");
30333015

3034-
auto fragment = expander.take_expanded_fragment ();
3016+
auto fragment = expander.take_expanded_fragment (*this);
30353017
if (fragment.should_expand ())
3036-
{
3037-
fragment.accept_vis (*this);
3038-
init_expr = fragment.take_expression_fragment ();
3039-
}
3018+
init_expr = fragment.take_expression_fragment ();
30403019
}
30413020
}
30423021
void

gcc/rust/expand/rust-macro-expand.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -379,10 +379,9 @@ MacroExpander::expand_crate ()
379379
// mark for stripping if required
380380
item->accept_vis (attr_visitor);
381381

382-
auto fragment = take_expanded_fragment ();
382+
auto fragment = take_expanded_fragment (attr_visitor);
383383
if (fragment.should_expand ())
384384
{
385-
fragment.accept_vis (attr_visitor);
386385
// Remove the current expanded invocation
387386
it = items.erase (it);
388387
for (auto &node : fragment.get_nodes ())

gcc/rust/expand/rust-macro-expand.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,18 @@ struct MacroExpander
287287
expanded_fragment = std::move (fragment);
288288
}
289289

290-
AST::ASTFragment take_expanded_fragment ()
290+
AST::ASTFragment take_expanded_fragment (AST::ASTVisitor &vis)
291291
{
292292
AST::ASTFragment old_fragment = std::move (expanded_fragment);
293293
expanded_fragment = AST::ASTFragment::create_empty ();
294294

295+
for (auto &node : old_fragment.get_nodes ())
296+
{
297+
expansion_depth++;
298+
node.accept_vis (vis);
299+
expansion_depth--;
300+
}
301+
295302
return old_fragment;
296303
}
297304

gcc/testsuite/rust/compile/macro17.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
macro_rules! rep {
2+
($a:literal) => { $a }; // { dg-error "reached recursion limit" }
3+
($a:literal $(, $e:literal)*) => { // { dg-error "reached recursion limit" }
4+
$a + rep!(0 $(, $e)*) // { dg-error "Failed to match" }
5+
}
6+
}
7+
8+
fn main() -> i32 {
9+
rep!(1, 2)
10+
}

0 commit comments

Comments
 (0)