xref: /llvm-project/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp (revision 12d24e0c56a154c88247e55c7c352030e4d9073d)
1 // RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
2 
3 #include "Inputs/coroutine.h"
4 
5 struct Printy {
PrintyPrinty6   Printy(const char *name) : name(name) {}
~PrintyPrinty7   ~Printy() {}
8   const char *name;
9 };
10 
11 struct coroutine {
12   struct promise_type;
13   std::coroutine_handle<promise_type> handle;
~coroutinecoroutine14   ~coroutine() {
15     if (handle) handle.destroy();
16   }
17 };
18 
19 struct coroutine::promise_type {
get_return_objectcoroutine::promise_type20   coroutine get_return_object() {
21     return {std::coroutine_handle<promise_type>::from_promise(*this)};
22   }
initial_suspendcoroutine::promise_type23   std::suspend_never initial_suspend() noexcept { return {}; }
final_suspendcoroutine::promise_type24   std::suspend_always final_suspend() noexcept { return {}; }
return_voidcoroutine::promise_type25   void return_void() {}
unhandled_exceptioncoroutine::promise_type26   void unhandled_exception() {}
27 };
28 
29 struct Awaiter : std::suspend_always {
await_resumeAwaiter30   Printy await_resume() { return {"awaited"}; }
31 };
32 
foo()33 int foo() { return 2; }
34 
ArrayInitCoro()35 coroutine ArrayInitCoro() {
36   // Verify that:
37   //  - We do the necessary stores for array cleanups.
38   //  - Array cleanups are called by await.cleanup.
39   //  - We activate the cleanup after the first element and deactivate it in await.ready (see cleanup.isactive).
40 
41   // CHECK-LABEL: define dso_local void @_Z13ArrayInitCorov
42   // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
43   // CHECK: %cleanup.isactive = alloca i1, align 1
44   Printy arr[2] = {
45     Printy("a"),
46     // CHECK:       store i1 true, ptr %cleanup.isactive.reload.addr, align 1
47     // CHECK-NEXT:  store ptr %arr.reload.addr, ptr %arrayinit.endOfInit.reload.addr, align 8
48     // CHECK-NEXT:  call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) %arr.reload.addr, ptr noundef @.str)
49     // CHECK-NEXT:  %arrayinit.element = getelementptr inbounds %struct.Printy, ptr %arr.reload.addr, i64 1
50     // CHECK-NEXT:  %arrayinit.element.spill.addr = getelementptr inbounds %_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 10
51     // CHECK-NEXT:  store ptr %arrayinit.element, ptr %arrayinit.element.spill.addr, align 8
52     // CHECK-NEXT:  store ptr %arrayinit.element, ptr %arrayinit.endOfInit.reload.addr, align 8
53     co_await Awaiter{}
54     // CHECK-NEXT:  @_ZNSt14suspend_always11await_readyEv
55     // CHECK-NEXT:  br i1 %{{.+}}, label %await.ready, label %CoroSave30
56   };
57   // CHECK:       await.cleanup:                                    ; preds = %AfterCoroSuspend{{.*}}
58   // CHECK-NEXT:    br label %cleanup{{.*}}.from.await.cleanup
59 
60   // CHECK:       cleanup{{.*}}.from.await.cleanup:                      ; preds = %await.cleanup
61   // CHECK:         br label %cleanup{{.*}}
62 
63   // CHECK:       await.ready:
64   // CHECK-NEXT:    %arrayinit.element.reload.addr = getelementptr inbounds %_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 10
65   // CHECK-NEXT:    %arrayinit.element.reload = load ptr, ptr %arrayinit.element.reload.addr, align 8
66   // CHECK-NEXT:    call void @_ZN7Awaiter12await_resumeEv
67   // CHECK-NEXT:    store i1 false, ptr %cleanup.isactive.reload.addr, align 1
68   // CHECK-NEXT:    br label %cleanup{{.*}}.from.await.ready
69 
70   // CHECK:       cleanup{{.*}}:                                         ; preds = %cleanup{{.*}}.from.await.ready, %cleanup{{.*}}.from.await.cleanup
71   // CHECK:         %cleanup.is_active = load i1, ptr %cleanup.isactive.reload.addr, align 1
72   // CHECK-NEXT:    br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done
73 
74   // CHECK:       cleanup.action:
75   // CHECK:         %arraydestroy.isempty = icmp eq ptr %arr.reload.addr, %{{.*}}
76   // CHECK-NEXT:    br i1 %arraydestroy.isempty, label %arraydestroy.done{{.*}}, label %arraydestroy.body.from.cleanup.action
77   // Ignore rest of the array cleanup.
78 }
79 
ArrayInitWithCoReturn()80 coroutine ArrayInitWithCoReturn() {
81   // CHECK-LABEL: define dso_local void @_Z21ArrayInitWithCoReturnv
82   // Verify that we start to emit the array destructor.
83   // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
84   Printy arr[2] = {"a", ({
85                       if (foo()) {
86                         co_return;
87                       }
88                       "b";
89                     })};
90 }
91