Skip to content

Commit 0feda45

Browse files
committed
macros: Add remaining context and improve parsing macro dispatch
This allows us to expand macor invocations in more places, as macro calls are not limited to statements or expressions. It is quite common to use macros to abstract writing repetitive boilerplate for type implementations, for example.
1 parent 2dfc196 commit 0feda45

File tree

8 files changed

+300
-94
lines changed

8 files changed

+300
-94
lines changed

gcc/rust/ast/rust-ast.h

Lines changed: 103 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,18 +1488,45 @@ class SingleASTNode
14881488
EXPRESSION,
14891489
ITEM,
14901490
STMT,
1491+
EXTERN,
1492+
TRAIT,
1493+
IMPL,
14911494
};
14921495

1496+
private:
1497+
NodeType kind;
1498+
1499+
// FIXME make this a union
1500+
std::unique_ptr<Expr> expr;
1501+
std::unique_ptr<Item> item;
1502+
std::unique_ptr<Stmt> stmt;
1503+
std::unique_ptr<ExternalItem> external_item;
1504+
std::unique_ptr<TraitItem> trait_item;
1505+
std::unique_ptr<InherentImplItem> impl_item;
1506+
1507+
public:
14931508
SingleASTNode (std::unique_ptr<Expr> expr)
1494-
: kind (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr)
1509+
: kind (EXPRESSION), expr (std::move (expr))
14951510
{}
14961511

14971512
SingleASTNode (std::unique_ptr<Item> item)
1498-
: kind (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr)
1513+
: kind (ITEM), item (std::move (item))
14991514
{}
15001515

15011516
SingleASTNode (std::unique_ptr<Stmt> stmt)
1502-
: kind (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt))
1517+
: kind (STMT), stmt (std::move (stmt))
1518+
{}
1519+
1520+
SingleASTNode (std::unique_ptr<ExternalItem> item)
1521+
: kind (EXTERN), external_item (std::move (item))
1522+
{}
1523+
1524+
SingleASTNode (std::unique_ptr<TraitItem> item)
1525+
: kind (TRAIT), trait_item (std::move (item))
1526+
{}
1527+
1528+
SingleASTNode (std::unique_ptr<InherentImplItem> item)
1529+
: kind (IMPL), impl_item (std::move (item))
15031530
{}
15041531

15051532
SingleASTNode (SingleASTNode const &other)
@@ -1518,6 +1545,18 @@ class SingleASTNode
15181545
case STMT:
15191546
stmt = other.stmt->clone_stmt ();
15201547
break;
1548+
1549+
case EXTERN:
1550+
external_item = other.external_item->clone_external_item ();
1551+
break;
1552+
1553+
case TRAIT:
1554+
trait_item = other.trait_item->clone_trait_item ();
1555+
break;
1556+
1557+
case IMPL:
1558+
impl_item = other.impl_item->clone_inherent_impl_item ();
1559+
break;
15211560
}
15221561
}
15231562

@@ -1537,6 +1576,18 @@ class SingleASTNode
15371576
case STMT:
15381577
stmt = other.stmt->clone_stmt ();
15391578
break;
1579+
1580+
case EXTERN:
1581+
external_item = other.external_item->clone_external_item ();
1582+
break;
1583+
1584+
case TRAIT:
1585+
trait_item = other.trait_item->clone_trait_item ();
1586+
break;
1587+
1588+
case IMPL:
1589+
impl_item = other.impl_item->clone_inherent_impl_item ();
1590+
break;
15401591
}
15411592
return *this;
15421593
}
@@ -1546,7 +1597,7 @@ class SingleASTNode
15461597

15471598
NodeType get_kind () const { return kind; }
15481599

1549-
std::unique_ptr<Expr> &get_inner ()
1600+
std::unique_ptr<Expr> &get_expr ()
15501601
{
15511602
rust_assert (kind == EXPRESSION);
15521603
return expr;
@@ -1587,6 +1638,24 @@ class SingleASTNode
15871638
return std::move (item);
15881639
}
15891640

1641+
std::unique_ptr<TraitItem> take_trait_item ()
1642+
{
1643+
rust_assert (!is_error ());
1644+
return std::move (trait_item);
1645+
}
1646+
1647+
std::unique_ptr<ExternalItem> take_external_item ()
1648+
{
1649+
rust_assert (!is_error ());
1650+
return std::move (external_item);
1651+
}
1652+
1653+
std::unique_ptr<InherentImplItem> take_impl_item ()
1654+
{
1655+
rust_assert (!is_error ());
1656+
return std::move (impl_item);
1657+
}
1658+
15901659
void accept_vis (ASTVisitor &vis)
15911660
{
15921661
switch (kind)
@@ -1602,6 +1671,18 @@ class SingleASTNode
16021671
case STMT:
16031672
stmt->accept_vis (vis);
16041673
break;
1674+
1675+
case EXTERN:
1676+
external_item->accept_vis (vis);
1677+
break;
1678+
1679+
case TRAIT:
1680+
trait_item->accept_vis (vis);
1681+
break;
1682+
1683+
case IMPL:
1684+
impl_item->accept_vis (vis);
1685+
break;
16051686
}
16061687
}
16071688

