diff options
author | Matthew Jasper <mjjasper1@gmail.com> | 2023-06-08 20:14:47 +0100 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2023-06-20 08:10:23 +0000 |
commit | 33544f79849a5b747d84fea0fc2be25e208e3ab4 (patch) | |
tree | 23aeda774724f82f2030efc3e38cfd7c1db8c564 | |
parent | cbca7bdde221f68da59cd6d624cd34bf439b04b7 (diff) | |
download | gcc-33544f79849a5b747d84fea0fc2be25e208e3ab4.zip gcc-33544f79849a5b747d84fea0fc2be25e208e3ab4.tar.gz gcc-33544f79849a5b747d84fea0fc2be25e208e3ab4.tar.bz2 |
gccrs: Parse semicolons in more cases for statement macros
gcc/rust/ChangeLog:
* ast/rust-ast.h (MacroInvocation::add_semicolon): New method.
* ast/rust-macro.h (MacroInvocation::add_semicolon): Add override.
* ast/rust-stmt.h (ExprStmt::add_semicolon): Add override.
* expand/rust-macro-expand.cc (parse_many): Pass enum by value.
(transcribe_many_stmts): Parse statements with semicolons.
* parse/rust-parse-impl.h (Parser::parse_let_stmt):
Work around lack of NT tokens.
(Parser::parse_expr_stmt): Handle statements at end of macro expansions.
* parse/rust-parse.h (struct ParseRestrictions): Additional flag.
gcc/testsuite/ChangeLog:
* rust/compile/macro53.rs: New test.
Signed-off-by: Matthew Jasper <mjjasper1@gmail.com>
-rw-r--r-- | gcc/rust/ast/rust-ast.h | 2 | ||||
-rw-r--r-- | gcc/rust/ast/rust-macro.h | 2 | ||||
-rw-r--r-- | gcc/rust/ast/rust-stmt.h | 5 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-expand.cc | 26 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse-impl.h | 37 | ||||
-rw-r--r-- | gcc/rust/parse/rust-parse.h | 3 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/macro53.rs | 10 |
7 files changed, 68 insertions, 17 deletions
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index 09a7351..a9b31e0 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -904,6 +904,8 @@ public: virtual bool is_expr () const { return false; } + virtual void add_semicolon () {} + protected: Stmt () : node_id (Analysis::Mappings::get ()->get_next_node_id ()) {} diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index 29bb9fa..4e24144 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -787,6 +787,8 @@ public: return new MacroInvocation (*this); } + void add_semicolon () override { is_semi_coloned = true; } + protected: Item *clone_item_impl () const override { diff --git a/gcc/rust/ast/rust-stmt.h b/gcc/rust/ast/rust-stmt.h index 38ca215..6e2113a 100644 --- a/gcc/rust/ast/rust-stmt.h +++ b/gcc/rust/ast/rust-stmt.h @@ -192,6 +192,11 @@ public: bool is_item () const override final { return false; } bool is_expr () const override final { return true; } + + // Used for the last statement for statement macros with a trailing + // semicolon. + void add_semicolon () override final { semicolon_followed = true; } + std::string as_string () const override; std::vector<LetStmt *> locals; diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc index 9858049..a5a11cb 100644 --- a/gcc/rust/expand/rust-macro-expand.cc +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -724,7 +724,7 @@ MacroExpander::match_repetition (Parser<MacroInvocLexer> &parser, * Helper function to refactor calling a parsing function 0 or more times */ static AST::Fragment -parse_many (Parser<MacroInvocLexer> &parser, TokenId &delimiter, +parse_many (Parser<MacroInvocLexer> &parser, TokenId delimiter, std::function<AST::SingleASTNode ()> parse_fn) { auto &lexer = parser.get_token_source (); @@ -836,18 +836,22 @@ transcribe_many_trait_impl_items (Parser<MacroInvocLexer> &parser, * @param delimiter Id of the token on which parsing should stop */ static AST::Fragment -transcribe_many_stmts (Parser<MacroInvocLexer> &parser, TokenId &delimiter) +transcribe_many_stmts (Parser<MacroInvocLexer> &parser, TokenId delimiter, + bool semicolon) { auto restrictions = ParseRestrictions (); - restrictions.consume_semi = false; - - // FIXME: This is invalid! It needs to also handle cases where the macro - // transcriber is an expression, but since the macro call is followed by - // a semicolon, it's a valid ExprStmt - return parse_many (parser, delimiter, [&parser, restrictions] () { - auto stmt = parser.parse_stmt (restrictions); - return AST::SingleASTNode (std::move (stmt)); - }); + restrictions.allow_close_after_expr_stmt = true; + + return parse_many (parser, delimiter, + [&parser, restrictions, delimiter, semicolon] () { + auto stmt = parser.parse_stmt (restrictions); + if (semicolon && stmt + && parser.peek_current_token ()->get_id () + == delimiter) + stmt->add_semicolon (); + + return AST::SingleASTNode (std::move (stmt)); + }); } /** diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index d6b045b..c9dbee2 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -6348,8 +6348,16 @@ Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, } if (restrictions.consume_semi) - if (!skip_token (SEMICOLON)) - return nullptr; + { + // `stmt` macro variables are parsed without a semicolon, but should be + // parsed as a full statement when interpolated. This should be handled + // by having the interpolated statement be distinguishable from normal + // tokens, e.g. by NT tokens. + if (restrictions.allow_close_after_expr_stmt) + maybe_skip_token (SEMICOLON); + else if (!skip_token (SEMICOLON)) + return nullptr; + } return std::unique_ptr<AST::LetStmt> ( new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type), @@ -7289,10 +7297,27 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, if (restrictions.consume_semi) { - if (skip_token (SEMICOLON)) - has_semi = true; - else if (expr->is_expr_without_block ()) - return nullptr; + if (maybe_skip_token (SEMICOLON)) + { + has_semi = true; + } + else if (!expr->is_expr_without_block ()) + { + if (restrictions.allow_close_after_expr_stmt) + { + TokenId id = lexer.peek_token ()->get_id (); + if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE) + { + expect_token (SEMICOLON); + return nullptr; + } + } + else + { + expect_token (SEMICOLON); + return nullptr; + } + } } return std::unique_ptr<AST::ExprStmt> ( diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 315d3fc..74313df 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -87,6 +87,9 @@ struct ParseRestrictions bool expr_can_be_null = false; bool expr_can_be_stmt = false; bool consume_semi = true; + /* Macro invocations that are statements can expand without a semicolon after + * the final statement, if it's an expression statement. */ + bool allow_close_after_expr_stmt = false; }; // Parser implementation for gccrs. diff --git a/gcc/testsuite/rust/compile/macro53.rs b/gcc/testsuite/rust/compile/macro53.rs new file mode 100644 index 0000000..efa2d4b --- /dev/null +++ b/gcc/testsuite/rust/compile/macro53.rs @@ -0,0 +1,10 @@ +macro_rules! numbers { + {} => { 1 2 } + // { dg-error "expecting .;. but .integer literal. found" "" { target *-*-* } .-1 } +} + +pub fn foo() { + numbers!(); +} + +fn main() -> i32 { 0 } |