Skip to content

Commit f02392c

Browse files
CohenArthurSimplyTheOtherphilberty
committed
macros: Replace macro invocations with expanded nodes
Different parsing functions need to be called based on the context surrounding the macro invocation. This commit adds a flowchart trying to explain the base resolving rules Macro expansion happens at the same level as stripping, where nodes might get removed if they are gated behind an unmet predicate. We also perform macro expansion during this visitor's pass. What we can do is thus to replace macro invocations with new items that might have resulted from macro expansion: Since we're already mutating numerous elements by removing them if they should be stripped, we can also add elements if they should be expanded. This commit also "fixes" macro test cases so that they are now accepted by the new parser, which is more strict than it should for now. Co-authored-by: SimplyTheOther <simplytheother@gmail.com> Co-authored-by: philberty <philip.herron@embecosm.com>
1 parent 39c0425 commit f02392c

30 files changed

+475
-255
lines changed

gcc/rust/ast/rust-ast.h

Lines changed: 105 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,21 +1491,21 @@ class SingleASTNode
14911491
};
14921492

14931493
SingleASTNode (std::unique_ptr<Expr> expr)
1494-
: type (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr)
1494+
: kind (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr)
14951495
{}
14961496

14971497
SingleASTNode (std::unique_ptr<Item> item)
1498-
: type (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr)
1498+
: kind (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr)
14991499
{}
15001500

15011501
SingleASTNode (std::unique_ptr<Stmt> stmt)
1502-
: type (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt))
1502+
: kind (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt))
15031503
{}
15041504

