[clang] Implement lifetime analysis for lifetime_capture_by(X) (#115921)
[llvm-project.git] / clang / test / CodeGenCoroutines / coro-symmetric-transfer-02.cpp
blobf36f89926505f3aecd797b50f4919ebe529ab0c4
1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
3 #include "Inputs/coroutine.h"
5 struct Task {
6 struct promise_type {
7 Task get_return_object() noexcept {
8 return Task{std::coroutine_handle<promise_type>::from_promise(*this)};
11 void return_void() noexcept {}
13 struct final_awaiter {
14 bool await_ready() noexcept { return false; }
15 std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> h) noexcept {
16 h.destroy();
17 return {};
19 void await_resume() noexcept {}
22 void unhandled_exception() noexcept {}
24 final_awaiter final_suspend() noexcept { return {}; }
26 std::suspend_always initial_suspend() noexcept { return {}; }
28 template <typename Awaitable>
29 auto await_transform(Awaitable &&awaitable) {
30 return awaitable.co_viaIfAsync();
34 using handle_t = std::coroutine_handle<promise_type>;
36 class Awaiter {
37 public:
38 explicit Awaiter(handle_t coro) noexcept;
39 Awaiter(Awaiter &&other) noexcept;
40 Awaiter(const Awaiter &) = delete;
41 ~Awaiter();
43 bool await_ready() noexcept { return false; }
44 handle_t await_suspend(std::coroutine_handle<> continuation) noexcept;
45 void await_resume();
47 private:
48 handle_t coro_;
51 Task(handle_t coro) noexcept : coro_(coro) {}
53 handle_t coro_;
55 Task(const Task &t) = delete;
56 Task(Task &&t) noexcept;
57 ~Task();
58 Task &operator=(Task t) noexcept;
60 Awaiter co_viaIfAsync();
63 static Task foo() {
64 co_return;
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;
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: ]
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.+}}
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.+}}