Skip to content

Commit e2bccf4

Browse files
Merge #985
985: Parse macro!(); as MacroInvocation with semicolon r=CohenArthur a=CohenArthur 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. Closes #941 Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
2 parents d89c8cc + 58d1721 commit e2bccf4

20 files changed

+154
-200
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: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,18 +1275,6 @@ 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-
}
1289-
12901278
std::string
12911279
ExternBlock::as_string () const
12921280
{
@@ -1377,6 +1365,9 @@ MacroInvocation::as_string () const
13771365

13781366
str += "\n " + invoc_data.as_string ();
13791367

1368+
str += "\n has semicolon: ";
1369+
str += has_semicolon () ? "true" : "false";
1370+
13801371
return str;
13811372
}
13821373

@@ -4921,12 +4912,6 @@ LifetimeParam::accept_vis (ASTVisitor &vis)
49214912
vis.visit (*this);
49224913
}
49234914

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

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: 49 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,22 @@ 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+
472+
NodeId node_id;
473+
466474
public:
467475
std::string as_string () const override;
468476

469477
MacroInvocation (MacroInvocData invoc_data,
470-
std::vector<Attribute> outer_attrs, Location locus)
478+
std::vector<Attribute> outer_attrs, Location locus,
479+
bool is_semi_coloned = false)
471480
: outer_attrs (std::move (outer_attrs)),
472481
invoc_data (std::move (invoc_data)), locus (locus),
473-
fragment (ASTFragment::create_empty ())
482+
fragment (ASTFragment::create_empty ()),
483+
is_semi_coloned (is_semi_coloned),
484+
node_id (Analysis::Mappings::get ()->get_next_node_id ())
474485
{}
475486

476487
Location get_locus () const override final { return locus; }
@@ -497,12 +508,16 @@ class MacroInvocation : public TypeNoBounds,
497508
return ExprWithoutBlock::get_node_id ();
498509
}
499510

511+
NodeId get_macro_node_id () const { return node_id; }
512+
500513
MacroInvocData &get_invoc_data () { return invoc_data; }
501514

502515
ASTFragment &get_fragment () { return fragment; }
503516

504517
void set_fragment (ASTFragment &&f) { fragment = std::move (f); }
505518

519+
bool has_semicolon () const { return is_semi_coloned; }
520+
506521
protected:
507522
/* Use covariance to implement clone function as returning this object rather
508523
* than base */
@@ -529,6 +544,37 @@ class MacroInvocation : public TypeNoBounds,
529544
{
530545
return new MacroInvocation (*this);
531546
}
547+
548+
Item *clone_item_impl () const override
549+
{
550+
return clone_macro_invocation_impl ();
551+
}
552+
553+
bool is_item () const override { return !has_semicolon (); }
554+
555+
TraitItem *clone_trait_item_impl () const override
556+
{
557+
return clone_macro_invocation_impl ();
558+
};
559+
560+
TraitImplItem *clone_trait_impl_item_impl () const override
561+
{
562+
return clone_macro_invocation_impl ();
563+
};
564+
565+
InherentImplItem *clone_inherent_impl_item_impl () const override
566+
{
567+
return clone_macro_invocation_impl ();
568+
}
569+
570+
ExprWithoutBlock *to_stmt () const override
571+
572+
{
573+
auto new_impl = clone_macro_invocation_impl ();
574+
new_impl->is_semi_coloned = true;
575+
576+
return new_impl;
577+
}
532578
};
533579

534580
// 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

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

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ class AttrVisitor : public AST::ASTVisitor
310310
{
311311
// supposedly does not require - cfg does nothing
312312
}
313-
void visit (AST::MacroInvocationSemi &macro_invoc) override
313+
314+
void visit (AST::MacroInvocation &macro_invoc) override
314315
{
315316
// initial strip test based on outer attrs
316317
expander.expand_cfg_attrs (macro_invoc.get_outer_attrs ());
@@ -326,9 +327,13 @@ class AttrVisitor : public AST::ASTVisitor
326327

327328
// TODO: maybe have cfg! macro stripping behaviour here?
328329

329-
expander.expand_invoc_semi (macro_invoc);
330+
if (macro_invoc.has_semicolon ())
331+
expander.expand_invoc_semi (macro_invoc);
332+
else
333+
expander.expand_invoc (macro_invoc);
330334

331-
// we need to visit the expanded fragments since it may need cfg expansion
335+
// we need to visit the expanded fragments since it may need cfg
336+
// expansion
332337
// and it may be recursive
333338
for (auto &node : macro_invoc.get_fragment ().get_nodes ())
334339
node.accept_vis (*this);
@@ -2534,28 +2539,6 @@ class AttrVisitor : public AST::ASTVisitor
25342539
expander.mappings->insert_macro_def (&rules_def);
25352540
}
25362541

2537-
void visit (AST::MacroInvocation &macro_invoc) override
2538-
{
2539-
// FIXME
2540-
// we probably need another recurision check here
2541-
2542-
// initial strip test based on outer attrs
2543-
expander.expand_cfg_attrs (macro_invoc.get_outer_attrs ());
2544-
if (expander.fails_cfg_with_expand (macro_invoc.get_outer_attrs ()))
2545-
{
2546-
macro_invoc.mark_for_strip ();
2547-
return;
2548-
}
2549-
2550-
// I don't think any macro token trees can be stripped in any way
2551-
expander.expand_invoc (macro_invoc);
2552-
2553-
// we need to visit the expanded fragments since it may need cfg expansion
2554-
// and it may be recursive
2555-
for (auto &node : macro_invoc.get_fragment ().get_nodes ())
2556-
node.accept_vis (*this);
2557-
}
2558-
25592542
void visit (AST::MetaItemPath &) override {}
25602543
void visit (AST::MetaItemSeq &) override {}
25612544
void visit (AST::MetaWord &) override {}
@@ -3209,7 +3192,7 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc)
32093192
}
32103193

32113194
void
3212-
MacroExpander::expand_invoc_semi (AST::MacroInvocationSemi &invoc)
3195+
MacroExpander::expand_invoc_semi (AST::MacroInvocation &invoc)
32133196
{
32143197
if (depth_exceeds_recursion_limit ())
32153198
{

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,11 @@ struct MacroExpander
146146
// Expands all macros in the crate passed in.
147147
void expand_crate ();
148148

149-
/* Expands a macro invocation (not macro invocation semi) - possibly make both
149+
/* Expands a macro invocation - possibly make both
150150
* have similar duck-typed interface and use templates?*/
151151
// should this be public or private?
152152
void expand_invoc (AST::MacroInvocation &invoc);
153-
void expand_invoc_semi (AST::MacroInvocationSemi &invoc);
153+
void expand_invoc_semi (AST::MacroInvocation &invoc);
154154

155155
// Expands a single declarative macro.
156156
AST::ASTFragment expand_decl_macro (Location locus,

0 commit comments

Comments
 (0)