15051505
SingleASTNode (SingleASTNode const &other)
15061506
{
1507-
type = other.type;
1508-
switch (type)
1507+
kind = other.kind;
1508+
switch (kind)
15091509
{
15101510
case EXPRESSION:
15111511
expr = other.expr->clone_expr ();
@@ -1523,8 +1523,8 @@ class SingleASTNode
15231523

15241524
SingleASTNode operator= (SingleASTNode const &other)
15251525
{
1526-
type = other.type;
1527-
switch (type)
1526+
kind = other.kind;
1527+
switch (kind)
15281528
{
15291529
case EXPRESSION:
15301530
expr = other.expr->clone_expr ();
@@ -1544,27 +1544,52 @@ class SingleASTNode
15441544
SingleASTNode (SingleASTNode &&other) = default;
15451545
SingleASTNode &operator= (SingleASTNode &&other) = default;
15461546

1547-
std::unique_ptr<Expr> &get_expr ()
1547+
NodeType get_kind () const { return kind; }
1548+
1549+
std::unique_ptr<Expr> &get_inner ()
15481550
{
1549-
rust_assert (type == EXPRESSION);
1551+
rust_assert (kind == EXPRESSION);
15501552
return expr;
15511553
}
15521554

15531555
std::unique_ptr<Item> &get_item ()
15541556
{
1555-
rust_assert (type == ITEM);
1557+
rust_assert (kind == ITEM);
15561558
return item;
15571559
}
15581560

15591561
std::unique_ptr<Stmt> &get_stmt ()
15601562
{
1561-
rust_assert (type == STMT);
1563+
rust_assert (kind == STMT);
15621564
return stmt;
15631565
}
15641566

1567+
/**
1568+
* Access the inner nodes and take ownership of them.
1569+
* You can only call these functions once per node
1570+
*/
1571+
1572+
std::unique_ptr<Stmt> take_stmt ()
1573+
{
1574+
rust_assert (!is_error ());
1575+
return std::move (stmt);
1576+
}
1577+
1578+
std::unique_ptr<Expr> take_expr ()
1579+
{
1580+
rust_assert (!is_error ());
1581+
return std::move (expr);
1582+
}
1583+
1584+
std::unique_ptr<Item> take_item ()
1585+
{
1586+
rust_assert (!is_error ());
1587+
return std::move (item);
1588+
}
1589+
15651590
void accept_vis (ASTVisitor &vis)
15661591
{
1567-
switch (type)
1592+
switch (kind)
15681593
{
15691594
case EXPRESSION:
15701595
expr->accept_vis (vis);
@@ -1580,8 +1605,38 @@ class SingleASTNode
15801605
}
15811606
}
15821607

1608+
bool is_error ()
1609+
{
1610+
switch (kind)
1611+
{
1612+
case EXPRESSION:
1613+
return expr == nullptr;
1614+
case ITEM:
1615+
return item == nullptr;
1616+
case STMT:
1617+
return stmt == nullptr;
1618+
default:
1619+
return true;
1620+
}
1621+
}
1622+
1623+
std::string as_string ()
1624+
{
1625+
switch (kind)
1626+
{
1627+
case EXPRESSION:
1628+
return "Expr: " + expr->as_string ();
1629+
case ITEM:
1630+
return "Item: " + item->as_string ();
1631+
case STMT:
1632+
return "Stmt: " + stmt->as_string ();
1633+
default:
1634+
return "";
1635+
}
1636+
}
1637+
15831638
private:
1584-
NodeType type;
1639+
NodeType kind;
15851640

15861641
// FIXME make this a union
15871642
std::unique_ptr<Expr> expr;
@@ -1604,11 +1659,18 @@ class ASTFragment
16041659
* ability for a macro to expand to two statements, for instance. */
16051660

16061661
std::vector<SingleASTNode> nodes;
1662+
bool fragment_is_error;
16071663

16081664
public:
1609-
ASTFragment (std::vector<SingleASTNode> nodes) : nodes (std::move (nodes)) {}
1665+
ASTFragment (std::vector<SingleASTNode> nodes, bool fragment_is_error = false)
1666+
: nodes (std::move (nodes)), fragment_is_error (fragment_is_error)
1667+
{
1668+
if (fragment_is_error)
1669+
rust_assert (nodes.empty ());
1670+
}
16101671

16111672
ASTFragment (ASTFragment const &other)
1673+
: fragment_is_error (other.fragment_is_error)
16121674
{
16131675
nodes.clear ();
16141676
nodes.reserve (other.nodes.size ());
@@ -1620,18 +1682,47 @@ class ASTFragment
16201682

16211683
ASTFragment &operator= (ASTFragment const &other)
16221684
{
1685+
fragment_is_error = other.fragment_is_error;
16231686
nodes.clear ();
16241687
nodes.reserve (other.nodes.size ());
16251688
for (auto &n : other.nodes)
16261689
{
16271690
nodes.push_back (n);
16281691
}
1692+
16291693
return *this;
16301694
}
16311695

16321696
static ASTFragment create_empty () { return ASTFragment ({}); }
1697+
static ASTFragment create_error () { return ASTFragment ({}, true); }
16331698

16341699
std::vector<SingleASTNode> &get_nodes () { return nodes; }
1700+
bool is_error () const { return fragment_is_error; }
1701+
1702+
bool should_expand () const { return !is_error () && !nodes.empty (); }
1703+
1704+
/**
1705+
* We need to make a special case for Expression fragments as only one
1706+
* Node will be extracted from the `nodes` vector
1707+
*/
1708+
1709+
bool is_expression_fragment () const
1710+
{
1711+
return nodes.size () == 1
1712+
&& nodes[0].get_kind () == SingleASTNode::NodeType::EXPRESSION;
1713+
}
1714+
1715+
std::unique_ptr<Expr> take_expression_fragment ()
1716+
{
1717+
rust_assert (is_expression_fragment ());
1718+
return nodes[0].take_expr ();
1719+
}
1720+
1721+
void accept_vis (ASTVisitor &vis)
1722+
{
1723+
for (auto &node : nodes)
1724+
node.accept_vis (vis);
1725+
}
16351726
};
16361727

16371728
// A crate AST object - holds all the data for a single compilation unit

gcc/rust/ast/rust-macro.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,6 @@ class MacroInvocation : public TypeNoBounds,
464464
MacroInvocData invoc_data;
465465
Location locus;
466466

467-
// this is the expanded macro
468-
ASTFragment fragment;
469-
470467
// Important for when we actually expand the macro
471468
bool is_semi_coloned;
472469

@@ -480,7 +477,6 @@ class MacroInvocation : public TypeNoBounds,
480477
bool is_semi_coloned = false)
481478
: outer_attrs (std::move (outer_attrs)),
482479
invoc_data (std::move (invoc_data)), locus (locus),
483-
fragment (ASTFragment::create_empty ()),
484480
is_semi_coloned (is_semi_coloned),
485481
node_id (Analysis::Mappings::get ()->get_next_node_id ())
486482
{}
@@ -513,10 +509,6 @@ class MacroInvocation : public TypeNoBounds,
513509

514510
MacroInvocData &get_invoc_data () { return invoc_data; }
515511

516-
ASTFragment &get_fragment () { return fragment; }
517-
518-
void set_fragment (ASTFragment &&f) { fragment = std::move (f); }
519-
520512
bool has_semicolon () const { return is_semi_coloned; }
521513

522514
protected:

0 commit comments

Comments
 (0)