1 // Test for PR56919. Tests the destroy function contains the call to delete function only.
3 // REQUIRES: x86-registered-target
5 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 %s -O3 -S -o - | FileCheck %s
7 #include "Inputs/coroutine.h"
11 template <typename T
> struct remove_reference
{ using type
= T
; };
12 template <typename T
> struct remove_reference
<T
&> { using type
= T
; };
13 template <typename T
> struct remove_reference
<T
&&> { using type
= T
; };
16 constexpr typename
std::remove_reference
<T
>::type
&& move(T
&&t
) noexcept
{
17 return static_cast<typename
std::remove_reference
<T
>::type
&&>(t
);
27 class promise_type final
{
29 Task
<void> get_return_object() { return Task
<void>(std::coroutine_handle
<promise_type
>::from_promise(*this)); }
31 void unhandled_exception() {}
33 std::suspend_always
initial_suspend() { return {}; }
35 auto await_transform(Task
<void> co
) {
36 return await_transform(std::move(co
.handle_
.promise()));
39 auto await_transform(promise_type
&& awaited
) {
41 promise_type
&& awaited
;
43 bool await_ready() { return false; }
45 std::coroutine_handle
<> await_suspend(
46 const std::coroutine_handle
<> handle
) {
47 // Register our handle to be resumed once the awaited promise's coroutine
48 // finishes, and then resume that coroutine.
49 awaited
.registered_handle_
= handle
;
50 return std::coroutine_handle
<promise_type
>::from_promise(awaited
);
53 void await_resume() {}
58 return Awaitable
{std::move(awaited
)};
63 // At final suspend resume our registered handle.
64 auto final_suspend() noexcept
{
65 struct FinalSuspendAwaitable final
{
66 bool await_ready() noexcept
{ return false; }
68 std::coroutine_handle
<> await_suspend(
69 std::coroutine_handle
<> h
) noexcept
{
73 void await_resume() noexcept
{}
75 std::coroutine_handle
<> to_resume
;
78 return FinalSuspendAwaitable
{registered_handle_
};
82 std::coroutine_handle
<promise_type
> my_handle() {
83 return std::coroutine_handle
<promise_type
>::from_promise(*this);
86 std::coroutine_handle
<> registered_handle_
;
90 // Teach llvm that we are only ever destroyed when the coroutine body is done,
91 // so there is no need for the jump table in the destroy function. Our coroutine
92 // library doesn't expose handles to the user, so we know this constraint isn't
94 if (!handle_
.done()) {
95 __builtin_unreachable();
102 explicit Task(const std::coroutine_handle
<promise_type
> handle
)
105 const std::coroutine_handle
<promise_type
> handle_
;
108 Task
<void> Qux() { co_return
; }
109 Task
<void> Baz() { co_await
Qux(); }
110 Task
<void> Bar() { co_await
Baz(); }
112 // CHECK: _Z3Quxv.destroy:{{.*}}
114 // CHECK-NEXT: movl $40, %esi
115 // CHECK-NEXT: jmp _ZdlPvm@PLT
117 // CHECK: _Z3Bazv.destroy:{{.*}}
119 // CHECK-NEXT: movl $80, %esi
120 // CHECK-NEXT: jmp _ZdlPvm
122 // CHECK: _Z3Barv.destroy:{{.*}}
124 // CHECK-NEXT: movl $120, %esi
125 // CHECK-NEXT: jmp _ZdlPvm