[clang] 09231ed - [clang] Delay dependent co_return promise calls (#218779)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 31 05:58:03 PDT 2026
Author: Kunal Dubey
Date: 2026-08-31T14:57:55+02:00
New Revision: 09231ed02384f388ae5b87b9d89b804d8e94babf
URL: https://github.com/llvm/llvm-project/commit/09231ed02384f388ae5b87b9d89b804d8e94babf
DIFF: https://github.com/llvm/llvm-project/commit/09231ed02384f388ae5b87b9d89b804d8e94babf.diff
LOG: [clang] Delay dependent co_return promise calls (#218779)
Avoiding selection of return_value or return_void while building
co_return whose operand is type-dependent and keeping it unset until
template init rebuild for a type allows dependent operations like
co_return ctx.f(v) to use promise.return_void() instead of needing
promise.return_value().
Fixes #218368
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/Analysis/CFG.cpp
clang/lib/Sema/SemaCoroutine.cpp
clang/test/SemaCXX/coreturn.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 053a132e2408a..dd3dfdc5ad8d7 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -542,6 +542,10 @@ features cannot lower the translation-unit ABI level;
using ``__is_constructible`` on a nested class template inside the definition
of the containing class. (#GH215166)
+- Fixed a bug where Clang incorrectly required `promise.return_value()` for a
+ dependent `co_return` operand that inits to `void`, instead of using
+ `promise.return_void()`. (#GH218368)
+
- Fixed merging of lambdas across modules in the case where neither lambda is
imported from an AST file. (#GH214560)
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 5263114ebca28..5aaaf5a8c33a8 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -3432,8 +3432,9 @@ CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
CoreturnStmt *CRS = cast<CoreturnStmt>(S);
auto *B = Block;
- if (CFGBlock *R = Visit(CRS->getPromiseCall()))
- B = R;
+ if (Expr *PromiseCall = CRS->getPromiseCall())
+ if (CFGBlock *R = Visit(PromiseCall))
+ B = R;
if (Expr *RV = CRS->getOperand())
if (RV->getType()->isVoidType() && !isa<InitListExpr>(RV))
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 627ed96522025..b46efba09500f 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -1055,6 +1055,13 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
E = R.get();
}
+ // 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())
+ return new (Context)
+ CoreturnStmt(Loc, E, /*PromiseCall=*/nullptr, IsImplicit);
+
VarDecl *Promise = FSI->CoroutinePromise;
ExprResult PC;
if (E && (isa<InitListExpr>(E) || !E->getType()->isVoidType())) {
diff --git a/clang/test/SemaCXX/coreturn.cpp b/clang/test/SemaCXX/coreturn.cpp
index 7069a1040db23..8fb2506848c3d 100644
--- a/clang/test/SemaCXX/coreturn.cpp
+++ b/clang/test/SemaCXX/coreturn.cpp
@@ -138,3 +138,29 @@ VoidTagReturnValue test11(bool b) {
if (b)
co_return 42;
} // expected-warning {{non-void coroutine does not return a value in all control paths}}
+
+namespace dependent_void_coreturn {
+struct coro {
+ struct promise_type {
+ coro get_return_object();
+ suspend_never initial_suspend();
+ suspend_never final_suspend() noexcept;
+ void unhandled_exception();
+ void return_void();
+ };
+};
+
+struct Ctx {
+ template <typename T>
+ T &get();
+ void f(int);
+};
+
+template <typename T>
+coro f(Ctx &ctx) {
+ auto &v = ctx.get<T>();
+ co_return ctx.f(v);
+}
+
+void use(Ctx &ctx) { f<int>(ctx); }
+}
More information about the cfe-commits
mailing list