diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/ast/rust-ast.h | 170 | ||||
-rw-r--r-- | gcc/rust/ast/rust-macro.h | 129 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.cc | 127 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.h | 25 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-implitem.h | 20 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-item.h | 10 | ||||
-rw-r--r-- | gcc/rust/hir/rust-ast-lower-stmt.h | 10 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse-impl.h | 20 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-expr.h | 7 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-implitem.h | 21 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-item.h | 14 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-stmt.h | 8 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-toplevel.h | 7 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tycheck-dump.h | 6 | ||||
-rw-r--r-- | 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 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>> ¯o, 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 +} |