diff --git a/toolchain/lexer/token_kind.h b/toolchain/lexer/token_kind.h index 3828add4420f..a0c0bf6f1a67 100644 --- a/toolchain/lexer/token_kind.h +++ b/toolchain/lexer/token_kind.h @@ -64,12 +64,12 @@ class TokenKind { // The token kind must be an opening symbol. [[nodiscard]] auto GetClosingSymbol() const -> TokenKind; - // Test whether this kind of token is an closing symbol for a group. + // Test whether this kind of token is a closing symbol for a group. [[nodiscard]] auto IsClosingSymbol() const -> bool; // Returns the associated opening symbol for a closing symbol. // - // The token kind must be an closing symbol. + // The token kind must be a closing symbol. [[nodiscard]] auto GetOpeningSymbol() const -> TokenKind; // Test whether this kind of token is a keyword. diff --git a/toolchain/parser/fuzzer_corpus/386740becc4c02670666928a4699c330b2fe1152 b/toolchain/parser/fuzzer_corpus/386740becc4c02670666928a4699c330b2fe1152 new file mode 100644 index 000000000000..e4b750f75fd1 Binary files /dev/null and b/toolchain/parser/fuzzer_corpus/386740becc4c02670666928a4699c330b2fe1152 differ diff --git a/toolchain/parser/fuzzer_corpus/937ffb0f00790f35ae9b578df0bcfa40b06fd2e8 b/toolchain/parser/fuzzer_corpus/937ffb0f00790f35ae9b578df0bcfa40b06fd2e8 new file mode 100644 index 000000000000..4e3c7f42a0a0 Binary files /dev/null and b/toolchain/parser/fuzzer_corpus/937ffb0f00790f35ae9b578df0bcfa40b06fd2e8 differ diff --git a/toolchain/parser/fuzzer_corpus/eddd593ed1b3ecde2f2b4ddf2ba4a4fbb83a6028 b/toolchain/parser/fuzzer_corpus/eddd593ed1b3ecde2f2b4ddf2ba4a4fbb83a6028 new file mode 100644 index 000000000000..7a07a324e14b Binary files /dev/null and b/toolchain/parser/fuzzer_corpus/eddd593ed1b3ecde2f2b4ddf2ba4a4fbb83a6028 differ diff --git a/toolchain/parser/parse_tree_test.cpp b/toolchain/parser/parse_tree_test.cpp index f66a41569206..5ebd99c839ae 100644 --- a/toolchain/parser/parse_tree_test.cpp +++ b/toolchain/parser/parse_tree_test.cpp @@ -1159,5 +1159,21 @@ TEST_F(ParseTreeTest, PrintingAsYAML) { {"text", ""}}})); } +TEST_F(ParseTreeTest, ParenMatchRegression) { + // A regression test that the search for the closing `)` doesn't end early on + // the closing `}` when it skips over the nested scope. + TokenizedBuffer tokens = GetTokenizedBuffer("var = (foo {})"); + ParseTree tree = ParseTree::Parse(tokens, consumer); + EXPECT_TRUE(tree.HasErrors()); + EXPECT_THAT( + tree, MatchParseTreeNodes( + {MatchVariableDeclaration( + HasError, MatchVariableInitializer( + "=", MatchParenExpression( + HasError, MatchNameReference("foo"), + MatchParenExpressionEnd()))), + MatchFileEnd()})); +} + } // namespace } // namespace Carbon diff --git a/toolchain/parser/parser_impl.cpp b/toolchain/parser/parser_impl.cpp index 8aaad3280ea8..b634affb29b8 100644 --- a/toolchain/parser/parser_impl.cpp +++ b/toolchain/parser/parser_impl.cpp @@ -347,6 +347,8 @@ auto ParseTree::Parser::FindNextOf( } else if (kind.IsOpeningSymbol()) { new_position = TokenizedBuffer::TokenIterator(tokens_.GetMatchedClosingToken(token)); + // Advance past the closing token. + ++new_position; } else { ++new_position; }