[clang-cl] Ignore /Wv and /Wv:17 flags
[llvm-project.git] / clang / test / CodeGenCoroutines / coro-await.cpp
blob943a0a5c2b296048bf8b7604d0df0c04d7c8274c
1 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-unknown-linux-gnu -std=c++20 \
2 // RUN: -emit-llvm %s -o - -disable-llvm-passes -Wno-coroutine -Wno-unused | FileCheck %s
4 namespace std {
5 template <typename... T>
6 struct coroutine_traits;
8 template <typename Promise = void> struct coroutine_handle;
10 template <>
11 struct coroutine_handle<void> {
12 void *ptr;
13 static coroutine_handle from_address(void *);
14 void *address();
17 template <typename Promise>
18 struct coroutine_handle : coroutine_handle<> {
19 static coroutine_handle from_address(void *) noexcept;
22 } // namespace std
24 struct init_susp {
25 bool await_ready();
26 void await_suspend(std::coroutine_handle<>);
27 void await_resume();
29 struct final_susp {
30 bool await_ready() noexcept;
31 void await_suspend(std::coroutine_handle<>) noexcept;
32 void await_resume() noexcept;
35 struct suspend_always {
36 int stuff;
37 bool await_ready();
38 void await_suspend(std::coroutine_handle<>);
39 void await_resume();
42 template <>
43 struct std::coroutine_traits<void> {
44 struct promise_type {
45 void get_return_object();
46 init_susp initial_suspend();
47 final_susp final_suspend() noexcept;
48 void return_void();
52 // CHECK-LABEL: f0(
53 extern "C" void f0() {
54 // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
56 // See if initial_suspend was issued:
57 // ----------------------------------
58 // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
59 // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp*
60 // CHECK: %[[INITSP_ID:.+]] = call token @llvm.coro.save(
61 // CHECK: call i8 @llvm.coro.suspend(token %[[INITSP_ID]], i1 false)
63 co_await suspend_always{};
64 // See if we need to suspend:
65 // --------------------------
66 // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* {{[^,]*}} %[[AWAITABLE:.+]])
67 // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
69 // If we are suspending:
70 // ---------------------
71 // CHECK: [[SUSPEND_BB]]:
72 // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
73 // ---------------------------
74 // Build the coroutine handle and pass it to await_suspend
75 // ---------------------------
76 // CHECK: call i8* @_ZNSt16coroutine_handleINSt16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
77 // ... many lines of code to coerce coroutine_handle into an i8* scalar
78 // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
79 // CHECK: call void @_ZN14suspend_always13await_suspendESt16coroutine_handleIvE(%struct.suspend_always* {{[^,]*}} %[[AWAITABLE]], i8* %[[CH]])
80 // -------------------------
81 // Generate a suspend point:
82 // -------------------------
83 // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
84 // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
85 // CHECK: i8 0, label %[[READY_BB]]
86 // CHECK: i8 1, label %[[CLEANUP_BB:.+]]
87 // CHECK: ]
89 // Cleanup code goes here:
90 // -----------------------
91 // CHECK: [[CLEANUP_BB]]:
93 // When coroutine is resumed, call await_resume
94 // --------------------------
95 // CHECK: [[READY_BB]]:
96 // CHECK: call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* {{[^,]*}} %[[AWAITABLE]])
98 // See if final_suspend was issued:
99 // ----------------------------------
100 // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type13final_suspendEv(
101 // CHECK-NEXT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp*
102 // CHECK: %[[FINALSP_ID:.+]] = call token @llvm.coro.save(
103 // CHECK: call i8 @llvm.coro.suspend(token %[[FINALSP_ID]], i1 true)
106 struct suspend_maybe {
107 float stuff;
108 ~suspend_maybe();
109 bool await_ready();
110 bool await_suspend(std::coroutine_handle<>);
111 void await_resume();
114 template <>
115 struct std::coroutine_traits<void, int> {
116 struct promise_type {
117 void get_return_object();
118 init_susp initial_suspend();
119 final_susp final_suspend() noexcept;
120 void return_void();
121 suspend_maybe yield_value(int);
125 // CHECK-LABEL: f1(
126 extern "C" void f1(int) {
127 // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::coroutine_traits<void, int>::promise_type"
128 // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
129 co_yield 42;
130 // CHECK: call void @_ZNSt16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret(%struct.suspend_maybe) align 4 %[[AWAITER:.+]], %"struct.std::coroutine_traits<void, int>::promise_type"* {{[^,]*}} %[[PROMISE]], i32 42)
132 // See if we need to suspend:
133 // --------------------------
134 // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(%struct.suspend_maybe* {{[^,]*}} %[[AWAITABLE]])
135 // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
137 // If we are suspending:
138 // ---------------------
139 // CHECK: [[SUSPEND_BB]]:
140 // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
141 // ---------------------------
142 // Build the coroutine handle and pass it to await_suspend
143 // ---------------------------
144 // CHECK: call i8* @_ZNSt16coroutine_handleINSt16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
145 // ... many lines of code to coerce coroutine_handle into an i8* scalar
146 // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
147 // CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendESt16coroutine_handleIvE(%struct.suspend_maybe* {{[^,]*}} %[[AWAITABLE]], i8* %[[CH]])
148 // -------------------------------------------
149 // See if await_suspend decided not to suspend
150 // -------------------------------------------
151 // CHECK: br i1 %[[YES]], label %[[SUSPEND_PLEASE:.+]], label %[[READY_BB]]
153 // CHECK: [[SUSPEND_PLEASE]]:
154 // CHECK: call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
156 // CHECK: [[READY_BB]]:
157 // CHECK: call void @_ZN13suspend_maybe12await_resumeEv(%struct.suspend_maybe* {{[^,]*}} %[[AWAITABLE]])
160 struct ComplexAwaiter {
161 template <typename F> void await_suspend(F);
162 bool await_ready();
163 _Complex float await_resume();
165 extern "C" void UseComplex(_Complex float);
167 // CHECK-LABEL: @TestComplex(
168 extern "C" void TestComplex() {
169 UseComplex(co_await ComplexAwaiter{});
170 // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter*
171 // CHECK: call void @UseComplex(<2 x float> %{{.+}})
173 co_await ComplexAwaiter{};
174 // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter*
176 _Complex float Val = co_await ComplexAwaiter{};
177 // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter*
180 struct Aggr { int X, Y, Z; ~Aggr(); };
181 struct AggrAwaiter {
182 template <typename F> void await_suspend(F);
183 bool await_ready();
184 Aggr await_resume();
187 extern "C" void Whatever();
188 extern "C" void UseAggr(Aggr&&);
190 // FIXME: Once the cleanup code is in, add testing that destructors for Aggr
191 // are invoked properly on the cleanup branches.
193 // CHECK-LABEL: @TestAggr(
194 extern "C" void TestAggr() {
195 UseAggr(co_await AggrAwaiter{});
196 Whatever();
197 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret(%struct.Aggr) align 4 %[[AwaitResume:.+]],
198 // CHECK: call void @UseAggr(%struct.Aggr* nonnull align 4 dereferenceable(12) %[[AwaitResume]])
199 // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* {{[^,]*}} %[[AwaitResume]])
200 // CHECK: call void @Whatever()
202 co_await AggrAwaiter{};
203 Whatever();
204 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret(%struct.Aggr) align 4 %[[AwaitResume2:.+]],
205 // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* {{[^,]*}} %[[AwaitResume2]])
206 // CHECK: call void @Whatever()
208 Aggr Val = co_await AggrAwaiter{};
209 Whatever();
210 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret(%struct.Aggr) align 4 %[[AwaitResume3:.+]],
211 // CHECK: call void @Whatever()
212 // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* {{[^,]*}} %[[AwaitResume3]])
215 struct ScalarAwaiter {
216 template <typename F> void await_suspend(F);
217 bool await_ready();
218 int await_resume();
221 extern "C" void UseScalar(int);
223 // CHECK-LABEL: @TestScalar(
224 extern "C" void TestScalar() {
225 UseScalar(co_await ScalarAwaiter{});
226 // CHECK: %[[Result:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter*
227 // CHECK: call void @UseScalar(i32 %[[Result]])
229 int Val = co_await ScalarAwaiter{};
230 // CHECK: %[[Result2:.+]] = call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter*
231 // CHECK: store i32 %[[Result2]], i32* %[[TMP_EXPRCLEANUP:.+]],
232 // CHECK: %[[TMP:.+]] = load i32, i32* %[[TMP_EXPRCLEANUP]],
233 // CHECK: store i32 %[[TMP]], i32* %Val,
235 co_await ScalarAwaiter{};
236 // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter*
239 // Test operator co_await codegen.
240 enum class MyInt: int {};
241 ScalarAwaiter operator co_await(MyInt);
243 struct MyAgg {
244 AggrAwaiter operator co_await();
247 // CHECK-LABEL: @TestOpAwait(
248 extern "C" void TestOpAwait() {
249 co_await MyInt(42);
250 // CHECK: call void @_Zaw5MyInt(i32 42)
251 // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter* {{[^,]*}} %
253 co_await MyAgg{};
254 // CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* {{[^,]*}} %
255 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret(%struct.Aggr) align 4 %
258 // CHECK-LABEL: EndlessLoop(
259 extern "C" void EndlessLoop() {
260 // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin(
262 // See if initial_suspend was issued:
263 // ----------------------------------
264 // CHECK: call void @_ZNSt16coroutine_traitsIJvEE12promise_type15initial_suspendEv(
265 // CHECK-NEXT: call zeroext i1 @_ZN9init_susp11await_readyEv(%struct.init_susp*
267 for (;;)
268 co_await suspend_always{};
270 // Verify that final_suspend was NOT issued:
271 // ----------------------------------
272 // CHECK-NOT: call void @_ZNSt16coroutine_traitsIJvEE12promise_type13final_suspendEv(
273 // CHECK-NOT: call zeroext i1 @_ZN10final_susp11await_readyEv(%struct.final_susp*
276 // Verifies that we don't crash when awaiting on an lvalue.
277 // CHECK-LABEL: @_Z11AwaitLValuev(
278 void AwaitLValue() {
279 suspend_always lval;
280 co_await lval;
283 struct RefTag { };
285 struct AwaitResumeReturnsLValue {
286 bool await_ready();
287 void await_suspend(std::coroutine_handle<>);
288 RefTag& await_resume();
291 template <>
292 struct std::coroutine_traits<void, double> {
293 struct promise_type {
294 void get_return_object();
295 init_susp initial_suspend();
296 final_susp final_suspend() noexcept;
297 void return_void();
298 AwaitResumeReturnsLValue yield_value(int);
302 // Verifies that we don't crash when returning an lvalue from an await_resume()
303 // expression.
304 // CHECK-LABEL: define{{.*}} void @_Z18AwaitReturnsLValued(double %0)
305 void AwaitReturnsLValue(double) {
306 AwaitResumeReturnsLValue a;
307 // CHECK: %[[AVAR:.+]] = alloca %struct.AwaitResumeReturnsLValue,
308 // CHECK: %[[XVAR:.+]] = alloca %struct.RefTag*,
310 // CHECK: %[[YVAR:.+]] = alloca %struct.RefTag*,
311 // CHECK-NEXT: %[[TMP1:.+]] = alloca %struct.AwaitResumeReturnsLValue,
313 // CHECK: %[[TMP_EXPRCLEANUP1:.+]] = alloca %struct.RefTag*,
314 // CHECK: %[[ZVAR:.+]] = alloca %struct.RefTag*,
315 // CHECK-NEXT: %[[TMP2:.+]] = alloca %struct.AwaitResumeReturnsLValue,
316 // CHECK: %[[TMP_EXPRCLEANUP2:.+]] = alloca %struct.RefTag*,
318 // CHECK: %[[RES1:.+]] = call nonnull align 1 dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* {{[^,]*}} %[[AVAR]])
319 // CHECK-NEXT: store %struct.RefTag* %[[RES1]], %struct.RefTag** %[[XVAR]],
320 RefTag& x = co_await a;
322 // CHECK: %[[RES2:.+]] = call nonnull align 1 dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* {{[^,]*}} %[[TMP1]])
323 // CHECK-NEXT: store %struct.RefTag* %[[RES2]], %struct.RefTag** %[[TMP_EXPRCLEANUP1]],
324 // CHECK: %[[LOAD_TMP1:.+]] = load %struct.RefTag*, %struct.RefTag** %[[TMP_EXPRCLEANUP1]],
325 // CHECK: store %struct.RefTag* %[[LOAD_TMP1]], %struct.RefTag** %[[YVAR]],
327 RefTag& y = co_await AwaitResumeReturnsLValue{};
328 // CHECK: %[[RES3:.+]] = call nonnull align 1 dereferenceable({{.*}}) %struct.RefTag* @_ZN24AwaitResumeReturnsLValue12await_resumeEv(%struct.AwaitResumeReturnsLValue* {{[^,]*}} %[[TMP2]])
329 // CHECK-NEXT: store %struct.RefTag* %[[RES3]], %struct.RefTag** %[[TMP_EXPRCLEANUP2]],
330 // CHECK: %[[LOAD_TMP2:.+]] = load %struct.RefTag*, %struct.RefTag** %[[TMP_EXPRCLEANUP2]],
331 // CHECK: store %struct.RefTag* %[[LOAD_TMP2]], %struct.RefTag** %[[ZVAR]],
332 RefTag& z = co_yield 42;
335 struct TailCallAwait {
336 bool await_ready();
337 std::coroutine_handle<> await_suspend(std::coroutine_handle<>);
338 void await_resume();
341 // CHECK-LABEL: @TestTailcall(
342 extern "C" void TestTailcall() {
343 co_await TailCallAwait{};
345 // CHECK: %[[RESULT:.+]] = call i8* @_ZN13TailCallAwait13await_suspendESt16coroutine_handleIvE(%struct.TailCallAwait*
346 // CHECK: %[[COERCE:.+]] = getelementptr inbounds %"struct.std::coroutine_handle", %"struct.std::coroutine_handle"* %[[TMP:.+]], i32 0, i32 0
347 // CHECK: store i8* %[[RESULT]], i8** %[[COERCE]]
348 // CHECK: %[[ADDR:.+]] = call i8* @_ZNSt16coroutine_handleIvE7addressEv(%"struct.std::coroutine_handle"* {{[^,]*}} %[[TMP]])
349 // CHECK: call void @llvm.coro.resume(i8* %[[ADDR]])