llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: puneeth_aditya_5656 (mugiwaraluffy56)

<details>
<summary>Changes</summary>

## Summary

Fixes #<!-- -->180319

Recursive lambdas in templates could cause Clang to crash with a stack overflow 
before hitting the template instantiation depth limit. This happened because 
`LambdaExpressionSubstitution` doesn't count toward the depth limit (by design 
for SFINAE per [temp.deduct]p9).

This PR wraps the `TransformLambdaBody` call in `runWithSufficientStackSpace` 
to handle deeply nested recursive lambdas gracefully:
- If threads are enabled, it runs on a new 8MB stack when stack is nearly 
exhausted
- If threads are disabled, it emits a warning and continues

## Test plan

- Added TEST=4 to `clang/test/SemaTemplate/stack-exhaustion.cpp` with the 
reproduction case from the issue
- The test uses `complexify&lt;200&gt;` which would previously crash but now 
handles gracefully

---
Full diff: https://github.com/llvm/llvm-project/pull/180325.diff


2 Files Affected:

- (modified) clang/lib/Sema/TreeTransform.h (+10-2) 
- (modified) clang/test/SemaTemplate/stack-exhaustion.cpp (+26) 


``````````diff
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index dd061996a0f9e..6ac180671895b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15963,8 +15963,16 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr 
*E) {
     getSema().pushCodeSynthesisContext(C);
 
     // Instantiate the body of the lambda expression.
-    Body = Invalid ? StmtError()
-                   : getDerived().TransformLambdaBody(E, E->getBody());
+    // Use runWithSufficientStackSpace to handle deeply nested recursive
+    // lambdas that might exhaust the stack before hitting the template
+    // instantiation depth limit.
+    if (Invalid) {
+      Body = StmtError();
+    } else {
+      getSema().runWithSufficientStackSpace(E->getBody()->getBeginLoc(), [&] {
+        Body = getDerived().TransformLambdaBody(E, E->getBody());
+      });
+    }
 
     getSema().popCodeSynthesisContext();
   }
diff --git a/clang/test/SemaTemplate/stack-exhaustion.cpp 
b/clang/test/SemaTemplate/stack-exhaustion.cpp
index c7bfea4132d5e..2883d71f66d60 100644
--- a/clang/test/SemaTemplate/stack-exhaustion.cpp
+++ b/clang/test/SemaTemplate/stack-exhaustion.cpp
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -verify %s -DTEST=1
 // RUN: %clang_cc1 -verify %s -DTEST=2
 // RUN: %clang_cc1 -verify %s -DTEST=3
+// RUN: %clang_cc1 -verify %s -DTEST=4 -std=c++20
 // REQUIRES: thread_support
 
 // FIXME: Detection of, or recovery from, stack exhaustion does not work on
@@ -60,6 +61,31 @@ namespace template_parameter_type_recursion {
   void printFunctionalType(ostream &os, mlir::Value &v) { os << v; }
 }
 
+#elif TEST == 4
+
+// Test for recursive lambdas in templates (GitHub issue #180319)
+// This should not crash with a stack overflow.
+namespace recursive_lambda_template {
+  struct foo_tag {};
+  template<class T> struct foo {
+    using tag = foo_tag;
+    T run;
+  };
+  template<class T> concept isFoo = requires(T a) { a.run(); };
+
+  template<int i, class T> auto complexify(T a) requires isFoo<T> {
+    if constexpr (i > 0) {
+      return complexify<i-1>(foo{ [a]{
+        return 1+a.run();
+      }});
+    } else return a;
+  }
+
+  // Use a moderate depth that would previously cause stack exhaustion
+  // but should now be handled gracefully.
+  auto result = complexify<200>(foo{[]{ return 1; }});
+}
+
 #else
 #error unknown test
 #endif

``````````

</details>


https://github.com/llvm/llvm-project/pull/180325
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to