xref: /llvm-project/clang/test/CodeGenCoroutines/coro-destructor-of-final_suspend.cpp (revision 7c1d9b15eee3a34678addab2bab66f3020ac0753)
1 // This addresses https://github.com/llvm/llvm-project/issues/57339
2 // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fcxx-exceptions \
3 // RUN:     -fexceptions -emit-llvm -o - %s -O1 | FileCheck %s
4 
5 #include "Inputs/coroutine.h"
6 
7 struct gen {
8   struct promise_type {
get_return_objectgen::promise_type9     gen get_return_object() noexcept {
10       return gen{std::coroutine_handle<promise_type>::from_promise(*this)};
11     }
initial_suspendgen::promise_type12     std::suspend_always initial_suspend() noexcept { return {}; }
13 
14     struct final_awaiter {
15       ~final_awaiter() noexcept;
await_readygen::promise_type::final_awaiter16       bool await_ready() noexcept {
17         return false;
18       }
await_suspendgen::promise_type::final_awaiter19       void await_suspend(std::coroutine_handle<>) noexcept {}
await_resumegen::promise_type::final_awaiter20       void await_resume() noexcept {}
21     };
22 
final_suspendgen::promise_type23     final_awaiter final_suspend() noexcept {
24       return {};
25     }
26 
unhandled_exceptiongen::promise_type27     void unhandled_exception() {
28       throw;
29     }
return_voidgen::promise_type30     void return_void() {}
31   };
32 
gengen33   gen(std::coroutine_handle<promise_type> coro) noexcept
34   : coro(coro)
35   {
36   }
37 
~gengen38   ~gen() noexcept {
39     if (coro) {
40       coro.destroy();
41     }
42   }
43 
gengen44   gen(gen&& g) noexcept
45   : coro(g.coro)
46   {
47     g.coro = {};
48   }
49 
50   std::coroutine_handle<promise_type> coro;
51 };
52 
53 struct X {};
54 
maybe_throwing(bool x)55 gen maybe_throwing(bool x) {
56   if (x) {
57     throw X{};
58   }
59   co_return;
60 }
61 
62 // CHECK: define{{.*}}@_Z14maybe_throwingb.destroy
63 // CHECK: %[[INDEX:.+]] = load i1, ptr %index.addr, align 1
64 // CHECK: br i1 %[[INDEX]], label %[[AFTERSUSPEND:.+]], label %[[CORO_FREE:.+]]
65 // CHECK: [[AFTERSUSPEND]]:
66 // CHECK: call{{.*}}_ZN3gen12promise_type13final_awaiterD1Ev(
67 // CHECK: [[CORO_FREE]]:
68 // CHECK: call{{.*}}_ZdlPv
69 
70 void noexcept_call() noexcept;
71 
no_throwing()72 gen no_throwing() {
73   noexcept_call();
74   co_return;
75 }
76 
77 // CHECK: define{{.*}}@_Z11no_throwingv.resume({{.*}}%[[ARG:.+]])
78 // CHECK: resume:
79 // CHECK:   call{{.*}}@_Z13noexcept_callv()
80 // CHECK:   store ptr null, ptr %[[ARG]]
81 // CHECK:   ret void
82 
83 // CHECK: define{{.*}}@_Z11no_throwingv.destroy({{.*}}%[[ARG:.+]])
84 // CHECK: %[[RESUME_FN_ADDR:.+]] = load ptr, ptr %[[ARG]]
85 // CHECK: %[[IF_NULL:.+]] = icmp eq ptr %[[RESUME_FN_ADDR]], null
86 // CHECK: br i1 %[[IF_NULL]], label %[[AFTERSUSPEND:.+]], label %[[CORO_FREE:.+]]
87 // CHECK: [[AFTERSUSPEND]]:
88 // CHECK: call{{.*}}_ZN3gen12promise_type13final_awaiterD1Ev(
89 // CHECK: [[CORO_FREE]]:
90 // CHECK: call{{.*}}_ZdlPv
91