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

Reply via email to