diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2022-03-21 17:27:05 +0100 |
---|---|---|
committer | Arthur Cohen <arthur.cohen@embecosm.com> | 2022-03-22 16:00:30 +0100 |
commit | ef5638186202daac03feed7a20eb975991965403 (patch) | |
tree | 247ff565c1d06636f05afbd5cd7af555e6d160bb /gcc/rust/parse/rust-parse-impl.h | |
parent | cc6e405912c83aee41efd3015d9157cdbe9134fe (diff) | |
download | gcc-ef5638186202daac03feed7a20eb975991965403.zip gcc-ef5638186202daac03feed7a20eb975991965403.tar.gz gcc-ef5638186202daac03feed7a20eb975991965403.tar.bz2 |
parser: Add better restrictions around semicolons in statements
When parsing macro invocations, rustc does not actually consume the
statement's trailing semicolon.
Let's take the following example:
```rust
macro_rules! one_stmt {
($s:stmt) => {};
}
macro_rules! one_or_more_stmt {
($($s:stmt)*) => {};
}
one_stmt!(let a = 1);
one_stmt!(let b = 2;); // error
one_or_more_stmt!(;); // valid
one_or_more_stmt!(let a = 15;); // valid, two statements!
one_or_more_stmt!(let a = 15 let b = 13); // valid, two statements again
```
A semicolon can count as a valid empty statement, but cannot be part of
a statement (in macro invocations). This commit adds more restrictions
that allow the parser to not always expect a semicolon token after the
statement. Furthermore, this fixes a test that was previously accepted
by the compiler but not by rustc.
Diffstat (limited to 'gcc/rust/parse/rust-parse-impl.h')
-rw-r--r-- | gcc/rust/parse/rust-parse-impl.h | 34 |
1 files changed, 13 insertions, 21 deletions
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 644e789..a34f3d4 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -6091,7 +6091,7 @@ Parser<ManagedTokenSource>::parse_named_function_param ( // Parses a statement (will further disambiguate any statement). template <typename ManagedTokenSource> std::unique_ptr<AST::Stmt> -Parser<ManagedTokenSource>::parse_stmt (bool allow_no_semi) +Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions) { // quick exit for empty statement // FIXME: Can we have empty statements without semicolons? Just nothing? @@ -6116,7 +6116,7 @@ Parser<ManagedTokenSource>::parse_stmt (bool allow_no_semi) { case LET: // let statement - return parse_let_stmt (std::move (outer_attrs), allow_no_semi); + return parse_let_stmt (std::move (outer_attrs), restrictions); case PUB: case MOD: case EXTERN_TOK: @@ -6171,7 +6171,7 @@ Parser<ManagedTokenSource>::parse_stmt (bool allow_no_semi) // TODO: find out how to disable gcc "implicit fallthrough" warning default: // fallback: expression statement - return parse_expr_stmt (std::move (outer_attrs), allow_no_semi); + return parse_expr_stmt (std::move (outer_attrs), restrictions); break; } } @@ -6180,7 +6180,7 @@ Parser<ManagedTokenSource>::parse_stmt (bool allow_no_semi) template <typename ManagedTokenSource> std::unique_ptr<AST::LetStmt> Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, - bool allow_no_semi) + ParseRestrictions restrictions) { Location locus = lexer.peek_token ()->get_locus (); skip_token (LET); @@ -6235,13 +6235,9 @@ Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, } } - if (!maybe_skip_token (SEMICOLON) && !allow_no_semi) - { - // skip after somewhere + if (restrictions.consume_semi) + if (!skip_token (SEMICOLON)) return nullptr; - /* TODO: how wise is it to ditch a mostly-valid let statement just - * because a semicolon is missing? */ - } return std::unique_ptr<AST::LetStmt> ( new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type), @@ -7076,7 +7072,7 @@ Parser<ManagedTokenSource>::parse_method () template <typename ManagedTokenSource> std::unique_ptr<AST::ExprStmt> Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, - bool allow_no_semi) + ParseRestrictions restrictions) { /* potential thoughts - define new virtual method "has_block()" on expr. parse * expr and then determine whether semicolon is needed as a result of this @@ -7116,7 +7112,7 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, else { return parse_expr_stmt_without_block (std::move (outer_attrs), - allow_no_semi); + restrictions); } } case UNSAFE: { @@ -7130,7 +7126,7 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, else { return parse_expr_stmt_without_block (std::move (outer_attrs), - allow_no_semi); + restrictions); } } default: @@ -7139,7 +7135,7 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, * initial tokens in order to prevent more syntactical errors at parse * time. */ return parse_expr_stmt_without_block (std::move (outer_attrs), - allow_no_semi); + restrictions); } } @@ -7255,7 +7251,7 @@ Parser<ManagedTokenSource>::parse_expr_stmt_with_block ( template <typename ManagedTokenSource> std::unique_ptr<AST::ExprStmtWithoutBlock> Parser<ManagedTokenSource>::parse_expr_stmt_without_block ( - AST::AttrVec outer_attrs, bool allow_no_semi) + AST::AttrVec outer_attrs, ParseRestrictions restrictions) { /* TODO: maybe move more logic for expr without block in here for better error * handling */ @@ -7264,7 +7260,6 @@ Parser<ManagedTokenSource>::parse_expr_stmt_without_block ( std::unique_ptr<AST::ExprWithoutBlock> expr = nullptr; Location locus = lexer.peek_token ()->get_locus (); - auto restrictions = ParseRestrictions (); restrictions.expr_can_be_stmt = true; expr = parse_expr_without_block (std::move (outer_attrs), restrictions); @@ -7279,12 +7274,9 @@ Parser<ManagedTokenSource>::parse_expr_stmt_without_block ( return nullptr; } - // skip semicolon at end that is required - if (!maybe_skip_token (SEMICOLON) && !allow_no_semi) - { - // skip somewhere? + if (restrictions.consume_semi) + if (!skip_token (SEMICOLON)) return nullptr; - } return std::unique_ptr<AST::ExprStmtWithoutBlock> ( new AST::ExprStmtWithoutBlock (std::move (expr), locus)); |