From 1a2ef9cae90db5bdb18723b6adafe2750a95ed76 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Mon, 14 Mar 2022 17:08:07 +0100 Subject: [PATCH 1/3] macros: Add remaining context and improve parsing macro dispatch This allows us to expand macor invocations in more places, as macro calls are not limited to statements or expressions. It is quite common to use macros to abstract writing repetitive boilerplate for type implementations, for example. --- gcc/rust/ast/rust-ast.h | 119 +++++++++++++++--- gcc/rust/ast/rust-macro.h | 6 + gcc/rust/expand/rust-attribute-visitor.cc | 52 ++++---- gcc/rust/expand/rust-attribute-visitor.h | 57 ++++++++- gcc/rust/expand/rust-macro-expand.cc | 139 ++++++++++++++++------ gcc/rust/expand/rust-macro-expand.h | 3 + gcc/rust/parse/rust-parse-impl.h | 7 +- gcc/rust/parse/rust-parse.h | 6 +- 8 files changed, 298 insertions(+), 91 deletions(-) diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 3b965346cf6..e33fff2d988 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -1511,18 +1511,45 @@ public: EXPRESSION, ITEM, STMT, + EXTERN, + TRAIT, + IMPL, }; +private: + NodeType kind; + + // FIXME make this a union + std::unique_ptr expr; + std::unique_ptr item; + std::unique_ptr stmt; + std::unique_ptr external_item; + std::unique_ptr trait_item; + std::unique_ptr impl_item; + +public: SingleASTNode (std::unique_ptr expr) - : kind (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr) + : kind (EXPRESSION), expr (std::move (expr)) {} SingleASTNode (std::unique_ptr item) - : kind (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr) + : kind (ITEM), item (std::move (item)) {} SingleASTNode (std::unique_ptr stmt) - : kind (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt)) + : kind (STMT), stmt (std::move (stmt)) + {} + + SingleASTNode (std::unique_ptr item) + : kind (EXTERN), external_item (std::move (item)) + {} + + SingleASTNode (std::unique_ptr item) + : kind (TRAIT), trait_item (std::move (item)) + {} + + SingleASTNode (std::unique_ptr item) + : kind (IMPL), impl_item (std::move (item)) {} SingleASTNode (SingleASTNode const &other) @@ -1541,6 +1568,18 @@ public: case STMT: stmt = other.stmt->clone_stmt (); break; + + case EXTERN: + external_item = other.external_item->clone_external_item (); + break; + + case TRAIT: + trait_item = other.trait_item->clone_trait_item (); + break; + + case IMPL: + impl_item = other.impl_item->clone_inherent_impl_item (); + break; } } @@ -1560,6 +1599,18 @@ public: case STMT: stmt = other.stmt->clone_stmt (); break; + + case EXTERN: + external_item = other.external_item->clone_external_item (); + break; + + case TRAIT: + trait_item = other.trait_item->clone_trait_item (); + break; + + case IMPL: + impl_item = other.impl_item->clone_inherent_impl_item (); + break; } return *this; } @@ -1569,7 +1620,7 @@ public: NodeType get_kind () const { return kind; } - std::unique_ptr &get_inner () + std::unique_ptr &get_expr () { rust_assert (kind == EXPRESSION); return expr; @@ -1610,6 +1661,24 @@ public: return std::move (item); } + std::unique_ptr take_trait_item () + { + rust_assert (!is_error ()); + return std::move (trait_item); + } + + std::unique_ptr take_external_item () + { + rust_assert (!is_error ()); + return std::move (external_item); + } + + std::unique_ptr take_impl_item () + { + rust_assert (!is_error ()); + return std::move (impl_item); + } + void accept_vis (ASTVisitor &vis) { switch (kind) @@ -1625,6 +1694,18 @@ public: case STMT: stmt->accept_vis (vis); break; + + case EXTERN: + external_item->accept_vis (vis); + break; + + case TRAIT: + trait_item->accept_vis (vis); + break; + + case IMPL: + impl_item->accept_vis (vis); + break; } } @@ -1638,9 +1719,16 @@ public: return item == nullptr; case STMT: return stmt == nullptr; - default: - return true; + case EXTERN: + return external_item == nullptr; + case TRAIT: + return trait_item == nullptr; + case IMPL: + return impl_item == nullptr; } + + gcc_unreachable (); + return true; } std::string as_string () @@ -1653,18 +1741,17 @@ public: return "Item: " + item->as_string (); case STMT: return "Stmt: " + stmt->as_string (); - default: - return ""; + case EXTERN: + return "External Item: " + external_item->as_string (); + case TRAIT: + return "Trait Item: " + trait_item->as_string (); + case IMPL: + return "Impl Item: " + impl_item->as_string (); } + + gcc_unreachable (); + return ""; } - -private: - NodeType kind; - - // 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 diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index 1c5d1020b20..5ecd5d72611 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -460,6 +460,7 @@ class MacroInvocation : public TypeNoBounds, public TraitItem, public TraitImplItem, public InherentImplItem, + public ExternalItem, public ExprWithoutBlock { std::vector outer_attrs; @@ -537,6 +538,11 @@ protected: return clone_macro_invocation_impl (); } + MacroInvocation *clone_external_item_impl () const final override + { + return clone_macro_invocation_impl (); + } + /*virtual*/ MacroInvocation *clone_macro_invocation_impl () const { return new MacroInvocation (*this); diff --git a/gcc/rust/expand/rust-attribute-visitor.cc b/gcc/rust/expand/rust-attribute-visitor.cc index 255e9bac9fe..50821edcfae 100644 --- a/gcc/rust/expand/rust-attribute-visitor.cc +++ b/gcc/rust/expand/rust-attribute-visitor.cc @@ -1114,8 +1114,6 @@ AttrVisitor::visit (AST::ClosureExprInner &expr) void AttrVisitor::visit (AST::BlockExpr &expr) { - 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 ())) @@ -1135,31 +1133,13 @@ AttrVisitor::visit (AST::BlockExpr &expr) return; } - // strip all statements - auto &stmts = expr.get_statements (); - for (auto it = stmts.begin (); it != stmts.end ();) - { - auto &stmt = *it; + std::function (AST::SingleASTNode)> extractor + = [] (AST::SingleASTNode node) { return node.take_stmt (); }; - stmt->accept_vis (*this); + expand_macro_children (MacroExpander::BLOCK, expr.get_statements (), + extractor); - auto fragment = expander.take_expanded_fragment (*this); - if (fragment.should_expand ()) - { - // Remove the current expanded invocation - it = stmts.erase (it); - for (auto &node : fragment.get_nodes ()) - { - it = stmts.insert (it, node.take_stmt ()); - it++; - } - } - - else if (stmt->is_marked_for_strip ()) - it = stmts.erase (it); - else - it++; - } + expander.push_context (MacroExpander::BLOCK); // strip tail expression if exists - can actually fully remove it if (expr.has_tail_expr ()) @@ -2489,8 +2469,11 @@ AttrVisitor::visit (AST::Trait &trait) if (trait.has_where_clause ()) expand_where_clause (trait.get_where_clause ()); - // strip trait items if required - expand_pointer_allow_strip (trait.get_trait_items ()); + std::function (AST::SingleASTNode)> extractor + = [] (AST::SingleASTNode node) { return node.take_trait_item (); }; + + expand_macro_children (MacroExpander::TRAIT, trait.get_trait_items (), + extractor); } void AttrVisitor::visit (AST::InherentImpl &impl) @@ -2523,8 +2506,11 @@ AttrVisitor::visit (AST::InherentImpl &impl) if (impl.has_where_clause ()) expand_where_clause (impl.get_where_clause ()); - // strip inherent impl items if required - expand_pointer_allow_strip (impl.get_impl_items ()); + std::function (AST::SingleASTNode)> + extractor = [] (AST::SingleASTNode node) { return node.take_impl_item (); }; + + expand_macro_children (MacroExpander::IMPL, impl.get_impl_items (), + extractor); } void AttrVisitor::visit (AST::TraitImpl &impl) @@ -2659,8 +2645,12 @@ AttrVisitor::visit (AST::ExternBlock &block) return; } - // strip external items if required - expand_pointer_allow_strip (block.get_extern_items ()); + std::function (AST::SingleASTNode)> + extractor + = [] (AST::SingleASTNode node) { return node.take_external_item (); }; + + expand_macro_children (MacroExpander::EXTERN, block.get_extern_items (), + extractor); } // I don't think it would be possible to strip macros without expansion diff --git a/gcc/rust/expand/rust-attribute-visitor.h b/gcc/rust/expand/rust-attribute-visitor.h index f6327d64d46..6da6583030c 100644 --- a/gcc/rust/expand/rust-attribute-visitor.h +++ b/gcc/rust/expand/rust-attribute-visitor.h @@ -40,6 +40,54 @@ public: void expand_trait_function_decl (AST::TraitFunctionDecl &decl); void expand_trait_method_decl (AST::TraitMethodDecl &decl); + /** + * Expand a set of values, erasing them if they are marked for strip, and + * replacing them with expanded macro nodes if necessary. + * This function is slightly different from `expand_pointer_allow_strip` as + * it can only be called in certain expansion contexts - where macro + * invocations are allowed. + * + * @param ctx Context to use for macro expansion + * @param values Iterable reference over values to replace or erase + * @param extractor Function to call when replacing values with the content + * of an expanded AST node + */ + template + void expand_macro_children (MacroExpander::ContextType ctx, T &values, + std::function extractor) + { + expander.push_context (ctx); + + for (auto it = values.begin (); it != values.end ();) + { + auto &value = *it; + + // mark for stripping if required + value->accept_vis (*this); + + auto fragment = expander.take_expanded_fragment (*this); + if (fragment.should_expand ()) + { + it = values.erase (it); + for (auto &node : fragment.get_nodes ()) + { + it = values.insert (it, extractor (node)); + it++; + } + } + else if (value->is_marked_for_strip ()) + { + it = values.erase (it); + } + else + { + ++it; + } + } + + expander.pop_context (); + } + template void expand_pointer_allow_strip (T &values) { for (auto it = values.begin (); it != values.end ();) @@ -48,11 +96,14 @@ public: // mark for stripping if required value->accept_vis (*this); - if (value->is_marked_for_strip ()) - it = values.erase (it); + { + it = values.erase (it); + } else - ++it; + { + ++it; + } } } diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 3389f207850..80f822b3e53 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -786,7 +786,6 @@ parse_many (Parser &parser, TokenId &delimiter, std::function parse_fn) { std::vector nodes; - while (true) { if (parser.peek_current_token ()->get_id () == delimiter) @@ -814,6 +813,52 @@ transcribe_many_items (Parser &parser, TokenId &delimiter) }); } +/** + * Transcribe 0 or more external items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static std::vector +transcribe_many_ext (Parser &parser, TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_external_item (); + return AST::SingleASTNode (std::move (item)); + }); +} + +/** + * Transcribe 0 or more trait items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static std::vector +transcribe_many_trait_items (Parser &parser, + TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_trait_item (); + return AST::SingleASTNode (std::move (item)); + }); +} + +/** + * Transcribe 0 or more impl items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static std::vector +transcribe_many_impl_items (Parser &parser, TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_inherent_impl_item (); + return AST::SingleASTNode (std::move (item)); + }); +} + /** * Transcribe 0 or more statements from a macro invocation * @@ -845,6 +890,57 @@ transcribe_expression (Parser &parser) return {AST::SingleASTNode (std::move (expr))}; } +static std::vector +transcribe_on_delimiter (Parser &parser, bool semicolon, + AST::DelimType delimiter, TokenId last_token_id) +{ + if (semicolon || delimiter == AST::DelimType::CURLY) + return transcribe_many_stmts (parser, last_token_id); + else + return transcribe_expression (parser); +} // namespace Rust + +static std::vector +transcribe_context (MacroExpander::ContextType ctx, + Parser &parser, bool semicolon, + AST::DelimType delimiter, TokenId last_token_id) +{ + // The flow-chart in order to choose a parsing function is as follows: + // + // [switch special context] + // -- Item --> parser.parse_item(); + // -- Trait --> parser.parse_trait_item(); + // -- Impl --> parser.parse_impl_item(); + // -- Extern --> parser.parse_extern_item(); + // -- None --> [has semicolon?] + // -- Yes --> parser.parse_stmt(); + // -- No --> [switch invocation.delimiter()] + // -- { } --> parser.parse_stmt(); + // -- _ --> parser.parse_expr(); // once! + + // If there is a semicolon OR we are expanding a MacroInvocationSemi, then + // we can parse multiple items. Otherwise, parse *one* expression + + switch (ctx) + { + case MacroExpander::ContextType::ITEM: + return transcribe_many_items (parser, last_token_id); + break; + case MacroExpander::ContextType::TRAIT: + return transcribe_many_trait_items (parser, last_token_id); + break; + case MacroExpander::ContextType::IMPL: + return transcribe_many_impl_items (parser, last_token_id); + break; + case MacroExpander::ContextType::EXTERN: + return transcribe_many_ext (parser, last_token_id); + break; + default: + return transcribe_on_delimiter (parser, semicolon, delimiter, + last_token_id); + } +} + AST::ASTFragment MacroExpander::transcribe_rule ( AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree, @@ -864,18 +960,15 @@ MacroExpander::transcribe_rule ( std::vector> substituted_tokens = substitute_context.substitute_tokens (); + // handy for debugging + // for (auto &tok : substituted_tokens) + // rust_debug ("[tok] %s", tok->as_string ().c_str ()); + // parse it to an ASTFragment MacroInvocLexer lex (std::move (substituted_tokens)); Parser parser (std::move (lex)); - // handy for debugging - // for (auto &tok : substituted_tokens) - // { - // rust_debug ("tok: [%s]", tok->as_string ().c_str ()); - // } - auto last_token_id = TokenId::RIGHT_CURLY; - std::vector nodes; // this is used so we can check that we delimit the stream correctly. switch (transcribe_tree.get_delim_type ()) @@ -905,33 +998,9 @@ MacroExpander::transcribe_rule ( // as a statement (either via ExpressionStatement or // MacroInvocationWithSemi) - // The flow-chart in order to choose a parsing function is as follows: - // - // [is in item context?] - // -- Yes --> parser.parse_item(); - // -- No --> [has semicolon?] - // -- Yes --> parser.parse_stmt(); - // -- No --> [switch invocation.delimiter()] - // -- { } --> parser.parse_stmt(); - // -- _ --> parser.parse_expr(); - - // If there is a semicolon OR we are expanding a MacroInvocationSemi, then - // we can parse multiple items. Otherwise, parse *one* expression - - if (ctx == ContextType::ITEM) - nodes = transcribe_many_items (parser, last_token_id); - else if (semicolon) - nodes = transcribe_many_stmts (parser, last_token_id); - else - switch (invoc_token_tree.get_delim_type ()) - { - case AST::CURLY: - nodes = transcribe_many_stmts (parser, last_token_id); - break; - default: - nodes = transcribe_expression (parser); - break; - } + auto nodes + = transcribe_context (ctx, parser, semicolon, + invoc_token_tree.get_delim_type (), last_token_id); // emit any errors if (parser.has_errors ()) diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h index 0d0282e111a..61b69e412a4 100644 --- a/gcc/rust/expand/rust-macro-expand.h +++ b/gcc/rust/expand/rust-macro-expand.h @@ -187,6 +187,9 @@ struct MacroExpander { ITEM, BLOCK, + TRAIT, + IMPL, + EXTERN, }; ExpansionCfg cfg; diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 0bbd8fbf31b..82e7e249531 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -5251,12 +5251,11 @@ Parser::parse_inherent_impl_item () switch (t->get_id ()) { case IDENTIFIER: + // FIXME: Arthur: Do we need to some lookahead here? + return parse_macro_invocation_semi (outer_attrs); case SUPER: case SELF: case CRATE: - case DOLLAR_SIGN: - // these seem to be SimplePath tokens, so this is a macro invocation semi - return parse_macro_invocation_semi (std::move (outer_attrs)); case PUB: { // visibility, so not a macro invocation semi - must be constant, // function, or method @@ -5813,6 +5812,8 @@ Parser::parse_external_item () const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { + case IDENTIFIER: + return parse_macro_invocation_semi (outer_attrs); case STATIC_TOK: { // parse extern static item lexer.skip_token (); diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 5fcb3052156..bb5bf3d7072 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -135,6 +135,9 @@ public: */ std::unique_ptr parse_stmt (bool allow_no_semi = false); std::unique_ptr parse_type (); + std::unique_ptr parse_external_item (); + std::unique_ptr parse_trait_item (); + std::unique_ptr parse_inherent_impl_item (); AST::PathInExpression parse_path_in_expression (); std::vector > parse_lifetime_params (); AST::Visibility parse_visibility (); @@ -285,7 +288,6 @@ private: AST::AttrVec outer_attrs); std::unique_ptr parse_trait (AST::Visibility vis, AST::AttrVec outer_attrs); - std::unique_ptr parse_trait_item (); std::unique_ptr parse_trait_type (AST::AttrVec outer_attrs); std::unique_ptr @@ -293,7 +295,6 @@ private: AST::SelfParam parse_self_param (); std::unique_ptr parse_impl (AST::Visibility vis, AST::AttrVec outer_attrs); - std::unique_ptr parse_inherent_impl_item (); std::unique_ptr parse_inherent_impl_function_or_method (AST::Visibility vis, AST::AttrVec outer_attrs); @@ -303,7 +304,6 @@ private: AST::AttrVec outer_attrs); std::unique_ptr parse_extern_block (AST::Visibility vis, AST::AttrVec outer_attrs); - std::unique_ptr parse_external_item (); AST::NamedFunctionParam parse_named_function_param (AST::AttrVec outer_attrs = AST::AttrVec ()); AST::Method parse_method (); From 935b561e7fb6471773e2a7e860011b76702cd563 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Tue, 15 Mar 2022 09:12:37 +0100 Subject: [PATCH 2/3] macros: Add test cases for remaining expansion contexts --- gcc/testsuite/rust/compile/macro20.rs | 16 ++++++++++++++++ gcc/testsuite/rust/compile/macro21.rs | 9 +++++++++ gcc/testsuite/rust/compile/macro22.rs | 10 ++++++++++ gcc/testsuite/rust/compile/macro23.rs | 25 +++++++++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 gcc/testsuite/rust/compile/macro20.rs create mode 100644 gcc/testsuite/rust/compile/macro21.rs create mode 100644 gcc/testsuite/rust/compile/macro22.rs create mode 100644 gcc/testsuite/rust/compile/macro23.rs diff --git a/gcc/testsuite/rust/compile/macro20.rs b/gcc/testsuite/rust/compile/macro20.rs new file mode 100644 index 00000000000..9f3cbca012c --- /dev/null +++ b/gcc/testsuite/rust/compile/macro20.rs @@ -0,0 +1,16 @@ +macro_rules! define_trait { + ($assoc:ident, $i:item) => { + type $assoc; + + $i + }; +} + +trait DefinedThroughMacros { + define_trait!( + Inner, + fn takes_inner(i: Self::Inner) -> Self::Inner { + i + } + ); +} diff --git a/gcc/testsuite/rust/compile/macro21.rs b/gcc/testsuite/rust/compile/macro21.rs new file mode 100644 index 00000000000..9a1d773ec4b --- /dev/null +++ b/gcc/testsuite/rust/compile/macro21.rs @@ -0,0 +1,9 @@ +macro_rules! c_fn { + {$name:ident ($($arg_name:ident $arg_ty:ty),*) -> $ret_ty:ty} => { + fn $name($($arg_name: $arg_ty)*) -> $ret_ty; + }; +} + +extern "C" { + c_fn! {puts (s *const i8) -> i64} +} diff --git a/gcc/testsuite/rust/compile/macro22.rs b/gcc/testsuite/rust/compile/macro22.rs new file mode 100644 index 00000000000..bdc4bada270 --- /dev/null +++ b/gcc/testsuite/rust/compile/macro22.rs @@ -0,0 +1,10 @@ +macro_rules! print { + () => { + fn puts(s: *const i8); + fn printf(fmt: *const i8, ...); + }; +} + +extern "C" { + print! {} +} diff --git a/gcc/testsuite/rust/compile/macro23.rs b/gcc/testsuite/rust/compile/macro23.rs new file mode 100644 index 00000000000..afaca9bc96b --- /dev/null +++ b/gcc/testsuite/rust/compile/macro23.rs @@ -0,0 +1,25 @@ +macro_rules! maybe_impl { + ($left:ident, $right:ident, $l_fn:ident, $r_fn:ident) => { + fn $l_fn(value: T) -> Maybe { + Maybe::$left(value) + } + + fn $r_fn() -> Maybe { + Maybe::$right + } + }; +} + +enum Maybe { + Just(T), + Nothing, +} + +impl Maybe { + maybe_impl!(Just, Nothing, just, nothing); +} + +fn main() { + let _ = Maybe::just(14); + let _: Maybe = Maybe::nothing(); +} From a7ef6f98be0e25187ad1690428aafc17e19b5751 Mon Sep 17 00:00:00 2001 From: Arthur Cohen Date: Wed, 16 Mar 2022 16:57:17 +0100 Subject: [PATCH 3/3] macros: Allow macro calls in trait implementations Just like inherent implementation blocks, trait implementation blocks (`impl Trait for Type`) can also contain macro invocations. --- gcc/rust/ast/rust-ast.h | 28 +++++++++++++++++++ gcc/rust/expand/rust-attribute-visitor.cc | 8 ++++-- gcc/rust/expand/rust-macro-expand.cc | 19 +++++++++++++ gcc/rust/expand/rust-macro-expand.h | 3 +- gcc/rust/parse/rust-parse.h | 2 +- .../rust/execute/torture/macros23.rs | 19 +++++++++++++ 6 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/macros23.rs diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index e33fff2d988..a22c2d1ad1d 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -1514,6 +1514,7 @@ public: EXTERN, TRAIT, IMPL, + TRAIT_IMPL, }; private: @@ -1526,6 +1527,7 @@ private: std::unique_ptr external_item; std::unique_ptr trait_item; std::unique_ptr impl_item; + std::unique_ptr trait_impl_item; public: SingleASTNode (std::unique_ptr expr) @@ -1552,6 +1554,10 @@ public: : kind (IMPL), impl_item (std::move (item)) {} + SingleASTNode (std::unique_ptr trait_impl_item) + : kind (TRAIT_IMPL), trait_impl_item (std::move (trait_impl_item)) + {} + SingleASTNode (SingleASTNode const &other) { kind = other.kind; @@ -1580,6 +1586,10 @@ public: case IMPL: impl_item = other.impl_item->clone_inherent_impl_item (); break; + + case TRAIT_IMPL: + trait_impl_item = other.trait_impl_item->clone_trait_impl_item (); + break; } } @@ -1611,6 +1621,10 @@ public: case IMPL: impl_item = other.impl_item->clone_inherent_impl_item (); break; + + case TRAIT_IMPL: + trait_impl_item = other.trait_impl_item->clone_trait_impl_item (); + break; } return *this; } @@ -1679,6 +1693,12 @@ public: return std::move (impl_item); } + std::unique_ptr take_trait_impl_item () + { + rust_assert (!is_error ()); + return std::move (trait_impl_item); + } + void accept_vis (ASTVisitor &vis) { switch (kind) @@ -1706,6 +1726,10 @@ public: case IMPL: impl_item->accept_vis (vis); break; + + case TRAIT_IMPL: + trait_impl_item->accept_vis (vis); + break; } } @@ -1725,6 +1749,8 @@ public: return trait_item == nullptr; case IMPL: return impl_item == nullptr; + case TRAIT_IMPL: + return trait_impl_item == nullptr; } gcc_unreachable (); @@ -1747,6 +1773,8 @@ public: return "Trait Item: " + trait_item->as_string (); case IMPL: return "Impl Item: " + impl_item->as_string (); + case TRAIT_IMPL: + return "Trait Impl Item: " + impl_item->as_string (); } gcc_unreachable (); diff --git a/gcc/rust/expand/rust-attribute-visitor.cc b/gcc/rust/expand/rust-attribute-visitor.cc index 50821edcfae..3de660897ca 100644 --- a/gcc/rust/expand/rust-attribute-visitor.cc +++ b/gcc/rust/expand/rust-attribute-visitor.cc @@ -2549,8 +2549,12 @@ AttrVisitor::visit (AST::TraitImpl &impl) if (impl.has_where_clause ()) expand_where_clause (impl.get_where_clause ()); - // strip trait impl items if required - expand_pointer_allow_strip (impl.get_impl_items ()); + std::function (AST::SingleASTNode)> + extractor + = [] (AST::SingleASTNode node) { return node.take_trait_impl_item (); }; + + expand_macro_children (MacroExpander::TRAIT_IMPL, impl.get_impl_items (), + extractor); } void AttrVisitor::visit (AST::ExternalStaticItem &item) diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 80f822b3e53..3bdb8c685e6 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -859,6 +859,22 @@ transcribe_many_impl_items (Parser &parser, TokenId &delimiter) }); } +/** + * Transcribe 0 or more trait impl items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static std::vector +transcribe_many_trait_impl_items (Parser &parser, + TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_trait_impl_item (); + return AST::SingleASTNode (std::move (item)); + }); +} + /** * Transcribe 0 or more statements from a macro invocation * @@ -932,6 +948,9 @@ transcribe_context (MacroExpander::ContextType ctx, case MacroExpander::ContextType::IMPL: return transcribe_many_impl_items (parser, last_token_id); break; + case MacroExpander::ContextType::TRAIT_IMPL: + return transcribe_many_trait_impl_items (parser, last_token_id); + break; case MacroExpander::ContextType::EXTERN: return transcribe_many_ext (parser, last_token_id); break; diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h index 61b69e412a4..f08525fd4e8 100644 --- a/gcc/rust/expand/rust-macro-expand.h +++ b/gcc/rust/expand/rust-macro-expand.h @@ -187,9 +187,10 @@ struct MacroExpander { ITEM, BLOCK, + EXTERN, TRAIT, IMPL, - EXTERN, + TRAIT_IMPL, }; ExpansionCfg cfg; diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index bb5bf3d7072..588061629e9 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -138,6 +138,7 @@ public: std::unique_ptr parse_external_item (); std::unique_ptr parse_trait_item (); std::unique_ptr parse_inherent_impl_item (); + std::unique_ptr parse_trait_impl_item (); AST::PathInExpression parse_path_in_expression (); std::vector > parse_lifetime_params (); AST::Visibility parse_visibility (); @@ -298,7 +299,6 @@ private: std::unique_ptr parse_inherent_impl_function_or_method (AST::Visibility vis, AST::AttrVec outer_attrs); - std::unique_ptr parse_trait_impl_item (); std::unique_ptr parse_trait_impl_function_or_method (AST::Visibility vis, AST::AttrVec outer_attrs); diff --git a/gcc/testsuite/rust/execute/torture/macros23.rs b/gcc/testsuite/rust/execute/torture/macros23.rs new file mode 100644 index 00000000000..846352d0487 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/macros23.rs @@ -0,0 +1,19 @@ +trait Valuable { + const VALUE: i32; +} + +struct Something; + +macro_rules! implement { + () => { + const VALUE: i32 = 18; + }; +} + +impl Valuable for Something { + implement!(); +} + +fn main() -> i32 { + Something::VALUE - 18 +}