[clang] [Clang] fix crash with generic lambdas in function default args (PR #222987)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 14 03:19:23 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Oleksandr Tarasiuk (a-tarasyuk)
<details>
<summary>Changes</summary>
Fixes #<!-- -->48768
---
This PR addresses an issue in which a generic lambda in a function's default argument refers to an earlier parameter. It fixes template dependence and depth tracking and diagnoses invalid parameter references.
---
Full diff: https://github.com/llvm/llvm-project/pull/222987.diff
6 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+2)
- (modified) clang/lib/Parse/ParseDecl.cpp (+6)
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+8-1)
- (modified) clang/lib/Sema/SemaLambda.cpp (+1-1)
- (modified) clang/lib/Sema/SemaTemplate.cpp (+1-4)
- (modified) clang/test/SemaCXX/lambda-unevaluated.cpp (+47)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 8fd0dc4bfd245..cd44f3da170a9 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -679,6 +679,8 @@ features cannot lower the translation-unit ABI level;
class with an invalid non-static data member, such as one qualified with an
address space. (#GH194605)
+- Fixed a crash with generic lambdas in default arguments of functions with `auto` parameters.
+
#### Bug Fixes to AST Handling
- Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 1d3789a10d9de..bf42a04adf965 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7756,6 +7756,12 @@ void Parser::ParseParameterDeclarationClause(
DelayTemplateIdDestructionRAII DontDestructTemplateIds(
*this, /*DelayTemplateIdDestruction=*/true);
+ TemplateParameterDepthRAII CurTemplateDepthTracker(
+ TemplateParameterDepth);
+ unsigned Depth = Actions.getTemplateDepth(getCurScope());
+ if (Depth > TemplateParameterDepth)
+ CurTemplateDepthTracker.addDepth(Depth - TemplateParameterDepth);
+
// The argument isn't actually potentially evaluated unless it is
// used.
EnterExpressionEvaluationContext Eval(
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ea628f29d8a00..568bb4c785140 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -165,12 +165,19 @@ bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(
}
bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) {
+ bool Invalid = false;
+ for (NamedDecl *P : Lambda->getExplicitTemplateParameters()) {
+ const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P);
+ if (!NTTP || !NTTP->hasDefaultArgument())
+ continue;
+ Invalid |= Visit(NTTP->getDefaultArgument().getArgument().getAsExpr());
+ }
+
// [expr.prim.lambda.capture]p9
// a lambda-expression appearing in a default argument cannot implicitly or
// explicitly capture any local entity. Such a lambda-expression can still
// have an init-capture if any full-expression in its initializer satisfies
// the constraints of an expression appearing in a default argument.
- bool Invalid = false;
for (const LambdaCapture &LC : Lambda->captures()) {
if (!Lambda->isInitCapture(&LC))
return S.Diag(LC.getLocation(), diag::err_lambda_capture_default_arg);
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 288f3c4f664cb..ffbe5e72d4c51 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1143,7 +1143,7 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
// be dependent, because there are template parameters in scope.
CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind =
CXXRecordDecl::LDK_Unknown;
- if (CurScope->getTemplateParamParent() != nullptr) {
+ if (getTemplateDepth(CurScope) > 0) {
LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
} else if (Scope *ParentScope = CurScope->getParent()) {
// Given a lambda defined inside a requires expression,
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b8b0c71894daa..b800a433b3bf7 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -76,11 +76,8 @@ unsigned Sema::getTemplateDepth(Scope *S) const {
if (auto *LSI = dyn_cast<LambdaScopeInfo>(FSI)) {
if (!LSI->TemplateParams.empty()) {
ParamsAtDepth(LSI->AutoTemplateParameterDepth);
- break;
- }
- if (LSI->GLTemplateParameterList) {
+ } else if (LSI->GLTemplateParameterList) {
ParamsAtDepth(LSI->GLTemplateParameterList->getDepth());
- break;
}
}
}
diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp
index 9c723c6bc3b99..018d597e6831b 100644
--- a/clang/test/SemaCXX/lambda-unevaluated.cpp
+++ b/clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -std=c++20 %s -Wno-c++23-extensions -verify
// RUN: %clang_cc1 -std=c++23 %s -verify
+// RUN: %clang_cc1 -std=c++26 %s -verify
template <auto> struct Nothing {};
Nothing<[]() { return 0; }()> nothing;
@@ -283,10 +284,21 @@ static_assert(__is_same_as(int, helper<int>));
} // namespace GH138018
namespace GH172814 {
+auto f() {
+ int x = 0;
+ return [](auto w = [&] { x += w(); }); // expected-error {{lambda expression in default argument cannot capture any entity}} \
+ // expected-error {{expected body of lambda expression}}
+}
+
auto t() {
int x = 0;
return [](auto w = [&] { return x; }) { }; // expected-error {{lambda expression in default argument cannot capture any entity}}
};
+
+auto g() {
+ int x = 0;
+ return []<class T>(T w = [&] { return x; }) {}; // expected-error {{lambda expression in default argument cannot capture any entity}}
+}
}
namespace GH176534 {
@@ -318,3 +330,38 @@ struct S {
void c(int x, int = sizeof([=] { return x; }));
};
}
+
+namespace GH48768 {
+
+auto a(auto x = 1, auto = []<auto = x> {}()); // expected-error {{default argument references parameter 'x'}}
+void b(auto x, auto = []<auto = x> {}); // expected-error {{default argument references parameter 'x'}}
+auto c = [](auto x, int = []<auto = x> { return 0; }()) {}; // expected-error {{default argument references parameter 'x'}}
+
+constexpr int d(auto x, int n = []<auto N = sizeof(x)> { return N; }()) {
+ return n;
+}
+
+constexpr int e(auto x, int n = []<class T = decltype(x)> { return sizeof(T); }()) {
+ return n;
+}
+
+constexpr auto f = [](auto x, int n = []<auto N = sizeof(x)> { return N; }()) {
+ return n;
+};
+
+constexpr auto g = [](auto x, int n = []<class T = decltype(x)> { return sizeof(T); }()) {
+ return n;
+};
+
+constexpr auto h = [](auto x) {
+ return [](auto y, int n = []<auto N = sizeof(y)> { return N; }()) {
+ return n;
+ };
+};
+
+static_assert(d(0) == sizeof(int));
+static_assert(e(0) == sizeof(int));
+static_assert(f(0) == sizeof(int));
+static_assert(g(0) == sizeof(int));
+static_assert(h(0)('a') == 1);
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/222987
More information about the cfe-commits
mailing list