aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2022-02-17 15:26:35 +0000
committerPhilip Herron <philip.herron@embecosm.com>2022-02-17 16:41:15 +0000
commit37415eec77438bba2fc61df3e9a396c1e2cbaca8 (patch)
treed8ed1ea0d957afd906556ae89e8622f79c4690f1 /gcc
parent4c70d7ec770d226bf9ad59b4f03897f6fb10df15 (diff)
downloadgcc-37415eec77438bba2fc61df3e9a396c1e2cbaca8.zip
gcc-37415eec77438bba2fc61df3e9a396c1e2cbaca8.tar.gz
gcc-37415eec77438bba2fc61df3e9a396c1e2cbaca8.tar.bz2
Semicolon based macro invocation
This allows for macro invocation at the toplevel or as statements. This patched required us to propogate the delimited token tree fix to include the delimiter tokens. The rest of the fix was straight forward to call the apropriate visitors in names resolution and hir lowering. Some thought will be needed to handle hir lowering for repeating items.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/ast/rust-ast.h170
-rw-r--r--gcc/rust/ast/rust-macro.h129
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc127
-rw-r--r--gcc/rust/expand/rust-macro-expand.h25
-rw-r--r--gcc/rust/hir/rust-ast-lower-implitem.h20
-rw-r--r--gcc/rust/hir/rust-ast-lower-item.h10
-rw-r--r--gcc/rust/hir/rust-ast-lower-stmt.h10
-rw-r--r--gcc/rust/parse/rust-parse-impl.h20
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h7
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-implitem.h21
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.h14
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-stmt.h8
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-toplevel.h7
-rw-r--r--gcc/rust/typecheck/rust-tycheck-dump.h6
-rw-r--r--gcc/testsuite/rust/execute/torture/macros6.rs12
15 files changed, 430 insertions, 156 deletions
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index 3e7faf5..e72937e 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -1475,6 +1475,160 @@ public:
}
};
+class SingleASTNode
+{
+public:
+ enum NodeType
+ {
+ EXPRESSION,
+ ITEM,
+ STMT,
+ };
+
+ SingleASTNode (std::unique_ptr<Expr> expr)
+ : type (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr)
+ {}
+
+ SingleASTNode (std::unique_ptr<Item> item)
+ : type (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr)
+ {}
+
+ SingleASTNode (std::unique_ptr<Stmt> stmt)
+ : type (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt))
+ {}
+
+ SingleASTNode (SingleASTNode const &other)
+ {
+ type = other.type;
+ switch (type)
+ {
+ case EXPRESSION:
+ expr = other.expr->clone_expr ();
+ break;
+
+ case ITEM:
+ item = other.item->clone_item ();
+ break;
+
+ case STMT:
+ stmt = other.stmt->clone_stmt ();
+ break;
+ }
+ }
+
+ SingleASTNode operator= (SingleASTNode const &other)
+ {
+ type = other.type;
+ switch (type)
+ {
+ case EXPRESSION:
+ expr = other.expr->clone_expr ();
+ break;
+
+ case ITEM:
+ item = other.item->clone_item ();
+ break;
+
+ case STMT:
+ stmt = other.stmt->clone_stmt ();
+ break;
+ }
+ return *this;
+ }
+
+ SingleASTNode (SingleASTNode &&other) = default;
+ SingleASTNode &operator= (SingleASTNode &&other) = default;
+
+ std::unique_ptr<Expr> &get_expr ()
+ {
+ rust_assert (type == EXPRESSION);
+ return expr;
+ }
+
+ std::unique_ptr<Item> &get_item ()
+ {
+ rust_assert (type == ITEM);
+ return item;
+ }
+
+ std::unique_ptr<Stmt> &get_stmt ()
+ {
+ rust_assert (type == STMT);
+ return stmt;
+ }
+
+ void accept_vis (ASTVisitor &vis)
+ {
+ switch (type)
+ {
+ case EXPRESSION:
+ expr->accept_vis (vis);
+ break;
+
+ case ITEM:
+ item->accept_vis (vis);
+ break;
+
+ case STMT:
+ stmt->accept_vis (vis);
+ break;
+ }
+ }
+
+private:
+ NodeType type;
+
+ // FIXME make this a union
+ std::unique_ptr<Expr> expr;
+ std::unique_ptr<Item> item;
+ std::unique_ptr<Stmt> stmt;
+};
+
+/* Basically, a "fragment" that can be incorporated into the AST, created as
+ * a result of macro expansion. Really annoying to work with due to the fact
+ * that macros can really expand to anything. As such, horrible representation
+ * at the moment. */
+class ASTFragment
+{
+private:
+ /* basic idea: essentially, a vector of tagged unions of different AST node
+ * types. Now, this could actually be stored without a tagged union if the
+ * different AST node types had a unified parent, but that would create
+ * issues with the diamond problem or significant performance penalties. So
+ * a tagged union had to be used instead. A vector is used to represent the
+ * ability for a macro to expand to two statements, for instance. */
+
+ std::vector<SingleASTNode> nodes;
+
+public:
+ ASTFragment (std::vector<SingleASTNode> nodes) : nodes (std::move (nodes)) {}
+
+ ASTFragment (ASTFragment const &other)
+ {
+ nodes.clear ();
+ nodes.reserve (other.nodes.size ());
+ for (auto &n : other.nodes)
+ {
+ nodes.push_back (n);
+ }
+ }
+
+ ASTFragment &operator= (ASTFragment const &other)
+ {
+ nodes.clear ();
+ nodes.reserve (other.nodes.size ());
+ for (auto &n : other.nodes)
+ {
+ nodes.push_back (n);
+ }
+ return *this;
+ }
+
+ static ASTFragment create_empty () { return ASTFragment ({}); }
+
+ std::vector<SingleASTNode> &get_nodes () { return nodes; }
+};
+
/* A macro invocation item (or statement) AST node (i.e. semi-coloned macro
* invocation) */
class MacroInvocationSemi : public MacroItem,
@@ -1486,6 +1640,10 @@ class MacroInvocationSemi : public MacroItem,
std::vector<Attribute> outer_attrs;
MacroInvocData invoc_data;
Location locus;
+ NodeId node_id;
+
+ // this is the expanded macro
+ ASTFragment fragment;
public:
std::string as_string () const override;
@@ -1493,7 +1651,9 @@ public:
MacroInvocationSemi (MacroInvocData invoc_data,
std::vector<Attribute> outer_attrs, Location locus)
: outer_attrs (std::move (outer_attrs)),
- invoc_data (std::move (invoc_data)), locus (locus)
+ invoc_data (std::move (invoc_data)), locus (locus),
+ node_id (Analysis::Mappings::get ()->get_next_node_id ()),
+ fragment (ASTFragment::create_empty ())
{}
void accept_vis (ASTVisitor &vis) override;
@@ -1517,6 +1677,14 @@ public:
Location get_locus () const override final { return locus; }
+ MacroInvocData &get_invoc_data () { return invoc_data; }
+
+ ASTFragment &get_fragment () { return fragment; }
+
+ void set_fragment (ASTFragment &&f) { fragment = std::move (f); }
+
+ NodeId get_macro_node_id () const { return node_id; }
+
protected:
MacroInvocationSemi *clone_macro_invocation_semi_impl () const
{
diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h
index 1e95ebe..b5370d8 100644
--- a/gcc/rust/ast/rust-macro.h
+++ b/gcc/rust/ast/rust-macro.h
@@ -84,135 +84,6 @@ get_frag_spec_from_str (std::string str)
}
}
-class SingleASTNode
-{
-public:
- enum NodeType
- {
- EXPRESSION,
- ITEM,
- };
-
- SingleASTNode (std::unique_ptr<Expr> expr)
- : type (EXPRESSION), expr (std::move (expr)), item (nullptr)
- {}
-
- SingleASTNode (std::unique_ptr<Item> item)
- : type (ITEM), expr (nullptr), item (std::move (item))
- {}
-
- SingleASTNode (SingleASTNode const &other)
- {
- type = other.type;
- switch (type)
- {
- case EXPRESSION:
- expr = other.expr->clone_expr ();
- break;
-
- case ITEM:
- item = other.item->clone_item ();
- break;
- }
- }
-
- SingleASTNode operator= (SingleASTNode const &other)
- {
- type = other.type;
- switch (type)
- {
- case EXPRESSION:
- expr = other.expr->clone_expr ();
- break;
-
- case ITEM:
- item = other.item->clone_item ();
- break;
- }
- return *this;
- }
-
- SingleASTNode (SingleASTNode &&other) = default;
- SingleASTNode &operator= (SingleASTNode &&other) = default;
-
- std::unique_ptr<Expr> &get_expr ()
- {
- rust_assert (type == EXPRESSION);
- return expr;
- }
-
- std::unique_ptr<Item> &get_item ()
- {
- rust_assert (type == ITEM);
- return item;
- }
-
- void accept_vis (ASTVisitor &vis)
- {
- switch (type)
- {
- case EXPRESSION:
- expr->accept_vis (vis);
- break;
-
- case ITEM:
- item->accept_vis (vis);
- break;
- }
- }
-
-private:
- NodeType type;
- std::unique_ptr<Expr> expr;
- std::unique_ptr<Item> item;
- // TODO add meta attribute
-};
-
-/* Basically, a "fragment" that can be incorporated into the AST, created as
- * a result of macro expansion. Really annoying to work with due to the fact
- * that macros can really expand to anything. As such, horrible representation
- * at the moment. */
-class ASTFragment
-{
-private:
- /* basic idea: essentially, a vector of tagged unions of different AST node
- * types. Now, this could actually be stored without a tagged union if the
- * different AST node types had a unified parent, but that would create
- * issues with the diamond problem or significant performance penalties. So
- * a tagged union had to be used instead. A vector is used to represent the
- * ability for a macro to expand to two statements, for instance. */
-
- std::vector<SingleASTNode> nodes;
-
-public:
- ASTFragment (std::vector<SingleASTNode> nodes) : nodes (std::move (nodes)) {}
-
- ASTFragment (ASTFragment const &other)
- {
- nodes.clear ();
- nodes.reserve (other.nodes.size ());
- for (auto &n : other.nodes)
- {
- nodes.push_back (n);
- }
- }
-
- ASTFragment &operator= (ASTFragment const &other)
- {
- nodes.clear ();
- nodes.reserve (other.nodes.size ());
- for (auto &n : other.nodes)
- {
- nodes.push_back (n);
- }
- return *this;
- }
-
- static ASTFragment create_empty () { return ASTFragment ({}); }
-
- std::vector<SingleASTNode> &get_nodes () { return nodes; }
-};
-
// A macro match that has an identifier and fragment spec
class MacroMatchFragment : public MacroMatch
{
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index bce5246..dcfec7c 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -324,6 +324,13 @@ public:
// I don't think any macro token trees can be stripped in any way
// TODO: maybe have cfg! macro stripping behaviour here?
+
+ expander.expand_invoc_semi (macro_invoc);
+
+ // we need to visit the expanded fragments since it may need cfg expansion
+ // and it may be recursive
+ for (auto &node : macro_invoc.get_fragment ().get_nodes ())
+ node.accept_vis (*this);
}
void visit (AST::PathInExpression &path) override
@@ -1034,13 +1041,17 @@ public:
"cannot strip expression in this position - outer "
"attributes not allowed");
}
+
void visit (AST::BlockExpr &expr) override
{
+ expander.push_context (MacroExpander::BLOCK);
+
// initial strip test based on outer attrs
expander.expand_cfg_attrs (expr.get_outer_attrs ());
if (expander.fails_cfg_with_expand (expr.get_outer_attrs ()))
{
expr.mark_for_strip ();
+ expander.pop_context ();
return;
}
@@ -1050,6 +1061,7 @@ public:
if (expander.fails_cfg_with_expand (expr.get_inner_attrs ()))
{
expr.mark_for_strip ();
+ expander.pop_context ();
return;
}
@@ -1066,7 +1078,9 @@ public:
if (tail_expr->is_marked_for_strip ())
expr.strip_tail_expr ();
}
+ expander.pop_context ();
}
+
void visit (AST::ClosureExprInnerTyped &expr) override
{
// initial strip test based on outer attrs
@@ -2533,7 +2547,6 @@ public:
}
// I don't think any macro token trees can be stripped in any way
-
expander.expand_invoc (macro_invoc);
// we need to visit the expanded fragments since it may need cfg expansion
@@ -3059,7 +3072,8 @@ MacroExpander::expand_cfg_macro (AST::MacroInvocData &invoc)
AST::ASTFragment
MacroExpander::expand_decl_macro (Location invoc_locus,
AST::MacroInvocData &invoc,
- AST::MacroRulesDefinition &rules_def)
+ AST::MacroRulesDefinition &rules_def,
+ bool semicolon)
{
// ensure that both invocation and rules are in a valid state
rust_assert (!invoc.is_marked_for_strip ());
@@ -3126,7 +3140,8 @@ MacroExpander::expand_decl_macro (Location invoc_locus,
return AST::ASTFragment::create_empty ();
}
- return transcribe_rule (*matched_rule, invoc_token_tree, matched_fragments);
+ return transcribe_rule (*matched_rule, invoc_token_tree, matched_fragments,
+ semicolon, peek_context ());
}
void
@@ -3176,7 +3191,42 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc)
rust_assert (ok);
auto fragment
- = expand_decl_macro (invoc.get_locus (), invoc_data, *rules_def);
+ = expand_decl_macro (invoc.get_locus (), invoc_data, *rules_def, false);
+
+ // lets attach this fragment to the invocation
+ invoc.set_fragment (std::move (fragment));
+}
+
+void
+MacroExpander::expand_invoc_semi (AST::MacroInvocationSemi &invoc)
+{
+ if (depth_exceeds_recursion_limit ())
+ {
+ rust_error_at (invoc.get_locus (), "reached recursion limit");
+ return;
+ }
+
+ AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
+
+ // lookup the rules for this macro
+ NodeId resolved_node = UNKNOWN_NODEID;
+ bool found = resolver->get_macro_scope ().lookup (
+ Resolver::CanonicalPath::new_seg (invoc.get_macro_node_id (),
+ invoc_data.get_path ().as_string ()),
+ &resolved_node);
+ if (!found)
+ {
+ rust_error_at (invoc.get_locus (), "unknown macro");
+ return;
+ }
+
+ // lookup the rules
+ AST::MacroRulesDefinition *rules_def = nullptr;
+ bool ok = mappings->lookup_macro_def (resolved_node, &rules_def);
+ rust_assert (ok);
+
+ auto fragment
+ = expand_decl_macro (invoc.get_locus (), invoc_data, *rules_def, true);
// lets attach this fragment to the invocation
invoc.set_fragment (std::move (fragment));
@@ -3301,6 +3351,8 @@ MacroExpander::expand_crate ()
}
// expand module attributes?
+ push_context (ITEM);
+
// expand attributes recursively and strip items if required
AttrVisitor attr_visitor (*this);
auto &items = crate.items;
@@ -3317,6 +3369,8 @@ MacroExpander::expand_crate ()
++it;
}
+ pop_context ();
+
// TODO: should recursive attribute and macro expansion be done in the same
// transversal? Or in separate ones like currently?
@@ -3555,7 +3609,8 @@ MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser,
AST::ASTFragment
MacroExpander::transcribe_rule (
AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
- std::map<std::string, MatchedFragment> &matched_fragments)
+ std::map<std::string, MatchedFragment> &matched_fragments, bool semicolon,
+ ContextType ctx)
{
// we can manipulate the token tree to substitute the dollar identifiers so
// that when we call parse its already substituted for us
@@ -3568,7 +3623,7 @@ MacroExpander::transcribe_rule (
std::vector<std::unique_ptr<AST::Token>> substituted_tokens
= substitute_tokens (invoc_stream, macro_rule_tokens, matched_fragments);
- // handy for debugging
+ // // handy for debugging
// for (auto &tok : substituted_tokens)
// {
// rust_debug ("tok: [%s]", tok->as_string ().c_str ());
@@ -3579,7 +3634,6 @@ MacroExpander::transcribe_rule (
Parser<MacroInvocLexer> parser (std::move (lex));
// this is used so we can check that we delimit the stream correctly.
- std::vector<AST::SingleASTNode> nodes;
switch (transcribe_tree.get_delim_type ())
{
case AST::DelimType::PARENS:
@@ -3595,26 +3649,61 @@ MacroExpander::transcribe_rule (
break;
}
+ // see https://github.com/Rust-GCC/gccrs/issues/22
+ // TL;DR:
+ // - Treat all macro invocations with parentheses, (), or square brackets,
+ // [], as expressions.
+ // - If the macro invocation has curly brackets, {}, it may be parsed as a
+ // statement depending on the context.
+ // - If the macro invocation has a semicolon at the end, it must be parsed
+ // as a statement (either via ExpressionStatement or
+ // MacroInvocationWithSemi)
+
// parse the item
+ std::vector<AST::SingleASTNode> nodes;
switch (invoc_token_tree.get_delim_type ())
{
- case AST::DelimType::PARENS: {
- auto expr = parser.parse_expr ();
- if (expr != nullptr && !parser.has_errors ())
- nodes.push_back (std::move (expr));
+ case AST::DelimType::PARENS:
+ case AST::DelimType::SQUARE: {
+ switch (ctx)
+ {
+ case ContextType::ITEM: {
+ auto item = parser.parse_item (true);
+ if (item != nullptr && !parser.has_errors ())
+ {
+ rust_debug ("HELLO WORLD: [%s]", item->as_string ().c_str ());
+ nodes.push_back (std::move (item));
+ }
+ }
+ break;
+
+ case ContextType::BLOCK: {
+ auto expr = parser.parse_expr ();
+ if (expr != nullptr && !parser.has_errors ())
+ nodes.push_back (std::move (expr));
+ }
+ break;
+ }
}
break;
case AST::DelimType::CURLY: {
- auto item = parser.parse_item (false);
- if (item != nullptr && !parser.has_errors ())
- nodes.push_back (std::move (item));
- }
- break;
+ switch (ctx)
+ {
+ case ContextType::ITEM: {
+ auto item = parser.parse_item (true);
+ if (item != nullptr && !parser.has_errors ())
+ nodes.push_back (std::move (item));
+ }
+ break;
- case AST::DelimType::SQUARE: {
- // FIXME
- gcc_unreachable ();
+ case ContextType::BLOCK: {
+ auto stmt = parser.parse_stmt ();
+ if (stmt != nullptr && !parser.has_errors ())
+ nodes.push_back (std::move (stmt));
+ }
+ break;
+ }
}
break;
}
diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h
index 0f13f9e..d8a2d50 100644
--- a/gcc/rust/expand/rust-macro-expand.h
+++ b/gcc/rust/expand/rust-macro-expand.h
@@ -130,6 +130,12 @@ private:
// Object used to store shared data (between functions) for macro expansion.
struct MacroExpander
{
+ enum ContextType
+ {
+ ITEM,
+ BLOCK,
+ };
+
ExpansionCfg cfg;
unsigned int expansion_depth = 0;
@@ -148,11 +154,13 @@ struct MacroExpander
* have similar duck-typed interface and use templates?*/
// should this be public or private?
void expand_invoc (AST::MacroInvocation &invoc);
+ void expand_invoc_semi (AST::MacroInvocationSemi &invoc);
// Expands a single declarative macro.
AST::ASTFragment expand_decl_macro (Location locus,
AST::MacroInvocData &invoc,
- AST::MacroRulesDefinition &rules_def);
+ AST::MacroRulesDefinition &rules_def,
+ bool semicolon);
void expand_cfg_attrs (AST::AttrVec &attrs);
bool fails_cfg (const AST::AttrVec &attr) const;
@@ -171,7 +179,8 @@ struct MacroExpander
AST::ASTFragment
transcribe_rule (AST::MacroRule &match_rule,
AST::DelimTokenTree &invoc_token_tree,
- std::map<std::string, MatchedFragment> &matched_fragments);
+ std::map<std::string, MatchedFragment> &matched_fragments,
+ bool semicolon, ContextType ctx);
bool match_fragment (Parser<MacroInvocLexer> &parser,
AST::MacroMatchFragment &fragment);
@@ -189,10 +198,22 @@ struct MacroExpander
std::vector<std::unique_ptr<AST::Token>> &macro,
std::map<std::string, MatchedFragment> &fragments);
+ void push_context (ContextType t) { context.push_back (t); }
+
+ ContextType pop_context ()
+ {
+ ContextType t = context.back ();
+ context.pop_back ();
+ return t;
+ }
+
+ ContextType peek_context () { return context.back (); }
+
private:
AST::Crate &crate;
Session &session;
SubstitutionScope sub_stack;
+ std::vector<ContextType> context;
public:
Resolver::Resolver *resolver;
diff --git a/gcc/rust/hir/rust-ast-lower-implitem.h b/gcc/rust/hir/rust-ast-lower-implitem.h
index c9dfd1b..3d10b70 100644
--- a/gcc/rust/hir/rust-ast-lower-implitem.h
+++ b/gcc/rust/hir/rust-ast-lower-implitem.h
@@ -52,6 +52,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::TypeAlias &alias) override
{
std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
@@ -308,6 +318,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::TraitItemFunc &func) override
{
AST::TraitFunctionDecl &ref = func.get_trait_function_decl ();
diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h
index d4b5910..30bd896 100644
--- a/gcc/rust/hir/rust-ast-lower-item.h
+++ b/gcc/rust/hir/rust-ast-lower-item.h
@@ -47,6 +47,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::Module &module) override
{
auto crate_num = mappings->get_current_crate ();
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
index ede72bd..b25246a 100644
--- a/gcc/rust/hir/rust-ast-lower-stmt.h
+++ b/gcc/rust/hir/rust-ast-lower-stmt.h
@@ -45,6 +45,16 @@ public:
return resolver.translated;
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ // FIXME
+ // this assertion might go away, maybe on failure's to expand a macro?
+ rust_assert (!fragment.get_nodes ().empty ());
+ fragment.get_nodes ().at (0).accept_vis (*this);
+ }
+
void visit (AST::ExprStmtWithBlock &stmt) override
{
HIR::ExprWithBlock *expr
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index 2ea42c7..784e6d1 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -1571,6 +1571,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi (
// parse actual token trees
std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
+ auto delim_open
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+ token_trees.push_back (std::move (delim_open));
t = lexer.peek_token ();
// parse token trees until the initial delimiter token is found again
@@ -1593,6 +1596,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi (
t = lexer.peek_token ();
}
+ auto delim_close
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
+ token_trees.push_back (std::move (delim_close));
AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
tok_tree_locus);
@@ -1611,6 +1617,7 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi (
if (!skip_token (SEMICOLON))
{
// as this is the end, allow recovery (probably) - may change
+
return std::unique_ptr<AST::MacroInvocationSemi> (
new AST::MacroInvocationSemi (std::move (invoc_data),
std::move (outer_attrs),
@@ -11761,6 +11768,9 @@ Parser<ManagedTokenSource>::parse_path_based_stmt_or_expr (
// parse actual token trees
std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
+ auto delim_open
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
+ token_trees.push_back (std::move (delim_open));
t3 = lexer.peek_token ();
// parse token trees until the initial delimiter token is found again
@@ -11785,6 +11795,10 @@ Parser<ManagedTokenSource>::parse_path_based_stmt_or_expr (
t3 = lexer.peek_token ();
}
+ auto delim_close
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
+ token_trees.push_back (std::move (delim_close));
+
// parse end delimiters
t3 = lexer.peek_token ();
if (token_id_matches_delims (t3->get_id (), type))
@@ -12076,6 +12090,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_maybe_semi (
// parse actual token trees
std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
+ auto delim_open
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
+ token_trees.push_back (std::move (delim_open));
t3 = lexer.peek_token ();
// parse token trees until the initial delimiter token is found again
@@ -12098,6 +12115,9 @@ Parser<ManagedTokenSource>::parse_macro_invocation_maybe_semi (
t3 = lexer.peek_token ();
}
+ auto delim_close
+ = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
+ token_trees.push_back (std::move (delim_close));
// parse end delimiters
t3 = lexer.peek_token ();
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 4ccb72b..bb1cbb0 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -73,11 +73,8 @@ public:
void visit (AST::MacroInvocation &expr) override
{
AST::ASTFragment &fragment = expr.get_fragment ();
-
- // FIXME
- // this assertion might go away, maybe on failure's to expand a macro?
- rust_assert (!fragment.get_nodes ().empty ());
- fragment.get_nodes ().at (0).accept_vis (*this);
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
}
void visit (AST::TupleIndexExpr &expr) override
diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h
index f17b222..ce7234c 100644
--- a/gcc/rust/resolve/rust-ast-resolve-implitem.h
+++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h
@@ -49,6 +49,13 @@ public:
item->accept_vis (resolver);
}
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TypeAlias &type) override
{
auto decl
@@ -137,6 +144,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TraitItemFunc &function) override
{
auto decl = ResolveTraitItemFunctionToCanonicalPath::resolve (function);
@@ -240,6 +254,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::ExternalFunctionItem &function) override
{
auto decl = CanonicalPath::new_seg (function.get_node_id (),
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 5d32c00..48f93e5 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -45,6 +45,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TraitItemType &type) override
{
auto decl = ResolveTraitItemTypeToCanonicalPath::resolve (type);
@@ -227,6 +234,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::TypeAlias &alias) override
{
auto talias = CanonicalPath::new_seg (alias.get_node_id (),
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index 3afed53..7521739 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -44,6 +44,14 @@ public:
stmt->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::ExprStmtWithBlock &stmt) override
{
ResolveExpr::go (stmt.get_expr ().get (), stmt.get_node_id (), prefix,
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index 7aba67f..39d6818 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -43,6 +43,13 @@ public:
item->accept_vis (resolver);
};
+ void visit (AST::MacroInvocationSemi &invoc) override
+ {
+ AST::ASTFragment &fragment = invoc.get_fragment ();
+ for (auto &node : fragment.get_nodes ())
+ node.accept_vis (*this);
+ }
+
void visit (AST::Module &module) override
{
auto mod
diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h
index 0bcc6c8..53daa42 100644
--- a/gcc/rust/typecheck/rust-tycheck-dump.h
+++ b/gcc/rust/typecheck/rust-tycheck-dump.h
@@ -57,6 +57,12 @@ public:
+= indent () + "union " + type_string (union_decl.get_mappings ()) + "\n";
}
+ void visit (HIR::TupleStruct &struct_decl) override
+ {
+ dump += indent () + "struct" + type_string (struct_decl.get_mappings ())
+ + "\n";
+ }
+
void visit (HIR::ImplBlock &impl_block) override
{
dump += indent () + "impl "
diff --git a/gcc/testsuite/rust/execute/torture/macros6.rs b/gcc/testsuite/rust/execute/torture/macros6.rs
new file mode 100644
index 0000000..652a765
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/macros6.rs
@@ -0,0 +1,12 @@
+macro_rules! Test {
+ ($a:ident, $b:ty) => {
+ struct $a($b);
+ };
+}
+
+Test!(Foo, i32);
+
+fn main() -> i32 {
+ let a = Foo(123);
+ a.0 - 123
+}