xref: /llvm-project/clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp (revision 3bb39690d729d85cd93c9dd6e750d82d6f367541)
1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
2 
3 #include "Inputs/coroutine.h"
4 
5 struct Task {
6   struct promise_type {
get_return_objectTask::promise_type7     Task get_return_object() noexcept {
8       return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
9     }
10 
return_voidTask::promise_type11     void return_void() noexcept {}
12 
13     struct final_awaiter {
await_readyTask::promise_type::final_awaiter14       bool await_ready() noexcept { return false; }
await_suspendTask::promise_type::final_awaiter15       std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> h) noexcept {
16         h.destroy();
17         return {};
18       }
await_resumeTask::promise_type::final_awaiter19       void await_resume() noexcept {}
20     };
21 
unhandled_exceptionTask::promise_type22     void unhandled_exception() noexcept {}
23 
final_suspendTask::promise_type24     final_awaiter final_suspend() noexcept { return {}; }
25 
initial_suspendTask::promise_type26     std::suspend_always initial_suspend() noexcept { return {}; }
27 
28     template <typename Awaitable>
await_transformTask::promise_type29     auto await_transform(Awaitable &&awaitable) {
30       return awaitable.co_viaIfAsync();
31     }
32   };
33 
34   using handle_t = std::coroutine_handle<promise_type>;
35 
36   class Awaiter {
37   public:
38     explicit Awaiter(handle_t coro) noexcept;
39     Awaiter(Awaiter &&other) noexcept;
40     Awaiter(const Awaiter &) = delete;
41     ~Awaiter();
42 
await_ready()43     bool await_ready() noexcept { return false; }
44     handle_t await_suspend(std::coroutine_handle<> continuation) noexcept;
45     void await_resume();
46 
47   private:
48     handle_t coro_;
49   };
50 
TaskTask51   Task(handle_t coro) noexcept : coro_(coro) {}
52 
53   handle_t coro_;
54 
55   Task(const Task &t) = delete;
56   Task(Task &&t) noexcept;
57   ~Task();
58   Task &operator=(Task t) noexcept;
59 
60   Awaiter co_viaIfAsync();
61 };
62 
foo()63 static Task foo() {
64   co_return;
65 }
66 
bar()67 Task bar() {
68   auto mode = 2;
69   switch (mode) {
70   case 1:
71     co_await foo();
72     break;
73   case 2:
74     co_await foo();
75     break;
76   default:
77     break;
78   }
79 }
80 
81 // CHECK-LABEL: define{{.*}} void @_Z3barv
82 // CHECK:         %[[MODE:.+]] = load i32, ptr %mode
83 // CHECK-NEXT:    switch i32 %[[MODE]], label %{{.+}} [
84 // CHECK-NEXT:      i32 1, label %[[CASE1:.+]]
85 // CHECK-NEXT:      i32 2, label %[[CASE2:.+]]
86 // CHECK-NEXT:    ]
87 
88 // CHECK:       [[CASE1]]:
89 // CHECK:         br i1 %{{.+}}, label %[[CASE1_AWAIT_READY:.+]], label %[[CASE1_AWAIT_SUSPEND:.+]]
90 // CHECK:       [[CASE1_AWAIT_SUSPEND]]:
91 // CHECK-NEXT:    %{{.+}} = call token @llvm.coro.save(ptr null)
92 // CHECK-NEXT:    call void @llvm.coro.await.suspend.handle
93 // CHECK-NEXT:    %{{.+}} = call i8 @llvm.coro.suspend
94 // CHECK-NEXT:    switch i8 %{{.+}}, label %coro.ret [
95 // CHECK-NEXT:      i8 0, label %[[CASE1_AWAIT_READY]]
96 // CHECK-NEXT:      i8 1, label %[[CASE1_AWAIT_CLEANUP:.+]]
97 // CHECK-NEXT:    ]
98 // CHECK:       [[CASE1_AWAIT_CLEANUP]]:
99 // make sure that the awaiter eventually gets cleaned up.
100 // CHECK:         call void @{{.+Awaiter.+}}
101 
102 // CHECK:       [[CASE2]]:
103 // CHECK:         br i1 %{{.+}}, label %[[CASE2_AWAIT_READY:.+]], label %[[CASE2_AWAIT_SUSPEND:.+]]
104 // CHECK:       [[CASE2_AWAIT_SUSPEND]]:
105 // CHECK-NEXT:    %{{.+}} = call token @llvm.coro.save(ptr null)
106 // CHECK-NEXT:    call void @llvm.coro.await.suspend.handle
107 // CHECK-NEXT:    %{{.+}} = call i8 @llvm.coro.suspend
108 // CHECK-NEXT:    switch i8 %{{.+}}, label %coro.ret [
109 // CHECK-NEXT:      i8 0, label %[[CASE2_AWAIT_READY]]
110 // CHECK-NEXT:      i8 1, label %[[CASE2_AWAIT_CLEANUP:.+]]
111 // CHECK-NEXT:    ]
112 // CHECK:       [[CASE2_AWAIT_CLEANUP]]:
113 // make sure that the awaiter eventually gets cleaned up.
114 // CHECK:         call void @{{.+Awaiter.+}}
115