aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2023-06-08 20:14:47 +0100
committerPhilip Herron <philip.herron@embecosm.com>2023-06-20 08:10:23 +0000
commit33544f79849a5b747d84fea0fc2be25e208e3ab4 (patch)
tree23aeda774724f82f2030efc3e38cfd7c1db8c564
parentcbca7bdde221f68da59cd6d624cd34bf439b04b7 (diff)
downloadgcc-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.h2
-rw-r--r--gcc/rust/ast/rust-macro.h2
-rw-r--r--gcc/rust/ast/rust-stmt.h5
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc26
-rw-r--r--gcc/rust/parse/rust-parse-impl.h37
-rw-r--r--gcc/rust/parse/rust-parse.h3
-rw-r--r--gcc/testsuite/rust/compile/macro53.rs10
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 }