https://github.com/avikivity updated 
https://github.com/llvm/llvm-project/pull/220234

>From f1b9749942d9b4b30ec36604088be49130d655da Mon Sep 17 00:00:00 2001
From: Avi Kivity <[email protected]>
Date: Tue, 1 Sep 2026 15:25:40 +0300
Subject: [PATCH] [clang] Fix lost lambda capture in dependent co_return
 operand

09231ed02384 ("[clang] Delay dependent co_return promise calls") made
Sema::BuildCoreturnStmt return early for a type-dependent operand, before
reaching the ActOnFinishFullExpr() call that every other path performs.

Inside a lambda, a reference to a variable of an enclosing function is not
captured immediately: DoMarkPotentialCapture() only records it via
LambdaScopeInfo::addPotentialCapture(), and relies on ActOnFinishFullExpr()
to turn it into an actual capture and odr-use. Skipping that on the
dependent path silently drops the pending capture, so a variable mentioned
only in the operand of a dependent co_return never gets a capture field.
When the generic lambda's call operator is later instantiated from another
context, Sema tries to capture the variable again and rejects valid code
with "reference to local variable 'p' declared in enclosing function".

Finish the full-expression on the dependent path as well.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

Fixes #220233
---
 clang/lib/Sema/SemaCoroutine.cpp | 10 ++++--
 clang/test/SemaCXX/coreturn.cpp  | 53 ++++++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index b46efba09500f..d22260b887415 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -1058,9 +1058,15 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, 
Expr *E,
   // A type-dependent operand can init to either void or non-void.
   // Delay selecting return_void or return_value until template init
   // rebuilds the co_return statement with the operand type.
-  if (E && !isa<InitListExpr>(E) && E->isTypeDependent())
+  if (E && !isa<InitListExpr>(E) && E->isTypeDependent()) {
+    // Still finish the full-expression, so that potential captures in the
+    // operand are turned into actual captures of the enclosing lambda.
+    ExprResult FE = ActOnFinishFullExpr(E, /*DiscardedValue=*/false);
+    if (FE.isInvalid())
+      return StmtError();
     return new (Context)
-        CoreturnStmt(Loc, E, /*PromiseCall=*/nullptr, IsImplicit);
+        CoreturnStmt(Loc, FE.get(), /*PromiseCall=*/nullptr, IsImplicit);
+  }
 
   VarDecl *Promise = FSI->CoroutinePromise;
   ExprResult PC;
diff --git a/clang/test/SemaCXX/coreturn.cpp b/clang/test/SemaCXX/coreturn.cpp
index 8fb2506848c3d..bfb274c5693c6 100644
--- a/clang/test/SemaCXX/coreturn.cpp
+++ b/clang/test/SemaCXX/coreturn.cpp
@@ -164,3 +164,56 @@ coro f(Ctx &ctx) {
 
 void use(Ctx &ctx) { f<int>(ctx); }
 }
+
+namespace dependent_coreturn_lambda_capture {
+// A variable of the enclosing function referenced only from the type-dependent
+// operand of a co_return must still be captured by the enclosing lambda.
+struct coro_void {
+  struct promise_type {
+    coro_void get_return_object();
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+    void unhandled_exception();
+    void return_void();
+  };
+};
+
+struct coro_value {
+  struct promise_type {
+    coro_value get_return_object();
+    suspend_never initial_suspend();
+    suspend_never final_suspend() noexcept;
+    void unhandled_exception();
+    void return_value(int);
+  };
+};
+
+template <typename T> void use_void(int &, T);
+template <typename T> int use_value(int &, T);
+
+// Instantiates the generic lambda from a context that no longer has the
+// enclosing function's scopes on the stack.
+template <typename F> void call(F f) {
+  int t = 0;
+  f(t);
+}
+
+void captured_by_dependent_coreturn(int p) {
+  call([&](auto &t) -> coro_void {
+    if (t)
+      co_return;
+    co_return use_void(p, t);
+  });
+  call([&](auto &t) -> coro_value {
+    if (t)
+      co_return 0;
+    co_return use_value(p, t);
+  });
+  // Same, but the co_return is reached after a co_await rather than after
+  // another co_return.
+  call([&](auto &t) -> coro_void {
+    co_await suspend_never{};
+    co_return use_void(p, t);
+  });
+}
+} // namespace dependent_coreturn_lambda_capture

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

Reply via email to