1*532dc62bSNikita Popov // RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-unknown-linux-gnu -std=c++20 \
2a9b3d097SEric Fiselier // RUN: -Wno-coroutine-missing-unhandled-exception -emit-llvm %s -o - -disable-llvm-passes \
3a9b3d097SEric Fiselier // RUN: | FileCheck %s
48df64e94SGor Nishanov
58df64e94SGor Nishanov namespace std {
68df64e94SGor Nishanov template <typename... T>
78df64e94SGor Nishanov struct coroutine_traits; // expected-note {{declared here}}
86dcb0eb3SGor Nishanov
96dcb0eb3SGor Nishanov template <class Promise = void>
106dcb0eb3SGor Nishanov struct coroutine_handle {
116dcb0eb3SGor Nishanov coroutine_handle() = default;
from_addressstd::coroutine_handle12516803dcSXun Li static coroutine_handle from_address(void *) noexcept { return {}; }
136dcb0eb3SGor Nishanov };
146dcb0eb3SGor Nishanov
156dcb0eb3SGor Nishanov template <>
166dcb0eb3SGor Nishanov struct coroutine_handle<void> {
from_addressstd::coroutine_handle176dcb0eb3SGor Nishanov static coroutine_handle from_address(void *) { return {}; }
186dcb0eb3SGor Nishanov coroutine_handle() = default;
196dcb0eb3SGor Nishanov template <class PromiseType>
coroutine_handlestd::coroutine_handle20516803dcSXun Li coroutine_handle(coroutine_handle<PromiseType>) noexcept {}
216dcb0eb3SGor Nishanov };
226dcb0eb3SGor Nishanov
23f692e7dbSEric Fiselier struct nothrow_t {};
24f692e7dbSEric Fiselier constexpr nothrow_t nothrow = {};
25f692e7dbSEric Fiselier
26f692e7dbSEric Fiselier } // end namespace std
27f692e7dbSEric Fiselier
28f692e7dbSEric Fiselier // Required when get_return_object_on_allocation_failure() is defined by
29f692e7dbSEric Fiselier // the promise.
30f692e7dbSEric Fiselier using SizeT = decltype(sizeof(int));
31f692e7dbSEric Fiselier void* operator new(SizeT __sz, const std::nothrow_t&) noexcept;
32f692e7dbSEric Fiselier void operator delete(void* __p, const std::nothrow_t&) noexcept;
33f692e7dbSEric Fiselier
348df64e94SGor Nishanov
358df64e94SGor Nishanov struct suspend_always {
await_readysuspend_always36516803dcSXun Li bool await_ready() noexcept { return false; }
await_suspendsuspend_always37ec117158SChuanqi Xu void await_suspend(std::coroutine_handle<>) noexcept {}
await_resumesuspend_always38516803dcSXun Li void await_resume() noexcept {}
398df64e94SGor Nishanov };
408df64e94SGor Nishanov
418df64e94SGor Nishanov struct global_new_delete_tag {};
428df64e94SGor Nishanov
438df64e94SGor Nishanov template <>
44ec117158SChuanqi Xu struct std::coroutine_traits<void, global_new_delete_tag> {
458df64e94SGor Nishanov struct promise_type {
get_return_objectstd::coroutine_traits::promise_type468df64e94SGor Nishanov void get_return_object() {}
initial_suspendstd::coroutine_traits::promise_type478df64e94SGor Nishanov suspend_always initial_suspend() { return {}; }
final_suspendstd::coroutine_traits::promise_type48516803dcSXun Li suspend_always final_suspend() noexcept { return {}; }
return_voidstd::coroutine_traits::promise_type498df64e94SGor Nishanov void return_void() {}
508df64e94SGor Nishanov };
518df64e94SGor Nishanov };
528df64e94SGor Nishanov
538df64e94SGor Nishanov // CHECK-LABEL: f0(
f0(global_new_delete_tag)548df64e94SGor Nishanov extern "C" void f0(global_new_delete_tag) {
558df64e94SGor Nishanov // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
56aa6e9a99SGor Nishanov // CHECK: %[[NeedAlloc:.+]] = call i1 @llvm.coro.alloc(token %[[ID]])
57aa6e9a99SGor Nishanov // CHECK: br i1 %[[NeedAlloc]], label %[[AllocBB:.+]], label %[[InitBB:.+]]
58aa6e9a99SGor Nishanov
59aa6e9a99SGor Nishanov // CHECK: [[AllocBB]]:
608df64e94SGor Nishanov // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
611b1c8d83Shyeongyu kim // CHECK: %[[MEM:.+]] = call noalias noundef nonnull i8* @_Znwm(i64 noundef %[[SIZE]])
62aa6e9a99SGor Nishanov // CHECK: br label %[[InitBB]]
63aa6e9a99SGor Nishanov
64aa6e9a99SGor Nishanov // CHECK: [[InitBB]]:
65aa6e9a99SGor Nishanov // CHECK: %[[PHI:.+]] = phi i8* [ null, %{{.+}} ], [ %call, %[[AllocBB]] ]
6668fe6ee7SGor Nishanov // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(token %[[ID]], i8* %[[PHI]])
678df64e94SGor Nishanov
688df64e94SGor Nishanov // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
696c4530c6SGor Nishanov // CHECK: %[[NeedDealloc:.+]] = icmp ne i8* %[[MEM]], null
706c4530c6SGor Nishanov // CHECK: br i1 %[[NeedDealloc]], label %[[FreeBB:.+]], label %[[Afterwards:.+]]
716c4530c6SGor Nishanov
726c4530c6SGor Nishanov // CHECK: [[FreeBB]]:
731b1c8d83Shyeongyu kim // CHECK: call void @_ZdlPv(i8* noundef %[[MEM]])
746c4530c6SGor Nishanov // CHECK: br label %[[Afterwards]]
756c4530c6SGor Nishanov
766c4530c6SGor Nishanov // CHECK: [[Afterwards]]:
776c4530c6SGor Nishanov // CHECK: ret void
7890be1213SGor Nishanov co_return;
798df64e94SGor Nishanov }
808df64e94SGor Nishanov
818df64e94SGor Nishanov struct promise_new_tag {};
828df64e94SGor Nishanov
838df64e94SGor Nishanov template <>
84ec117158SChuanqi Xu struct std::coroutine_traits<void, promise_new_tag> {
858df64e94SGor Nishanov struct promise_type {
868df64e94SGor Nishanov void *operator new(unsigned long);
get_return_objectstd::coroutine_traits::promise_type878df64e94SGor Nishanov void get_return_object() {}
initial_suspendstd::coroutine_traits::promise_type888df64e94SGor Nishanov suspend_always initial_suspend() { return {}; }
final_suspendstd::coroutine_traits::promise_type89516803dcSXun Li suspend_always final_suspend() noexcept { return {}; }
return_voidstd::coroutine_traits::promise_type908df64e94SGor Nishanov void return_void() {}
918df64e94SGor Nishanov };
928df64e94SGor Nishanov };
938df64e94SGor Nishanov
948df64e94SGor Nishanov // CHECK-LABEL: f1(
f1(promise_new_tag)958df64e94SGor Nishanov extern "C" void f1(promise_new_tag ) {
968df64e94SGor Nishanov // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
978df64e94SGor Nishanov // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
981b1c8d83Shyeongyu kim // CHECK: call noundef i8* @_ZNSt16coroutine_traitsIJv15promise_new_tagEE12promise_typenwEm(i64 noundef %[[SIZE]])
998df64e94SGor Nishanov
10068fe6ee7SGor Nishanov // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
1018df64e94SGor Nishanov // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
1021b1c8d83Shyeongyu kim // CHECK: call void @_ZdlPv(i8* noundef %[[MEM]])
10390be1213SGor Nishanov co_return;
1048df64e94SGor Nishanov }
1058df64e94SGor Nishanov
10698606221SBrian Gesiak struct promise_matching_placement_new_tag {};
10798606221SBrian Gesiak
10898606221SBrian Gesiak template <>
109ec117158SChuanqi Xu struct std::coroutine_traits<void, promise_matching_placement_new_tag, int, float, double> {
11098606221SBrian Gesiak struct promise_type {
11198606221SBrian Gesiak void *operator new(unsigned long, promise_matching_placement_new_tag,
11298606221SBrian Gesiak int, float, double);
get_return_objectstd::coroutine_traits::promise_type11398606221SBrian Gesiak void get_return_object() {}
initial_suspendstd::coroutine_traits::promise_type11498606221SBrian Gesiak suspend_always initial_suspend() { return {}; }
final_suspendstd::coroutine_traits::promise_type115516803dcSXun Li suspend_always final_suspend() noexcept { return {}; }
return_voidstd::coroutine_traits::promise_type11698606221SBrian Gesiak void return_void() {}
11798606221SBrian Gesiak };
11898606221SBrian Gesiak };
11998606221SBrian Gesiak
12098606221SBrian Gesiak // CHECK-LABEL: f1a(
f1a(promise_matching_placement_new_tag,int x,float y,double z)12198606221SBrian Gesiak extern "C" void f1a(promise_matching_placement_new_tag, int x, float y , double z) {
12298606221SBrian Gesiak // CHECK: store i32 %x, i32* %x.addr, align 4
12398606221SBrian Gesiak // CHECK: store float %y, float* %y.addr, align 4
12498606221SBrian Gesiak // CHECK: store double %z, double* %z.addr, align 8
12598606221SBrian Gesiak // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
12698606221SBrian Gesiak // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
12798606221SBrian Gesiak // CHECK: %[[INT:.+]] = load i32, i32* %x.addr, align 4
12898606221SBrian Gesiak // CHECK: %[[FLOAT:.+]] = load float, float* %y.addr, align 4
12998606221SBrian Gesiak // CHECK: %[[DOUBLE:.+]] = load double, double* %z.addr, align 8
1301b1c8d83Shyeongyu kim // CHECK: call noundef i8* @_ZNSt16coroutine_traitsIJv34promise_matching_placement_new_tagifdEE12promise_typenwEmS0_ifd(i64 noundef %[[SIZE]], i32 noundef %[[INT]], float noundef %[[FLOAT]], double noundef %[[DOUBLE]])
13198606221SBrian Gesiak co_return;
13298606221SBrian Gesiak }
13398606221SBrian Gesiak
134cb024024SBrian Gesiak // Declare a placement form operator new, such as the one described in
135cb024024SBrian Gesiak // C++ 18.6.1.3.1, which takes a void* argument.
136cb024024SBrian Gesiak void* operator new(SizeT __sz, void *__p) noexcept;
137cb024024SBrian Gesiak
138cb024024SBrian Gesiak struct promise_matching_global_placement_new_tag {};
139cb024024SBrian Gesiak struct dummy {};
140cb024024SBrian Gesiak template <>
141ec117158SChuanqi Xu struct std::coroutine_traits<void, promise_matching_global_placement_new_tag, dummy *> {
142cb024024SBrian Gesiak struct promise_type {
get_return_objectstd::coroutine_traits::promise_type143cb024024SBrian Gesiak void get_return_object() {}
initial_suspendstd::coroutine_traits::promise_type144cb024024SBrian Gesiak suspend_always initial_suspend() { return {}; }
final_suspendstd::coroutine_traits::promise_type145516803dcSXun Li suspend_always final_suspend() noexcept { return {}; }
return_voidstd::coroutine_traits::promise_type146cb024024SBrian Gesiak void return_void() {}
147cb024024SBrian Gesiak };
148cb024024SBrian Gesiak };
149cb024024SBrian Gesiak
150cb024024SBrian Gesiak // A coroutine that takes a single pointer argument should not invoke this
151cb024024SBrian Gesiak // placement form operator. [dcl.fct.def.coroutine]/7 dictates that lookup for
152cb024024SBrian Gesiak // allocation functions matching the coroutine function's signature be done
153cb024024SBrian Gesiak // within the scope of the promise type's class.
154cb024024SBrian Gesiak // CHECK-LABEL: f1b(
f1b(promise_matching_global_placement_new_tag,dummy *)155cb024024SBrian Gesiak extern "C" void f1b(promise_matching_global_placement_new_tag, dummy *) {
1561b1c8d83Shyeongyu kim // CHECK: call noalias noundef nonnull i8* @_Znwm(i64
157cb024024SBrian Gesiak co_return;
158cb024024SBrian Gesiak }
159cb024024SBrian Gesiak
1608df64e94SGor Nishanov struct promise_delete_tag {};
1618df64e94SGor Nishanov
1628df64e94SGor Nishanov template <>
163ec117158SChuanqi Xu struct std::coroutine_traits<void, promise_delete_tag> {
1648df64e94SGor Nishanov struct promise_type {
1658df64e94SGor Nishanov void operator delete(void*);
get_return_objectstd::coroutine_traits::promise_type1668df64e94SGor Nishanov void get_return_object() {}
initial_suspendstd::coroutine_traits::promise_type1678df64e94SGor Nishanov suspend_always initial_suspend() { return {}; }
final_suspendstd::coroutine_traits::promise_type168516803dcSXun Li suspend_always final_suspend() noexcept { return {}; }
return_voidstd::coroutine_traits::promise_type1698df64e94SGor Nishanov void return_void() {}
1708df64e94SGor Nishanov };
1718df64e94SGor Nishanov };
1728df64e94SGor Nishanov
1738df64e94SGor Nishanov // CHECK-LABEL: f2(
f2(promise_delete_tag)1748df64e94SGor Nishanov extern "C" void f2(promise_delete_tag) {
1758df64e94SGor Nishanov // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
1768df64e94SGor Nishanov // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
1771b1c8d83Shyeongyu kim // CHECK: call noalias noundef nonnull i8* @_Znwm(i64 noundef %[[SIZE]])
1788df64e94SGor Nishanov
17968fe6ee7SGor Nishanov // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
1808df64e94SGor Nishanov // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
1811b1c8d83Shyeongyu kim // CHECK: call void @_ZNSt16coroutine_traitsIJv18promise_delete_tagEE12promise_typedlEPv(i8* noundef %[[MEM]])
18290be1213SGor Nishanov co_return;
1838df64e94SGor Nishanov }
1848df64e94SGor Nishanov
1858df64e94SGor Nishanov struct promise_sized_delete_tag {};
1868df64e94SGor Nishanov
1878df64e94SGor Nishanov template <>
188ec117158SChuanqi Xu struct std::coroutine_traits<void, promise_sized_delete_tag> {
1898df64e94SGor Nishanov struct promise_type {
1908df64e94SGor Nishanov void operator delete(void*, unsigned long);
get_return_objectstd::coroutine_traits::promise_type1918df64e94SGor Nishanov void get_return_object() {}
initial_suspendstd::coroutine_traits::promise_type1928df64e94SGor Nishanov suspend_always initial_suspend() { return {}; }
final_suspendstd::coroutine_traits::promise_type193516803dcSXun Li suspend_always final_suspend() noexcept { return {}; }
return_voidstd::coroutine_traits::promise_type1948df64e94SGor Nishanov void return_void() {}
1958df64e94SGor Nishanov };
1968df64e94SGor Nishanov };
1978df64e94SGor Nishanov
1988df64e94SGor Nishanov // CHECK-LABEL: f3(
f3(promise_sized_delete_tag)1998df64e94SGor Nishanov extern "C" void f3(promise_sized_delete_tag) {
2008df64e94SGor Nishanov // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
2018df64e94SGor Nishanov // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
2021b1c8d83Shyeongyu kim // CHECK: call noalias noundef nonnull i8* @_Znwm(i64 noundef %[[SIZE]])
2038df64e94SGor Nishanov
20468fe6ee7SGor Nishanov // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
2058df64e94SGor Nishanov // CHECK: %[[MEM:.+]] = call i8* @llvm.coro.free(token %[[ID]], i8* %[[FRAME]])
2068df64e94SGor Nishanov // CHECK: %[[SIZE2:.+]] = call i64 @llvm.coro.size.i64()
2071b1c8d83Shyeongyu kim // CHECK: call void @_ZNSt16coroutine_traitsIJv24promise_sized_delete_tagEE12promise_typedlEPvm(i8* noundef %[[MEM]], i64 noundef %[[SIZE2]])
2083aa9eb38SGor Nishanov co_return;
2093aa9eb38SGor Nishanov }
2103aa9eb38SGor Nishanov
2113aa9eb38SGor Nishanov struct promise_on_alloc_failure_tag {};
2123aa9eb38SGor Nishanov
2133aa9eb38SGor Nishanov template <>
214ec117158SChuanqi Xu struct std::coroutine_traits<int, promise_on_alloc_failure_tag> {
2153aa9eb38SGor Nishanov struct promise_type {
get_return_objectstd::coroutine_traits::promise_type216a9b3d097SEric Fiselier int get_return_object() { return 0; }
initial_suspendstd::coroutine_traits::promise_type2173aa9eb38SGor Nishanov suspend_always initial_suspend() { return {}; }
final_suspendstd::coroutine_traits::promise_type218516803dcSXun Li suspend_always final_suspend() noexcept { return {}; }
return_voidstd::coroutine_traits::promise_type2193aa9eb38SGor Nishanov void return_void() {}
get_return_object_on_allocation_failurestd::coroutine_traits::promise_type2203aa9eb38SGor Nishanov static int get_return_object_on_allocation_failure() { return -1; }
2213aa9eb38SGor Nishanov };
2223aa9eb38SGor Nishanov };
2233aa9eb38SGor Nishanov
2243aa9eb38SGor Nishanov // CHECK-LABEL: f4(
f4(promise_on_alloc_failure_tag)2253aa9eb38SGor Nishanov extern "C" int f4(promise_on_alloc_failure_tag) {
2266a470689SGor Nishanov // CHECK: %[[RetVal:.+]] = alloca i32
2273aa9eb38SGor Nishanov // CHECK: %[[ID:.+]] = call token @llvm.coro.id(i32 16
2283aa9eb38SGor Nishanov // CHECK: %[[SIZE:.+]] = call i64 @llvm.coro.size.i64()
2291b1c8d83Shyeongyu kim // CHECK: %[[MEM:.+]] = call noalias noundef i8* @_ZnwmRKSt9nothrow_t(i64 noundef %[[SIZE]], %"struct.std::nothrow_t"* noundef nonnull align 1 dereferenceable(1) @_ZStL7nothrow)
2303aa9eb38SGor Nishanov // CHECK: %[[OK:.+]] = icmp ne i8* %[[MEM]], null
2313aa9eb38SGor Nishanov // CHECK: br i1 %[[OK]], label %[[OKBB:.+]], label %[[ERRBB:.+]]
2323aa9eb38SGor Nishanov
2333aa9eb38SGor Nishanov // CHECK: [[ERRBB]]:
2341b1c8d83Shyeongyu kim // CHECK: %[[FailRet:.+]] = call noundef i32 @_ZNSt16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type39get_return_object_on_allocation_failureEv(
2356a470689SGor Nishanov // CHECK: store i32 %[[FailRet]], i32* %[[RetVal]]
2366a470689SGor Nishanov // CHECK: br label %[[RetBB:.+]]
2376a470689SGor Nishanov
2386a470689SGor Nishanov // CHECK: [[OKBB]]:
2391b1c8d83Shyeongyu kim // CHECK: %[[OkRet:.+]] = call noundef i32 @_ZNSt16coroutine_traitsIJi28promise_on_alloc_failure_tagEE12promise_type17get_return_objectEv(
2406a470689SGor Nishanov
2416a470689SGor Nishanov // CHECK: [[RetBB]]:
2426a470689SGor Nishanov // CHECK: %[[LoadRet:.+]] = load i32, i32* %[[RetVal]], align 4
2436a470689SGor Nishanov // CHECK: ret i32 %[[LoadRet]]
24490be1213SGor Nishanov co_return;
2458df64e94SGor Nishanov }
246