@@ -1615,9 +1696,16 @@ class SingleASTNode
16151696
return item == nullptr;
16161697
case STMT:
16171698
return stmt == nullptr;
1618-
default:
1619-
return true;
1699+
case EXTERN:
1700+
return external_item == nullptr;
1701+
case TRAIT:
1702+
return trait_item == nullptr;
1703+
case IMPL:
1704+
return impl_item == nullptr;
16201705
}
1706+
1707+
gcc_unreachable ();
1708+
return true;
16211709
}
16221710

16231711
std::string as_string ()
@@ -1630,18 +1718,17 @@ class SingleASTNode
16301718
return "Item: " + item->as_string ();
16311719
case STMT:
16321720
return "Stmt: " + stmt->as_string ();
1633-
default:
1634-
return "";
1721+
case EXTERN:
1722+
return "External Item: " + external_item->as_string ();
1723+
case TRAIT:
1724+
return "Trait Item: " + trait_item->as_string ();
1725+
case IMPL:
1726+
return "Impl Item: " + impl_item->as_string ();
16351727
}
1636-
}
1637-
1638-
private:
1639-
NodeType kind;
16401728

1641-
// FIXME make this a union
1642-
std::unique_ptr<Expr> expr;
1643-
std::unique_ptr<Item> item;
1644-
std::unique_ptr<Stmt> stmt;
1729+
gcc_unreachable ();
1730+
return "";
1731+
}
16451732
};
16461733

