https://github.com/a-tarasyuk created
https://github.com/llvm/llvm-project/pull/166180
Fixes #163498
---
This PR addresses the issue of confusing diagnostics for lambdas with
init-captures appearing inside braced initializers.
Cases such as:
```cpp
S s{[a(42), &] {}};
```
were misparsed as C99 array designators, producing unrelated diagnostics, such
as `use of undeclared identifier 'a'`, and `expected ']'`
---
https://github.com/llvm/llvm-project/blob/bb9bd5f263226840194b28457ddf9861986db51f/clang/lib/Parse/ParseInit.cpp#L470
https://github.com/llvm/llvm-project/blob/bb9bd5f263226840194b28457ddf9861986db51f/clang/lib/Parse/ParseInit.cpp#L74
https://github.com/llvm/llvm-project/blob/bb9bd5f263226840194b28457ddf9861986db51f/clang/include/clang/Parse/Parser.h#L4652-L4655
https://github.com/llvm/llvm-project/blob/24c22b7de620669aed9da28de323309c44a58244/clang/lib/Parse/ParseExprCXX.cpp#L871-L879
The tentative parser now returns `Incomplete` for partially valid lambda
introducers, preserving the `lambda` interpretation and allowing the proper
diagnostic to be issued later.
---
Clang now correctly recognizes such constructs as malformed lambda introducers
and emits the expected diagnostic — for example, “capture-default must be
first” — consistent with direct initialization cases such as:
```cpp
S s([a(42), &] {});
```
>From b97e99f73cddc4ca5c525dbd9e781679902adaec Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <[email protected]>
Date: Mon, 3 Nov 2025 17:21:38 +0200
Subject: [PATCH] [Clang] fix confusing diagnostics for lambdas with
init-captures inside braced initializers
---
clang/docs/ReleaseNotes.rst | 1 +
clang/lib/Parse/ParseExprCXX.cpp | 42 +++++++++++--------
.../lambda-misplaced-capture-default.cpp | 9 ++++
3 files changed, 35 insertions(+), 17 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92fc9381a5868..63faf46895989 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -496,6 +496,7 @@ Bug Fixes to C++ Support
nontrivial member when another member has an initializer. (#GH81774)
- Fixed a template depth issue when parsing lambdas inside a type constraint.
(#GH162092)
- Diagnose unresolved overload sets in non-dependent compound requirements.
(#GH51246) (#GH97753)
+- Fix incorrect diagnostics for lambdas with init-captures inside braced
initializers. (#GH163498)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 74f87a8cb63c3..03ae727168df0 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -772,9 +772,10 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// Produce a diagnostic if we're not tentatively parsing; otherwise track
// that our parse has failed.
- auto Invalid = [&](llvm::function_ref<void()> Action) {
+ auto Result = [&](llvm::function_ref<void()> Action,
+ LambdaIntroducerTentativeParse State) {
if (Tentative) {
- *Tentative = LambdaIntroducerTentativeParse::Invalid;
+ *Tentative = State;
return false;
}
Action();
@@ -824,9 +825,11 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
break;
}
- return Invalid([&] {
- Diag(Tok.getLocation(), diag::err_expected_comma_or_rsquare);
- });
+ return Result(
+ [&] {
+ Diag(Tok.getLocation(), diag::err_expected_comma_or_rsquare);
+ },
+ LambdaIntroducerTentativeParse::Invalid);
}
ConsumeToken();
}
@@ -861,9 +864,11 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
ConsumeToken();
Kind = LCK_StarThis;
} else {
- return Invalid([&] {
- Diag(Tok.getLocation(), diag::err_expected_star_this_capture);
- });
+ return Result(
+ [&] {
+ Diag(Tok.getLocation(), diag::err_expected_star_this_capture);
+ },
+ LambdaIntroducerTentativeParse::Invalid);
}
} else if (Tok.is(tok::kw_this)) {
Kind = LCK_This;
@@ -875,8 +880,9 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// or the start of a capture (in the "&" case) with the rest of the
// capture missing. Both are an error but a misplaced capture-default
// is more likely if we don't already have a capture default.
- return Invalid(
- [&] { Diag(Tok.getLocation(), diag::err_capture_default_first); });
+ return Result(
+ [&] { Diag(Tok.getLocation(), diag::err_capture_default_first); },
+ LambdaIntroducerTentativeParse::Incomplete);
} else {
TryConsumeToken(tok::ellipsis, EllipsisLocs[0]);
@@ -899,14 +905,16 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer
&Intro,
Id = Tok.getIdentifierInfo();
Loc = ConsumeToken();
} else if (Tok.is(tok::kw_this)) {
- return Invalid([&] {
- // FIXME: Suggest a fixit here.
- Diag(Tok.getLocation(), diag::err_this_captured_by_reference);
- });
+ return Result(
+ [&] {
+ // FIXME: Suggest a fixit here.
+ Diag(Tok.getLocation(), diag::err_this_captured_by_reference);
+ },
+ LambdaIntroducerTentativeParse::Invalid);
} else {
- return Invalid([&] {
- Diag(Tok.getLocation(), diag::err_expected_capture);
- });
+ return Result(
+ [&] { Diag(Tok.getLocation(), diag::err_expected_capture); },
+ LambdaIntroducerTentativeParse::Invalid);
}
TryConsumeToken(tok::ellipsis, EllipsisLocs[2]);
diff --git a/clang/test/Parser/lambda-misplaced-capture-default.cpp
b/clang/test/Parser/lambda-misplaced-capture-default.cpp
index d65b875102da7..4f5bd6d7fa5e9 100644
--- a/clang/test/Parser/lambda-misplaced-capture-default.cpp
+++ b/clang/test/Parser/lambda-misplaced-capture-default.cpp
@@ -36,3 +36,12 @@ template <typename... Args> void Test(Args... args) {
[... xs = &args, &] {}; // expected-error {{capture default must be first}}
}
} // namespace misplaced_capture_default_pack
+
+namespace GH163498 {
+struct S {
+ template <class T> S(T) {}
+};
+void t() {
+ S s{[a(42), &] {}}; // expected-error {{capture default must be first}}
+}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits