[clang] [CIR] Add support for coroutine allocation failure (PR #220466)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 2 19:54:53 PDT 2026
https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/220466
>From 9d20cb13fec7b761e98c8aa28ee07e871348ae2a Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Tue, 1 Sep 2026 22:01:28 -0500
Subject: [PATCH 1/3] [CIR] Add support for coroutine allocation failure
---
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 25 +++++-
.../test/CIR/CodeGenCoroutines/coro-alloc.cpp | 78 +++++++++++++++++++
2 files changed, 99 insertions(+), 4 deletions(-)
create mode 100644 clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 7bcaa43bae765..13e06c2b580ab 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/MissingFeatures.h"
@@ -370,16 +371,32 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
loc, emitScalarExpr(s.getAllocate()), storeAddr);
cir::YieldOp::create(builder, loc);
});
+
+ // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
+ if (Stmt *retOnAllocFailure = s.getReturnStmtOnAllocFailure()) {
+
+ mlir::LogicalResult res = mlir::success();
+ mlir::Value isPtrNull = builder.createPtrIsNull(storeAddr);
+
+ assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
+
+ cir::IfOp::create(
+ builder, openCurlyLoc, isPtrNull, /*withElseRegion=*/false,
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ res = emitStmt(retOnAllocFailure, /*useCurrentScope=*/true);
+ cir::TrapOp::create(builder, openCurlyLoc);
+ });
+
+ if (res.failed())
+ return res;
+ }
+
curCoro.data->coroBegin = cir::CoroBeginOp::create(
cgm.getBuilder(), openCurlyLoc,
mlir::ValueRange{
curCoro.data->coroId.getResult(),
cir::LoadOp::create(builder, openCurlyLoc, allocaTy, storeAddr)});
- // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
- if (s.getReturnStmtOnAllocFailure())
- cgm.errorNYI("handle coroutine return alloc failure");
-
{
assert(!cir::MissingFeatures::generateDebugInfo());
ParamReferenceReplacerRAII paramReplacer(localDeclMap);
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
new file mode 100644
index 0000000000000..02684a1dbfebf
--- /dev/null
+++ b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=OGCG
+#include "Inputs/coroutine.h"
+namespace std {
+
+struct nothrow_t {};
+constexpr nothrow_t nothrow = {};
+
+} // end namespace std
+
+// Required when get_return_object_on_allocation_failure() is defined by
+// the promise. The nothrow overload prevents allocation failure from
+// throwing std::bad_alloc.
+using SizeT = decltype(sizeof(int));
+void* operator new(SizeT __sz, const std::nothrow_t&) noexcept;
+void operator delete(void* __p, const std::nothrow_t&) noexcept;
+
+struct promise_on_alloc_failure_tag {};
+
+template <>
+struct std::coroutine_traits<int, promise_on_alloc_failure_tag> {
+ struct promise_type {
+ int get_return_object() { return 0; }
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
+ void return_void() {}
+ static int get_return_object_on_allocation_failure() { return -1; }
+ };
+};
+
+int f4(promise_on_alloc_failure_tag) {
+
+ co_return;
+}
+
+// CIR-LABEL: @_Z2f428promise_on_alloc_failure_tag(
+// CIR: %[[RetVal:.*]] = cir.alloca "__retval"
+// CIR: %[[SavedFrameAddr:.*]] = cir.alloca "__coro_frame_addr"
+// CIR: %[[CORO_ID:.*]] = cir.coro.intrinsic.id(
+// CIR: %[[ShouldAlloc:.*]] = cir.coro.intrinsic.alloc(%[[CORO_ID]])
+// CIR: cir.if %[[ShouldAlloc]] {
+// CIR: %[[CORO_SIZE:.*]] = cir.coro.intrinsic.size()
+// CIR: %[[STD_NOTHROW:.*]] = cir.get_global @_ZStL7nothrow
+// CIR: %[[ALLOC_ADDR:.*]] = cir.call @_ZnwmRKSt9nothrow_t(%[[CORO_SIZE]], %[[STD_NOTHROW]])
+// CIR: cir.store %[[ALLOC_ADDR]], %[[SavedFrameAddr]]
+// CIR: }
+// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null>
+// CIR: %[[IS_NULL_PTR:.*]] = cir.cmp eq %[[SavedFrameAddr]], %[[NULL_PTR:.*]]
+// CIR: cir.if %[[IS_NULL_PTR]] {
+// CIR: %[[FailRet:.*]] = cir.call @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv
+// CIR: cir.store %[[FailRet]], %[[RetVal]] : !s32i
+// CIR: %[[RET:.*]] = cir.load %[[RetVal]] : !cir.ptr<!s32i>
+// CIR: cir.return %[[RET]] : !s32i
+// CIR: ^[[UNREACHABLE:.*]]:
+// CIR: cir.trap
+// CIR: }
+
+// OGCG-LABEL: @_Z2f428promise_on_alloc_failure_tag(
+// OGCG: %[[RetVal:.*]] = alloca i32
+// OGCG: %[[ID:.*]] = call token @llvm.coro.id(i32 16
+// OGCG: %[[SIZE:.*]] = call i64 @llvm.coro.size.i64()
+// OGCG: %[[MEM:.*]] = call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef %[[SIZE]], ptr noundef nonnull align 1 dereferenceable(1) @_ZStL7nothrow)
+// OGCG: %[[OK:.*]] = icmp ne ptr %[[MEM]], null
+// OGCG: br i1 %[[OK]], label %[[OKBB:.*]], label %[[ERRBB:.*]]
+
+// OGCG: [[ERRBB]]:
+// OGCG: %[[FailRet:.*]] = call noundef i32 @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv()
+// OGCG: store i32 %[[FailRet]], ptr %[[RetVal]]
+// OGCG: br label %[[RetBB:.*]]
+
+// OGCG: [[OKBB]]:
+// OGCG: %[[OkRet:.*]] = call noundef i32 @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv({{.*}}
+
+// OGCG: [[RetBB]]:
+// OGCG: %[[LoadRet:.*]] = load i32, ptr %[[RetVal]], align 4
+// OGCG: ret i32 %[[LoadRet]]
>From 3988e6aff6b84f60cc0befd12260194de445a0a5 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Tue, 1 Sep 2026 23:39:13 -0500
Subject: [PATCH 2/3] Address review comments
---
clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp | 36 +++++++++----------
.../test/CIR/CodeGenCoroutines/coro-alloc.cpp | 26 +++++++-------
2 files changed, 30 insertions(+), 32 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
index 13e06c2b580ab..4fbede0f88ad4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCoroutine.cpp
@@ -363,33 +363,29 @@ CIRGenFunction::emitCoroutineBody(const CoroutineBodyStmt &s) {
mlir::Value storeAddr = coroFrame.getPointer();
builder.CIRBaseBuilderTy::createStore(openCurlyLoc, nullPtrCst, storeAddr);
+ mlir::LogicalResult res = mlir::success();
cir::IfOp::create(
builder, openCurlyLoc, coroAlloc.getResult(),
/*withElseRegion=*/false,
/*thenBuilder=*/[&](mlir::OpBuilder &b, mlir::Location loc) {
- builder.CIRBaseBuilderTy::createStore(
- loc, emitScalarExpr(s.getAllocate()), storeAddr);
+ mlir::Value allocatedPtr = emitScalarExpr(s.getAllocate());
+ builder.CIRBaseBuilderTy::createStore(loc, allocatedPtr, storeAddr);
+ // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
+ if (Stmt *retOnAllocFailure = s.getReturnStmtOnAllocFailure()) {
+ mlir::Value isPtrNull = builder.createPtrIsNull(allocatedPtr);
+ assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
+ cir::IfOp::create(builder, loc, isPtrNull, /*withElseRegion=*/false,
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ res = emitStmt(retOnAllocFailure,
+ /*useCurrentScope=*/true);
+ cir::UnreachableOp::create(builder, loc);
+ });
+ }
cir::YieldOp::create(builder, loc);
});
- // Handle allocation failure if 'ReturnStmtOnAllocFailure' was provided.
- if (Stmt *retOnAllocFailure = s.getReturnStmtOnAllocFailure()) {
-
- mlir::LogicalResult res = mlir::success();
- mlir::Value isPtrNull = builder.createPtrIsNull(storeAddr);
-
- assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
-
- cir::IfOp::create(
- builder, openCurlyLoc, isPtrNull, /*withElseRegion=*/false,
- [&](mlir::OpBuilder &b, mlir::Location loc) {
- res = emitStmt(retOnAllocFailure, /*useCurrentScope=*/true);
- cir::TrapOp::create(builder, openCurlyLoc);
- });
-
- if (res.failed())
- return res;
- }
+ if (res.failed())
+ return res;
curCoro.data->coroBegin = cir::CoroBeginOp::create(
cgm.getBuilder(), openCurlyLoc,
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
index 02684a1dbfebf..1c7bc9b4797c9 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
@@ -37,24 +37,26 @@ int f4(promise_on_alloc_failure_tag) {
// CIR-LABEL: @_Z2f428promise_on_alloc_failure_tag(
// CIR: %[[RetVal:.*]] = cir.alloca "__retval"
-// CIR: %[[SavedFrameAddr:.*]] = cir.alloca "__coro_frame_addr"
+// CIR: %[[FrameAddr:.*]] = cir.alloca "__coro_frame_addr"
+// CIR: %[[NULL_INIT:.*]] = cir.const #cir.ptr<null>
// CIR: %[[CORO_ID:.*]] = cir.coro.intrinsic.id(
// CIR: %[[ShouldAlloc:.*]] = cir.coro.intrinsic.alloc(%[[CORO_ID]])
+// CIR: cir.store %[[NULL_INIT]], %[[FrameAddr]]
// CIR: cir.if %[[ShouldAlloc]] {
// CIR: %[[CORO_SIZE:.*]] = cir.coro.intrinsic.size()
// CIR: %[[STD_NOTHROW:.*]] = cir.get_global @_ZStL7nothrow
// CIR: %[[ALLOC_ADDR:.*]] = cir.call @_ZnwmRKSt9nothrow_t(%[[CORO_SIZE]], %[[STD_NOTHROW]])
-// CIR: cir.store %[[ALLOC_ADDR]], %[[SavedFrameAddr]]
-// CIR: }
-// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null>
-// CIR: %[[IS_NULL_PTR:.*]] = cir.cmp eq %[[SavedFrameAddr]], %[[NULL_PTR:.*]]
-// CIR: cir.if %[[IS_NULL_PTR]] {
-// CIR: %[[FailRet:.*]] = cir.call @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv
-// CIR: cir.store %[[FailRet]], %[[RetVal]] : !s32i
-// CIR: %[[RET:.*]] = cir.load %[[RetVal]] : !cir.ptr<!s32i>
-// CIR: cir.return %[[RET]] : !s32i
-// CIR: ^[[UNREACHABLE:.*]]:
-// CIR: cir.trap
+// CIR: cir.store %[[ALLOC_ADDR]], %[[FrameAddr]]
+// CIR: %[[NULL_PTR:.*]] = cir.const #cir.ptr<null>
+// CIR: %[[IS_NULL_PTR:.*]] = cir.cmp eq %[[ALLOC_ADDR]], %[[NULL_PTR]]
+// CIR: cir.if %[[IS_NULL_PTR]] {
+// CIR: %[[FailRet:.*]] = cir.call @_ZNSt16coroutine_traitsIiJ28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv
+// CIR: cir.store %[[FailRet]], %[[RetVal]] : !s32i
+// CIR: %[[RET:.*]] = cir.load %[[RetVal]] : !cir.ptr<!s32i>
+// CIR: cir.return %[[RET]] : !s32i
+// CIR: ^[[UNREACHABLE:.*]]:
+// CIR: cir.unreachable
+// CIR: }
// CIR: }
// OGCG-LABEL: @_Z2f428promise_on_alloc_failure_tag(
>From 2dc20e008926f54914bb84c8b3d681cca76620a2 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 2 Sep 2026 16:58:59 -0500
Subject: [PATCH 3/3] Address review comments
---
clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
index 1c7bc9b4797c9..bb0d27af57271 100644
--- a/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
+++ b/clang/test/CIR/CodeGenCoroutines/coro-alloc.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-call-conv-lowering -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir
+// TODO(cir): drop -fno-clangir-call-conv-lowering once CallConvLowering
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -Wno-coroutine-missing-unhandled-exception -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm -disable-llvm-passes -Wno-coroutine-missing-unhandled-exception %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=OGCG
More information about the cfe-commits
mailing list