16471734
/* Basically, a "fragment" that can be incorporated into the AST, created as

gcc/rust/ast/rust-macro.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ class MacroInvocation : public TypeNoBounds,
458458
public TraitItem,
459459
public TraitImplItem,
460460
public InherentImplItem,
461+
public ExternalItem,
461462
public ExprWithoutBlock
462463
{
463464
std::vector<Attribute> outer_attrs;
@@ -533,6 +534,11 @@ class MacroInvocation : public TypeNoBounds,
533534
return clone_macro_invocation_impl ();
534535
}
535536

537+
MacroInvocation *clone_external_item_impl () const final override
538+
{
539+
return clone_macro_invocation_impl ();
540+
}
541+
536542
/*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
537543
{
538544
return new MacroInvocation (*this);

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

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,8 +1128,6 @@ AttrVisitor::visit (AST::ClosureExprInner &expr)
11281128
void
11291129
AttrVisitor::visit (AST::BlockExpr &expr)
11301130
{
1131-
expander.push_context (MacroExpander::BLOCK);
1132-
11331131
// initial strip test based on outer attrs
11341132
expander.expand_cfg_attrs (expr.get_outer_attrs ());
11351133
if (expander.fails_cfg_with_expand (expr.get_outer_attrs ()))
@@ -1149,32 +1147,13 @@ AttrVisitor::visit (AST::BlockExpr &expr)
11491147
return;
11501148
}
11511149

1152-
// strip all statements
1153-
auto &stmts = expr.get_statements ();
1154-
for (auto it = stmts.begin (); it != stmts.end ();)
1155-
{
1156-
auto &stmt = *it;
1150+
std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor
1151+
= [] (AST::SingleASTNode node) { return node.take_stmt (); };
11571152

1158-
stmt->accept_vis (*this);
1153+
expand_macro_children (MacroExpander::BLOCK, expr.get_statements (),
1154+
extractor);
11591155

1160-
auto fragment = expander.take_expanded_fragment ();
1161-
if (fragment.should_expand ())
1162-
{
1163-
fragment.accept_vis (*this);
1164-
// Remove the current expanded invocation
1165-
it = stmts.erase (it);
1166-
for (auto &node : fragment.get_nodes ())
1167-
{
1168-
it = stmts.insert (it, node.take_stmt ());
1169-
it++;
1170-
}
1171-
}
1172-
1173-
else if (stmt->is_marked_for_strip ())
1174-
it = stmts.erase (it);
1175-
else
1176-
it++;
1177-
}
1156+
expander.push_context (MacroExpander::BLOCK);
11781157

11791158
// strip tail expression if exists - can actually fully remove it
11801159
if (expr.has_tail_expr ())
@@ -2507,8 +2486,11 @@ AttrVisitor::visit (AST::Trait &trait)
25072486
if (trait.has_where_clause ())
25082487
expand_where_clause (trait.get_where_clause ());
25092488

2510-
// strip trait items if required
2511-
expand_pointer_allow_strip (trait.get_trait_items ());
2489+
std::function<std::unique_ptr<AST::TraitItem> (AST::SingleASTNode)> extractor
2490+
= [] (AST::SingleASTNode node) { return node.take_trait_item (); };
2491+
2492+
expand_macro_children (MacroExpander::TRAIT, trait.get_trait_items (),
2493+
extractor);
25122494
}
25132495
void
25142496
AttrVisitor::visit (AST::InherentImpl &impl)
@@ -2541,8 +2523,11 @@ AttrVisitor::visit (AST::InherentImpl &impl)
25412523
if (impl.has_where_clause ())
25422524
expand_where_clause (impl.get_where_clause ());
25432525

2544-
// strip inherent impl items if required
2545-
expand_pointer_allow_strip (impl.get_impl_items ());
2526+
std::function<std::unique_ptr<AST::InherentImplItem> (AST::SingleASTNode)>
2527+
extractor = [] (AST::SingleASTNode node) { return node.take_impl_item (); };
2528+
2529+
expand_macro_children (MacroExpander::IMPL, impl.get_impl_items (),
2530+
extractor);
25462531
}
25472532
void
25482533
AttrVisitor::visit (AST::TraitImpl &impl)
@@ -2677,8 +2662,12 @@ AttrVisitor::visit (AST::ExternBlock &block)
26772662
return;
26782663
}
26792664

2680-
// strip external items if required
2681-
expand_pointer_allow_strip (block.get_extern_items ());
2665+
std::function<std::unique_ptr<AST::ExternalItem> (AST::SingleASTNode)>
2666+
extractor
2667+
= [] (AST::SingleASTNode node) { return node.take_external_item (); };
2668+
2669+
expand_macro_children (MacroExpander::EXTERN, block.get_extern_items (),
2670+
extractor);
26822671
}
26832672

26842673
// I don't think it would be possible to strip macros without expansion

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

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,70 @@ class AttrVisitor : public AST::ASTVisitor
4040
void expand_trait_function_decl (AST::TraitFunctionDecl &decl);
4141
void expand_trait_method_decl (AST::TraitMethodDecl &decl);
4242

43-
template <typename T> void expand_pointer_allow_strip (T &values)
43+
/**
44+
* Expand a set of values, erasing them if they are marked for strip, and
45+
* replacing them with expanded macro nodes if necessary.
46+
* This function is slightly different from `expand_pointer_allow_strip` as
47+
* it can only be called in certain expansion contexts - where macro
48+
* invocations are allowed.
49+
*
50+
* @param ctx Context to use for macro expansion
51+
* @param values Iterable reference over values to replace or erase
52+
* @param extractor Function to call when replacing values with the content
53+
* of an expanded AST node
54+
*/
55+
template <typename T, typename U>
56+
void expand_macro_children (MacroExpander::ContextType ctx, T &values,
57+
std::function<U (AST::SingleASTNode)> extractor)
4458
{
59+
expander.push_context (ctx);
60+
4561
for (auto it = values.begin (); it != values.end ();)
4662
{
4763
auto &value = *it;
4864

4965
// mark for stripping if required
5066
value->accept_vis (*this);
67+
auto fragment = expander.take_expanded_fragment ();
68+
if (fragment.should_expand ())
69+
{
70+
fragment.accept_vis (*this);
71+
it = values.erase (it);
72+
for (auto &node : fragment.get_nodes ())
73+
{
74+
it = values.insert (it, extractor (node));
75+
it++;
76+
}
77+
}
78+
else if (value->is_marked_for_strip ())
79+
{
80+
it = values.erase (it);
81+
}
82+
else
83+
{
84+
++it;
85+
}
86+
}
87+
88+
expander.pop_context ();
89+
}
90+
91+
template <typename T> void expand_pointer_allow_strip (T &values)
92+
{
93+
for (auto it = values.begin (); it != values.end ();)
94+
{
95+
auto &value = *it;
5196

97+
// mark for stripping if required
98+
value->accept_vis (*this);
5299
if (value->is_marked_for_strip ())
53-
it = values.erase (it);
100+
{
101+
it = values.erase (it);
102+
}
54103
else
55-
++it;
104+
{
105+
++it;
106+
}
56107
}
57108
}
58109

0 commit comments

Comments
 (0)