Skip to content

Commit 1a2ef9c

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 1a14348 commit 1a2ef9c

8 files changed

+298
-91
lines changed

gcc/rust/ast/rust-ast.h

Lines changed: 103 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,18 +1511,45 @@ class SingleASTNode
15111511
EXPRESSION,
15121512
ITEM,
15131513
STMT,
1514+
EXTERN,
1515+
TRAIT,
1516+
IMPL,
15141517
};
15151518

1519+
private:
1520+
NodeType kind;
1521+
1522+
// FIXME make this a union
1523+
std::unique_ptr<Expr> expr;
1524+
std::unique_ptr<Item> item;
1525+
std::unique_ptr<Stmt> stmt;
1526+
std::unique_ptr<ExternalItem> external_item;
1527+
std::unique_ptr<TraitItem> trait_item;
1528+
std::unique_ptr<InherentImplItem> impl_item;
1529+
1530+
public:
15161531
SingleASTNode (std::unique_ptr<Expr> expr)
1517-
: kind (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr)
1532+
: kind (EXPRESSION), expr (std::move (expr))
15181533
{}
15191534

15201535
SingleASTNode (std::unique_ptr<Item> item)
1521-
: kind (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr)
1536+
: kind (ITEM), item (std::move (item))
15221537
{}
15231538

15241539
SingleASTNode (std::unique_ptr<Stmt> stmt)
1525-
: kind (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt))
1540+
: kind (STMT), stmt (std::move (stmt))
1541+
{}
1542+
1543+
SingleASTNode (std::unique_ptr<ExternalItem> item)
1544+
: kind (EXTERN), external_item (std::move (item))
1545+
{}
1546+
1547+
SingleASTNode (std::unique_ptr<TraitItem> item)
1548+
: kind (TRAIT), trait_item (std::move (item))
1549+
{}
1550+
1551+
SingleASTNode (std::unique_ptr<InherentImplItem> item)
1552+
: kind (IMPL), impl_item (std::move (item))
15261553
{}
15271554

15281555
SingleASTNode (SingleASTNode const &other)
@@ -1541,6 +1568,18 @@ class SingleASTNode
15411568
case STMT:
15421569
stmt = other.stmt->clone_stmt ();
15431570
break;
1571+
1572+
case EXTERN:
1573+
external_item = other.external_item->clone_external_item ();
1574+
break;
1575+
1576+
case TRAIT:
1577+
trait_item = other.trait_item->clone_trait_item ();
1578+
break;
1579+
1580+
case IMPL:
1581+
impl_item = other.impl_item->clone_inherent_impl_item ();
1582+
break;
15441583
}
15451584
}
15461585

@@ -1560,6 +1599,18 @@ class SingleASTNode
15601599
case STMT:
15611600
stmt = other.stmt->clone_stmt ();
15621601
break;
1602+
1603+
case EXTERN:
1604+
external_item = other.external_item->clone_external_item ();
1605+
break;
1606+
1607+
case TRAIT:
1608+
trait_item = other.trait_item->clone_trait_item ();
1609+
break;
1610+
1611+
case IMPL:
1612+
impl_item = other.impl_item->clone_inherent_impl_item ();
1613+
break;
15631614
}
15641615
return *this;
15651616
}
@@ -1569,7 +1620,7 @@ class SingleASTNode
15691620

15701621
NodeType get_kind () const { return kind; }
15711622

1572-
std::unique_ptr<Expr> &get_inner ()
1623+
std::unique_ptr<Expr> &get_expr ()
15731624
{
15741625
rust_assert (kind == EXPRESSION);
15751626
return expr;
@@ -1610,6 +1661,24 @@ class SingleASTNode
16101661
return std::move (item);
16111662
}
16121663

1664+
std::unique_ptr<TraitItem> take_trait_item ()
1665+
{
1666+
rust_assert (!is_error ());
1667+
return std::move (trait_item);
1668+
}
1669+
1670+
std::unique_ptr<ExternalItem> take_external_item ()
1671+
{
1672+
rust_assert (!is_error ());
1673+
return std::move (external_item);
1674+
}
1675+
1676+
std::unique_ptr<InherentImplItem> take_impl_item ()
1677+
{
1678+
rust_assert (!is_error ());
1679+
return std::move (impl_item);
1680+
}
1681+
16131682
void accept_vis (ASTVisitor &vis)
16141683
{
16151684
switch (kind)
@@ -1625,6 +1694,18 @@ class SingleASTNode
16251694
case STMT:
16261695
stmt->accept_vis (vis);
16271696
break;
1697+
1698+
case EXTERN:
1699+
external_item->accept_vis (vis);
1700+
break;
1701+
1702+
case TRAIT:
1703+
trait_item->accept_vis (vis);
1704+
break;
1705+
1706+
case IMPL:
1707+
impl_item->accept_vis (vis);
1708+
break;
16281709
}
16291710
}
16301711

@@ -1638,9 +1719,16 @@ class SingleASTNode
16381719
return item == nullptr;
16391720
case STMT:
16401721
return stmt == nullptr;
1641-
default:
1642-
return true;
1722+
case EXTERN:
1723+
return external_item == nullptr;
1724+
case TRAIT:
1725+
return trait_item == nullptr;
1726+
case IMPL:
1727+
return impl_item == nullptr;
16431728
}
1729+
1730+
gcc_unreachable ();
1731+
return true;
16441732
}
16451733

