[clang] 8242576 - [Clang] prevent crash in delayed default-argument lambda captures (#176749)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 27 06:25:14 PDT 2026
Author: Oleksandr Tarasiuk
Date: 2026-04-27T16:25:08+03:00
New Revision: 8242576869985db73d44ac537208744dceb93503
URL: https://github.com/llvm/llvm-project/commit/8242576869985db73d44ac537208744dceb93503
DIFF: https://github.com/llvm/llvm-project/commit/8242576869985db73d44ac537208744dceb93503.diff
LOG: [Clang] prevent crash in delayed default-argument lambda captures (#176749)
Fixes #176534
---
This patch resolves a crash when parsing delayed default arguments that
contain lambda expressions.
```cpp
struct S {
void f(int x, int = sizeof([x] { return x; }()));
};
```
When late-parsing default arguments that contain lambdas, `Sema` builds
a `FunctionScopes` stack containing only the lambda scope
(`FunctionScopes.size()` equals 1), however, `tryCaptureVariable`
expects an enclosing function scope outside the lambda scope
https://github.com/llvm/llvm-project/blob/41e231cae38028473dd327e8de5f65792b521ffe/clang/lib/Sema/SemaExpr.cpp#L19473-L19474
https://github.com/llvm/llvm-project/blob/41e231cae38028473dd327e8de5f65792b521ffe/clang/lib/Sema/SemaExpr.cpp#L19518
Scope capture handling logic decrements `FunctionScopesIndex` to align
declaration contexts
https://github.com/llvm/llvm-project/blob/41e231cae38028473dd327e8de5f65792b521ffe/clang/lib/Sema/SemaExpr.cpp#L19696
and later relies on it when traversing and accessing outer scopes
https://github.com/llvm/llvm-project/blob/41e231cae38028473dd327e8de5f65792b521ffe/clang/lib/Sema/SemaExpr.cpp#L19522-L19524
preserving the function scope in the late-parsing path prevents invalid
traversal during lambda capture handling
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Parse/ParseCXXInlineMethods.cpp
clang/test/SemaCXX/lambda-unevaluated.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2f72d55eb4ef8..b766bb834cf4f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -506,6 +506,7 @@ Bug Fixes in This Version
- Fixed a crash where constexpr evaluation encountered invalid overrides. (#GH183290)
- Fixed a crash when assigning to an element of an ``ext_vector_type`` with ``bool`` element type. (#GH189260)
- Clang now emits an error for friend declarations of lambda members. (#GH26540)
+- Fixed a crash caused by lambda capture handling in delayed default arguments. (#GH176534)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 5b26678454469..c1c567f7828cf 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -381,6 +381,20 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
InFunctionTemplateScope.Scopes.Enter(Scope::FunctionPrototypeScope |
Scope::FunctionDeclarationScope |
Scope::DeclScope);
+
+ // Delayed default arguments or exception specifications may contain lambdas,
+ // struct S {
+ // void ICE(int x, int = sizeof([x] { return x; }()));
+ // }
+ //
+ // struct X {
+ // void ICE(int val) noexcept(noexcept([val]{}));
+ // };
+ // Lambda capture handling in tryCaptureVariable() expects an enclosing
+ // function scope in Sema's FunctionScopes stack.
+ Sema::FunctionScopeRAII PopFnContext(Actions);
+ Actions.PushFunctionScope();
+
for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
auto Param = cast<ParmVarDecl>(LM.DefaultArgs[I].Param);
// Introduce the parameter into scope.
@@ -502,20 +516,11 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
FunctionToPush = cast<FunctionDecl>(LM.Method);
Method = dyn_cast<CXXMethodDecl>(FunctionToPush);
- // Push a function scope so that tryCaptureVariable() can properly visit
- // function scopes involving function parameters that are referenced inside
- // the noexcept specifier e.g. through a lambda expression.
- // Example:
- // struct X {
- // void ICE(int val) noexcept(noexcept([val]{}));
- // };
// Setup the CurScope to match the function DeclContext - we have such
// assumption in IsInFnTryBlockHandler().
ParseScope FnScope(this, Scope::FnScope);
Sema::ContextRAII FnContext(Actions, FunctionToPush,
/*NewThisContext=*/false);
- Sema::FunctionScopeRAII PopFnContext(Actions);
- Actions.PushFunctionScope();
Sema::CXXThisScopeRAII ThisScope(
Actions, Method ? Method->getParent() : nullptr,
diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp
index 55a4bc7aff1b5..9c723c6bc3b99 100644
--- a/clang/test/SemaCXX/lambda-unevaluated.cpp
+++ b/clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -288,3 +288,33 @@ auto t() {
return [](auto w = [&] { return x; }) { }; // expected-error {{lambda expression in default argument cannot capture any entity}}
};
}
+
+namespace GH176534 {
+struct S {
+ // expected-error at +9 {{reference to local variable 'x' declared in enclosing function 'GH176534::S::a'}}
+ // expected-error at +8 {{variable 'x' cannot be implicitly captured in a lambda with no capture-default specified}}
+ // expected-note at +7 {{'x' declared here}}
+ // expected-note at +6 {{'x' declared here}}
+ // expected-note at +5 {{lambda expression begins here}}
+ // expected-note at +4 {{capture 'x' by value}}
+ // expected-note at +3 {{capture 'x' by reference}}
+ // expected-note at +2 {{default capture by value}}
+ // expected-note at +1 {{default capture by reference}}
+ void a(int x, int = sizeof([x] { return x; }()));
+
+ // expected-error at +8 {{'this' cannot be captured in this context}}
+ // expected-error at +7 {{variable 'x' cannot be implicitly captured in a lambda with no capture-default specified}}
+ // expected-note at +6 {{default capture by reference}}
+ // expected-note at +5 {{lambda expression begins here}}
+ // expected-note at +4 {{capture 'x' by value}}
+ // expected-note at +3 {{capture 'x' by reference}}
+ // expected-note at +2 {{'x' declared here}}
+ // expected-note at +1 {{default capture by value}}
+ void b(int x, int = sizeof([this] { return x; }));
+
+ // expected-error at +3 {{non-local lambda expression cannot have a capture-default}}
+ // expected-error at +2 {{reference to local variable 'x' declared in enclosing function 'GH176534::S::c'}}
+ // expected-note at +1 {{'x' declared here}}
+ void c(int x, int = sizeof([=] { return x; }));
+};
+}
More information about the cfe-commits
mailing list