Skip to content

Commit 12d1565

Browse files
committed
parser: Allow parsing macro invocations as statements
When parsing a macro invocation as a statement, the parser would parse an expression and then try parsing a semicolon. Since no actual lookahead was done (which is a good thing), we couldn't convert a `MacroInvocation` to a `MacroInvocationSemi` after the fact. Since, unlike function calls, macro invocations can act differently based on whether or not they are followed by a semicolon, we actually need to differentiate between the two up until expansion. This commits adds a new virtual method for ExprWithoutBlock when converting to ExprStmtWithoutBlock so that classes inheriting ExprWithoutBlock can specify a new behavior. In the case of our MacroInvocation class, it simply means toggling a boolean: If we're converting a macro from an expression to a statement, it must mean that it should contain a semicolon.
1 parent bf92a10 commit 12d1565

20 files changed

+262
-296
lines changed

gcc/rust/ast/rust-ast-full-decls.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ class MacroItem;
5454
class TraitItem;
5555
class InherentImplItem;
5656
class TraitImplItem;
57-
class MacroInvocationSemi;
5857
struct Crate;
5958
class PathExpr;
6059

gcc/rust/ast/rust-ast-full-test.cc

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,17 +1275,18 @@ TypeAlias::as_string () const
12751275
return str;
12761276
}
12771277

1278-
std::string
1279-
MacroInvocationSemi::as_string () const
1280-
{
1281-
std::string str = "MacroInvocationSemi: ";
1282-
1283-
str += append_attributes (outer_attrs, OUTER);
1284-
1285-
str += "\n" + invoc_data.as_string ();
1286-
1287-
return str;
1288-
}
1278+
// FIXME: ARTHUR: Check if this is necessary for MacroInvocation
1279+
// std::string
1280+
// MacroInvocationSemi::as_string () const
1281+
// {
1282+
// std::string str = "MacroInvocationSemi: ";
1283+
//
1284+
// str += append_attributes (outer_attrs, OUTER);
1285+
//
1286+
// str += "\n" + invoc_data.as_string ();
1287+
//
1288+
// return str;
1289+
// }
12891290

12901291
std::string
12911292
ExternBlock::as_string () const
@@ -1377,6 +1378,9 @@ MacroInvocation::as_string () const
13771378

13781379
str += "\n " + invoc_data.as_string ();
13791380

1381+
str += "\n has semicolon: ";
1382+
str += has_semicolon () ? "true" : "false";
1383+
13801384
return str;
13811385
}
13821386

@@ -4921,12 +4925,6 @@ LifetimeParam::accept_vis (ASTVisitor &vis)
49214925
vis.visit (*this);
49224926
}
49234927

4924-
void
4925-
MacroInvocationSemi::accept_vis (ASTVisitor &vis)
4926-
{
4927-
vis.visit (*this);
4928-
}
4929-
49304928
void
49314929
PathInExpression::accept_vis (ASTVisitor &vis)
49324930
{

gcc/rust/ast/rust-ast-visitor.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ class ASTVisitor
5252
// virtual void visit(TraitItem& trait_item) = 0;
5353
// virtual void visit(InherentImplItem& inherent_impl_item) = 0;
5454
// virtual void visit(TraitImplItem& trait_impl_item) = 0;
55-
virtual void visit (MacroInvocationSemi &macro) = 0;
5655

5756
// rust-path.h
5857
virtual void visit (PathInExpression &path) = 0;

gcc/rust/ast/rust-ast.h

Lines changed: 5 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,9 @@ class Item : public Stmt
861861
add_crate_name (std::vector<std::string> &names ATTRIBUTE_UNUSED) const
862862
{}
863863

864-
bool is_item () const override final { return true; }
864+
// FIXME: ARTHUR: Is it okay to have removed that final? Is it *required*
865+
// behavior that we have items that can also be expressions?
866+
bool is_item () const override { return true; }
865867

866868
protected:
867869
// Clone function implementation as pure virtual method
@@ -957,6 +959,8 @@ class ExprWithoutBlock : public Expr
957959
{
958960
return clone_expr_without_block_impl ();
959961
}
962+
963+
virtual ExprWithoutBlock *to_stmt () const { return clone_expr_impl (); }
960964
};
961965

