From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id 22A09381F721; Wed, 8 Jun 2022 12:08:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 22A09381F721 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Thomas Schwinge To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] Semicolon based macro invocation X-Act-Checkin: gcc X-Git-Author: Philip Herron X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: 4c70d7ec770d226bf9ad59b4f03897f6fb10df15 X-Git-Newrev: 37415eec77438bba2fc61df3e9a396c1e2cbaca8 Message-Id: <20220608120800.22A09381F721@sourceware.org> Date: Wed, 8 Jun 2022 12:08:00 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Jun 2022 12:08:00 -0000 https://gcc.gnu.org/g:37415eec77438bba2fc61df3e9a396c1e2cbaca8 commit 37415eec77438bba2fc61df3e9a396c1e2cbaca8 Author: Philip Herron Date: Thu Feb 17 15:26:35 2022 +0000 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. Diff: --- gcc/rust/ast/rust-ast.h | 170 +++++++++++++++++++++++++- gcc/rust/ast/rust-macro.h | 129 ------------------- gcc/rust/expand/rust-macro-expand.cc | 127 ++++++++++++++++--- gcc/rust/expand/rust-macro-expand.h | 25 +++- gcc/rust/hir/rust-ast-lower-implitem.h | 20 +++ gcc/rust/hir/rust-ast-lower-item.h | 10 ++ gcc/rust/hir/rust-ast-lower-stmt.h | 10 ++ gcc/rust/parse/rust-parse-impl.h | 20 +++ gcc/rust/resolve/rust-ast-resolve-expr.h | 7 +- gcc/rust/resolve/rust-ast-resolve-implitem.h | 21 ++++ gcc/rust/resolve/rust-ast-resolve-item.h | 14 +++ gcc/rust/resolve/rust-ast-resolve-stmt.h | 8 ++ gcc/rust/resolve/rust-ast-resolve-toplevel.h | 7 ++ gcc/rust/typecheck/rust-tycheck-dump.h | 6 + gcc/testsuite/rust/execute/torture/macros6.rs | 12 ++ 15 files changed, 430 insertions(+), 156 deletions(-) diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 3e7faf55386..e72937e5d70 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) + : type (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr) + {} + + SingleASTNode (std::unique_ptr item) + : type (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr) + {} + + SingleASTNode (std::unique_ptr 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 &get_expr () + { + rust_assert (type == EXPRESSION); + return expr; + } + + std::unique_ptr &get_item () + { + rust_assert (type == ITEM); + return item; + } + + std::unique_ptr &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; + std::unique_ptr item; + std::unique_ptr 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 nodes; + +public: + ASTFragment (std::vector 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 &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 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 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 1e95ebe14e3..b5370d853fc 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) - : type (EXPRESSION), expr (std::move (expr)), item (nullptr) - {} - - SingleASTNode (std::unique_ptr 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 &get_expr () - { - rust_assert (type == EXPRESSION); - return expr; - } - - std::unique_ptr &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; - std::unique_ptr 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 nodes; - -public: - ASTFragment (std::vector 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 &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 bce524611cb..dcfec7ceeb7 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 &parser, AST::ASTFragment MacroExpander::transcribe_rule ( AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree, - std::map &matched_fragments) + std::map &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> 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 parser (std::move (lex)); // this is used so we can check that we delimit the stream correctly. - std::vector 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 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 0f13f9e566b..d8a2d5003e6 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 &matched_fragments); + std::map &matched_fragments, + bool semicolon, ContextType ctx); bool match_fragment (Parser &parser, AST::MacroMatchFragment &fragment); @@ -189,10 +198,22 @@ struct MacroExpander std::vector> ¯o, std::map &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 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 c9dfd1b6505..3d10b70bc17 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 > 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 d4b591090c0..30bd896a797 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 ede72bd71bf..b25246a43aa 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 2ea42c74663..784e6d1efd2 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -1571,6 +1571,9 @@ Parser::parse_macro_invocation_semi ( // parse actual token trees std::vector> token_trees; + auto delim_open + = std::unique_ptr (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::parse_macro_invocation_semi ( t = lexer.peek_token (); } + auto delim_close + = std::unique_ptr (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::parse_macro_invocation_semi ( if (!skip_token (SEMICOLON)) { // as this is the end, allow recovery (probably) - may change + return std::unique_ptr ( new AST::MacroInvocationSemi (std::move (invoc_data), std::move (outer_attrs), @@ -11761,6 +11768,9 @@ Parser::parse_path_based_stmt_or_expr ( // parse actual token trees std::vector> token_trees; + auto delim_open + = std::unique_ptr (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::parse_path_based_stmt_or_expr ( t3 = lexer.peek_token (); } + auto delim_close + = std::unique_ptr (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::parse_macro_invocation_maybe_semi ( // parse actual token trees std::vector> token_trees; + auto delim_open + = std::unique_ptr (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::parse_macro_invocation_maybe_semi ( t3 = lexer.peek_token (); } + auto delim_close + = std::unique_ptr (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 4ccb72bd4a8..bb1cbb04794 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 f17b2226a40..ce7234ca1a1 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 5d32c0022d0..48f93e53487 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 3afed532afa..7521739b884 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 7aba67fe7e7..39d6818427a 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 0bcc6c81064..53daa42dadf 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 00000000000..652a765d5a8 --- /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 +}