[clang][Parse] Stop parsing declarator chunks after a parenthesized structured binding
Project: llvm/llvm-project | Language: C++ | Concepts: compiler-internals, error-handling, testing-strategy | Difficulty: senior
Link: https://github.com/llvm/llvm-project/pull/219270
The problem
Clang would crash or assert when parsing a parenthesized structured binding followed by a function declarator and body, such as ([a, b])() {}. This is invalid C++, but the parser failed to reject it early, leading to an internal assertion or segmentation fault.
Why it's non-trivial
A naive fix might only check for unparenthesized structured bindings, but the bug occurs specifically when the binding is parenthesized (e.g., ([a, b])). In this case, the parser's logic for stopping after a structured binding was bypassed, so it incorrectly tried to parse further declarator chunks (like ()) and treated the construct as a function, leading to a crash.
The approach
The fix adds an explicit check after parsing a parenthesized declarator: if it turns out to be a structured binding, the parser stops immediately, preventing any further suffixes from being parsed.
Key code snippet:
@@ -6862,6 +6862,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// Example: 'char (*X)' or 'int (*XX)(void)'
ParseParenDeclarator(D);
+ // As above, a structured binding declarator cannot be followed by any
+ // declarator chunks.
+ if (D.isDecompositionDeclarator())
+ return;
+
// If the declarator was parenthesized, we entered the declarator
// scope when parsing the parenthesized declarator, then exited
// the scope already. Re-enter the scope, if we need to.
ParseParenDeclarator(D);parses the parenthesized declarator.- The new check
if (D.isDecompositionDeclarator()) return;detects if the result is a structured binding and exits early, preventing the parser from interpreting trailing()as a function declarator.
Test coverage:
A new test file, clang/test/Parser/GH218144.cpp, is added to verify that various invalid structured binding forms are rejected with the correct diagnostics and do not crash the compiler:
+auto ([a])() {}
+// expected-error@-1 {{structured binding declaration cannot be declared with parentheses}}
+// expected-error@-2 {{expected expression}}
+// expected-error@-3 {{expected ';' after top level declarator}}
This ensures that both parenthesized and nested parenthesized structured bindings with trailing function declarators are handled safely.
Release notes:
+- Fixed an assertion failure when a parenthesized structured binding declarator
+ was followed by a function declarator and body (e.g. ``([a, b])() {}``).
+ (#GH218144, #GH193687)
From the review thread
Fznamznon: Can we give the PR title that explains what the patch does in a short way instead of naming the assert? See https://llvm.org/docs/DeveloperPolicy.html#commit-messages .
akash-manna-sky: I changed the PR title...
Takeaways
- When fixing parser bugs, ensure that all syntactic forms (including parenthesized and nested variants) are covered by the stopping conditions.
- Defensive parsing: If an invalid construct is detected, halt further parsing immediately to avoid cascading errors or crashes.
- Add regression tests for each variant of the problematic syntax to prevent future regressions and to ensure correct diagnostics are emitted.