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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