962966
/* HACK: IdentifierExpr, delete when figure out identifier vs expr problem in
@@ -1630,104 +1634,6 @@ class ASTFragment
16301634
std::vector<SingleASTNode> &get_nodes () { return nodes; }
16311635
};
16321636

1633-
/* A macro invocation item (or statement) AST node (i.e. semi-coloned macro
1634-
* invocation) */
1635-
class MacroInvocationSemi : public MacroItem,
1636-
public TraitItem,
1637-
public InherentImplItem,
1638-
public TraitImplItem,
1639-
public ExternalItem
1640-
{
1641-
std::vector<Attribute> outer_attrs;
1642-
MacroInvocData invoc_data;
1643-
Location locus;
1644-
NodeId node_id;
1645-
1646-
// this is the expanded macro
1647-
ASTFragment fragment;
1648-
1649-
public:
1650-
std::string as_string () const override;
1651-
1652-
MacroInvocationSemi (MacroInvocData invoc_data,
1653-
std::vector<Attribute> outer_attrs, Location locus)
1654-
: outer_attrs (std::move (outer_attrs)),
1655-
invoc_data (std::move (invoc_data)), locus (locus),
1656-
node_id (Analysis::Mappings::get ()->get_next_node_id ()),
1657-
fragment (ASTFragment::create_empty ())
1658-
{}
1659-
1660-
void accept_vis (ASTVisitor &vis) override;
1661-
1662-
// Clones this macro invocation semi.
1663-
std::unique_ptr<MacroInvocationSemi> clone_macro_invocation_semi () const
1664-
{
1665-
return std::unique_ptr<MacroInvocationSemi> (
1666-
clone_macro_invocation_semi_impl ());
1667-
}
1668-
1669-
void mark_for_strip () override { invoc_data.mark_for_strip (); }
1670-
bool is_marked_for_strip () const override
1671-
{
1672-
return invoc_data.is_marked_for_strip ();
1673-
}
1674-
1675-
// TODO: this mutable getter seems really dodgy. Think up better way.
1676-
const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1677-
std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
1678-
1679-
Location get_locus () const override final { return locus; }
1680-
1681-
MacroInvocData &get_invoc_data () { return invoc_data; }
1682-
1683-
ASTFragment &get_fragment () { return fragment; }
1684-
1685-
void set_fragment (ASTFragment &&f) { fragment = std::move (f); }
1686-
1687-
NodeId get_macro_node_id () const { return node_id; }
1688-
1689-
protected:
1690-
MacroInvocationSemi *clone_macro_invocation_semi_impl () const
1691-
{
1692-
return new MacroInvocationSemi (*this);
1693-
}
1694-
1695-
/* Use covariance to implement clone function as returning this object
1696-
* rather than base */
1697-
MacroInvocationSemi *clone_item_impl () const final override
1698-
{
1699-
return clone_macro_invocation_semi_impl ();
1700-
}
1701-
1702-
/* Use covariance to implement clone function as returning this object
1703-
* rather than base */
1704-
MacroInvocationSemi *clone_inherent_impl_item_impl () const final override
1705-
{
1706-
return clone_macro_invocation_semi_impl ();
1707-
}
1708-
1709-
/* Use covariance to implement clone function as returning this object
1710-
* rather than base */
1711-
MacroInvocationSemi *clone_trait_impl_item_impl () const final override
1712-
{
1713-
return clone_macro_invocation_semi_impl ();
1714-
}
1715-
1716-
/* Use covariance to implement clone function as returning this object
1717-
* rather than base */
1718-
MacroInvocationSemi *clone_trait_item_impl () const final override
1719-
{
1720-
return clone_macro_invocation_semi_impl ();
1721-
}
1722-
1723-
/* Use covariance to implement clone function as returning this object
1724-
* rather than base */
1725-
MacroInvocationSemi *clone_external_item_impl () const final override
1726-
{
1727-
return clone_macro_invocation_semi_impl ();
1728-
}
1729-
};
1730-
17311637
// A crate AST object - holds all the data for a single compilation unit
17321638
struct Crate
17331639
{

gcc/rust/ast/rust-item.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ namespace AST {
2828
// forward decls
2929
class BlockExpr;
3030
class TypePath;
31-
class MacroInvocationSemi;
3231

3332
// TODO: inline?
3433
/*struct AbiName {
@@ -4306,7 +4305,6 @@ class ExternBlock : public VisItem
43064305

43074306
// Replaced with forward decls - defined in "rust-macro.h"
43084307
class MacroItem;
4309-
class MacroInvocationSemi;
43104308
class MacroRulesDefinition;
43114309
} // namespace AST
43124310
} // namespace Rust

gcc/rust/ast/rust-macro.h

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ namespace AST {
2727

2828
// Decls as definitions moved to rust-ast.h
2929
class MacroItem;
30-
class MacroInvocationSemi;
3130

3231
enum MacroFragSpec
3332
{
@@ -454,6 +453,10 @@ class MacroRulesDefinition : public MacroItem
454453
* compile time */
455454
class MacroInvocation : public TypeNoBounds,
456455
public Pattern,
456+
public MacroItem,
457+
public TraitItem,
458+
public TraitImplItem,
459+
public InherentImplItem,
457460
public ExprWithoutBlock
458461
{
459462
std::vector<Attribute> outer_attrs;
@@ -463,14 +466,18 @@ class MacroInvocation : public TypeNoBounds,
463466
// this is the expanded macro
464467
ASTFragment fragment;
465468

469+
// Important for when we actually expand the macro
470+
bool is_semi_coloned;
471+
466472
public:
467473
std::string as_string () const override;
468474

469475
MacroInvocation (MacroInvocData invoc_data,
470-
std::vector<Attribute> outer_attrs, Location locus)
476+
std::vector<Attribute> outer_attrs, Location locus,
477+
bool is_semi_coloned = false)
471478
: outer_attrs (std::move (outer_attrs)),
472479
invoc_data (std::move (invoc_data)), locus (locus),
473-
fragment (ASTFragment::create_empty ())
480+
fragment (ASTFragment::create_empty ()), is_semi_coloned (is_semi_coloned)
474481
{}
475482

476483
Location get_locus () const override final { return locus; }
@@ -503,6 +510,8 @@ class MacroInvocation : public TypeNoBounds,
503510

504511
void set_fragment (ASTFragment &&f) { fragment = std::move (f); }
505512

513+
bool has_semicolon () const { return is_semi_coloned; }
514+
506515
protected:
507516
/* Use covariance to implement clone function as returning this object rather
508517
* than base */
@@ -529,6 +538,40 @@ class MacroInvocation : public TypeNoBounds,
529538
{
530539
return new MacroInvocation (*this);
531540
}
541+
542+
Item *clone_item_impl () const override
543+
{
544+
return clone_macro_invocation_impl ();
545+
}
546+
547+
bool is_item () const override { return !has_semicolon (); }
548+
549+
TraitItem *clone_trait_item_impl () const override
550+
{
551+
return clone_macro_invocation_impl ();
552+
};
553+
554+
TraitImplItem *clone_trait_impl_item_impl () const override
555+
{
556+
return clone_macro_invocation_impl ();
557+
};
558+
559+
InherentImplItem *clone_inherent_impl_item_impl () const override
560+
{
561+
return clone_macro_invocation_impl ();
562+
}
563+
564+
ExprWithoutBlock *to_stmt () const override
565+
566+
567+
568+
569+
{
570+
auto new_impl = clone_macro_invocation_impl();
571+
new_impl->is_semi_coloned = true;
572+
573+
return new_impl;
574+
}
532575
};
533576

534577
// more generic meta item path-only form

gcc/rust/ast/rust-stmt.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,9 @@ class ExprStmtWithoutBlock : public ExprStmt
211211
std::string as_string () const override;
212212

213213
ExprStmtWithoutBlock (std::unique_ptr<ExprWithoutBlock> expr, Location locus)
214-
: ExprStmt (locus), expr (std::move (expr))
214+
: ExprStmt (locus), expr (std::move (expr->to_stmt ()))
215215
{}
216+
216217
/*ExprStmtWithoutBlock (std::unique_ptr<Expr> expr, Location locus)
217218
: ExprStmt (locus), expr (std::move (expr))
218219
{}*/
@@ -336,9 +337,6 @@ class ExprStmtWithBlock : public ExprStmt
336337
}
337338
};
338339

339-
/* Replaced definition of MacroInvocationSemi with forward decl - defined in
340-
* rust-macro.h */
341-
class MacroInvocationSemi;
342340
} // namespace AST
343341
} // namespace Rust
344342

0 commit comments

Comments
 (0)