1 // RUN: %clang_cc1 -disable-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 3 4 namespace std { 5 template <typename... T> 6 struct coroutine_traits; 7 8 template <typename Promise = void> struct coroutine_handle; 9 10 template <> 11 struct coroutine_handle<void> { 12 void *ptr; 13 static coroutine_handle from_address(void *); 14 void *address(); 15 }; 16 17 template <typename Promise> 18 struct coroutine_handle : coroutine_handle<> { 19 static coroutine_handle from_address(void *) noexcept; 20 }; 21 22 } // namespace std 23 24 struct init_susp { 25 bool await_ready(); 26 void await_suspend(std::coroutine_handle<>); 27 void await_resume(); 28 }; 29 struct final_susp { 30 bool await_ready() noexcept; 31 void await_suspend(std::coroutine_handle<>) noexcept; 32 void await_resume() noexcept; 33 }; 34 35 struct suspend_always { 36 int stuff; 37 bool await_ready(); 38 void await_suspend(std::coroutine_handle<>); 39 void await_resume(); 40 }; 41 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(); 49 }; 50 }; 51 52 // CHECK-LABEL: f0( 53 extern "C" void f0() { 54 // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( 55 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) 62 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:.+]] 68 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: ] 88 89 // Cleanup code goes here: 90 // ----------------------- 91 // CHECK: [[CLEANUP_BB]]: 92 93 // When coroutine is resumed, call await_resume 94 // -------------------------- 95 // CHECK: [[READY_BB]]: 96 // CHECK: call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* {{[^,]*}} %[[AWAITABLE]]) 97 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) 104 } 105 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(); 112 }; 113 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); 122 }; 123 }; 124 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) 131 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:.+]] 136 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]] 152 153 // CHECK: [[SUSPEND_PLEASE]]: 154 // CHECK: call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false) 155 156 // CHECK: [[READY_BB]]: 157 // CHECK: call void @_ZN13suspend_maybe12await_resumeEv(%struct.suspend_maybe* {{[^,]*}} %[[AWAITABLE]]) 158 } 159 160 struct ComplexAwaiter { 161 template <typename F> void await_suspend(F); 162 bool await_ready(); 163 _Complex float await_resume(); 164 }; 165 extern "C" void UseComplex(_Complex float); 166 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> %{{.+}}) 172 173 co_await ComplexAwaiter{}; 174 // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter* 175 176 _Complex float Val = co_await ComplexAwaiter{}; 177 // CHECK: call <2 x float> @_ZN14ComplexAwaiter12await_resumeEv(%struct.ComplexAwaiter* 178 } 179 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(); 185 }; 186 187 extern "C" void Whatever(); 188 extern "C" void UseAggr(Aggr&&); 189 190 // FIXME: Once the cleanup code is in, add testing that destructors for Aggr 191 // are invoked properly on the cleanup branches. 192 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() 201 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() 207 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]]) 213 } 214 215 struct ScalarAwaiter { 216 template <typename F> void await_suspend(F); 217 bool await_ready(); 218 int await_resume(); 219 }; 220 221 extern "C" void UseScalar(int); 222 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]]) 228 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, 234 235 co_await ScalarAwaiter{}; 236 // CHECK: call i32 @_ZN13ScalarAwaiter12await_resumeEv(%struct.ScalarAwaiter* 237 } 238 239 // Test operator co_await codegen. 240 enum class MyInt: int {}; 241 ScalarAwaiter operator co_await(MyInt); 242 243 struct MyAgg { 244 AggrAwaiter operator co_await(); 245 }; 246 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* {{[^,]*}} % 252 253 co_await MyAgg{}; 254 // CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* {{[^,]*}} % 255 // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret(%struct.Aggr) align 4 % 256 } 257 258 // CHECK-LABEL: EndlessLoop( 259 extern "C" void EndlessLoop() { 260 // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( 261 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* 266 267 for (;;) 268 co_await suspend_always{}; 269 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* 274 } 275 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; 281 } 282 283 struct RefTag { }; 284 285 struct AwaitResumeReturnsLValue { 286 bool await_ready(); 287 void await_suspend(std::coroutine_handle<>); 288 RefTag& await_resume(); 289 }; 290 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); 299 }; 300 }; 301 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*, 309 310 // CHECK: %[[YVAR:.+]] = alloca %struct.RefTag*, 311 // CHECK-NEXT: %[[TMP1:.+]] = alloca %struct.AwaitResumeReturnsLValue, 312 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*, 317 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; 321 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]], 326 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; 333 } 334 335 struct TailCallAwait { 336 bool await_ready(); 337 std::coroutine_handle<> await_suspend(std::coroutine_handle<>); 338 void await_resume(); 339 }; 340 341 // CHECK-LABEL: @TestTailcall( 342 extern "C" void TestTailcall() { 343 co_await TailCallAwait{}; 344 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]]) 350 }