16461734
std::string as_string ()
@@ -1653,18 +1741,17 @@ class SingleASTNode
16531741
return "Item: " + item->as_string ();
16541742
case STMT:
16551743
return "Stmt: " + stmt->as_string ();
1656-
default:
1657-
return "";
1744+
case EXTERN:
1745+
return "External Item: " + external_item->as_string ();
1746+
case TRAIT:
1747+
return "Trait Item: " + trait_item->as_string ();
1748+
case IMPL:
1749+
return "Impl Item: " + impl_item->as_string ();
16581750
}
1659-
}
1660-
1661-
private:
1662-
NodeType kind;
16631751

1664-
// FIXME make this a union
1665-
std::unique_ptr<Expr> expr;
1666-
std::unique_ptr<Item> item;
1667-
std::unique_ptr<Stmt> stmt;
1752+
gcc_unreachable ();
1753+
return "";
1754+
}
16681755
};
16691756

16701757
/* 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
@@ -460,6 +460,7 @@ class MacroInvocation : public TypeNoBounds,
460460
public TraitItem,
461461
public TraitImplItem,
462462
public InherentImplItem,
463+
public ExternalItem,
463464
public ExprWithoutBlock
464465
{
465466
std::vector<Attribute> outer_attrs;
@@ -537,6 +538,11 @@ class MacroInvocation : public TypeNoBounds,
537538
return clone_macro_invocation_impl ();
538539
}
539540

541+
MacroInvocation *clone_external_item_impl () const final override
542+
{
543+
return clone_macro_invocation_impl ();
544+
}
545+
540546
/*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
541547
{
542548
return new MacroInvocation (*this);

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

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,8 +1114,6 @@ AttrVisitor::visit (AST::ClosureExprInner &expr)
11141114
void
11151115
AttrVisitor::visit (AST::BlockExpr &expr)
11161116
{
1117-
expander.push_context (MacroExpander::BLOCK);
1118-
11191117
// initial strip test based on outer attrs
11201118
expander.expand_cfg_attrs (expr.get_outer_attrs ());
11211119
if (expander.fails_cfg_with_expand (expr.get_outer_attrs ()))
@@ -1135,31 +1133,13 @@ AttrVisitor::visit (AST::BlockExpr &expr)
11351133
return;
11361134
}
11371135

1138-
// strip all statements
1139-
auto &stmts = expr.get_statements ();
1140-
for (auto it = stmts.begin (); it != stmts.end ();)
1141-
{
1142-
auto &stmt = *it;
1143-
1144-
stmt->accept_vis (*this);
1136+
std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor
1137+
= [] (AST::SingleASTNode node) { return node.take_stmt (); };
11451138

1146-
auto fragment = expander.take_expanded_fragment (*this);
1147-
if (fragment.should_expand ())
1148-
{
1149-
// Remove the current expanded invocation
1150-
it = stmts.erase (it);
1151-
for (auto &node : fragment.get_nodes ())
1152-
{
1153-
it = stmts.insert (it, node.take_stmt ());
1154-
it++;
1155-
}
1156-
}
1139+
expand_macro_children (MacroExpander::BLOCK, expr.get_statements (),
1140+
extractor);
11571141

1158-
else if (stmt->is_marked_for_strip ())
1159-
it = stmts.erase (it);
1160-
else
1161-
it++;
1162-
}
1142+
expander.push_context (MacroExpander::BLOCK);
11631143

11641144
// strip tail expression if exists - can actually fully remove it
11651145
if (expr.has_tail_expr ())
@@ -2489,8 +2469,11 @@ AttrVisitor::visit (AST::Trait &trait)
24892469
if (trait.has_where_clause ())
24902470
expand_where_clause (trait.get_where_clause ());
24912471

2492-
// strip trait items if required
2493-
expand_pointer_allow_strip (trait.get_trait_items ());
2472+
std::function<std::unique_ptr<AST::TraitItem> (AST::SingleASTNode)> extractor
2473+
= [] (AST::SingleASTNode node) { return node.take_trait_item (); };
2474+
2475+
expand_macro_children (MacroExpander::TRAIT, trait.get_trait_items (),
2476+
extractor);
24942477
}
24952478
void
24962479
AttrVisitor::visit (AST::InherentImpl &impl)
@@ -2523,8 +2506,11 @@ AttrVisitor::visit (AST::InherentImpl &impl)
25232506
if (impl.has_where_clause ())
25242507
expand_where_clause (impl.get_where_clause ());
25252508

2526-
// strip inherent impl items if required
2527-
expand_pointer_allow_strip (impl.get_impl_items ());
2509+
std::function<std::unique_ptr<AST::InherentImplItem> (AST::SingleASTNode)>
2510+
extractor = [] (AST::SingleASTNode node) { return node.take_impl_item (); };
2511+
2512+
expand_macro_children (MacroExpander::IMPL, impl.get_impl_items (),
2513+
extractor);
25282514
}
25292515
void
25302516
AttrVisitor::visit (AST::TraitImpl &impl)
@@ -2659,8 +2645,12 @@ AttrVisitor::visit (AST::ExternBlock &block)
26592645
return;
26602646
}
26612647

2662-
// strip external items if required
2663-
expand_pointer_allow_strip (block.get_extern_items ());
2648+
std::function<std::unique_ptr<AST::ExternalItem> (AST::SingleASTNode)>
2649+
extractor
2650+
= [] (AST::SingleASTNode node) { return node.take_external_item (); };
2651+
2652+
expand_macro_children (MacroExpander::EXTERN, block.get_extern_items (),
2653+
extractor);
26642654
}
26652655

26662656
// 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);
5167

68+
auto fragment = expander.take_expanded_fragment (*this);
69+
if (fragment.should_expand ())
70+
{
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;
96+
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)