115 lines · cpp
1// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s2 3#include "Inputs/coroutine.h"4 5struct Task {6 struct promise_type {7 Task get_return_object() noexcept {8 return Task{std::coroutine_handle<promise_type>::from_promise(*this)};9 }10 11 void return_void() noexcept {}12 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 {};18 }19 void await_resume() noexcept {}20 };21 22 void unhandled_exception() noexcept {}23 24 final_awaiter final_suspend() noexcept { return {}; }25 26 std::suspend_always initial_suspend() noexcept { return {}; }27 28 template <typename Awaitable>29 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 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 51 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 63static Task foo() {64 co_return;65}66 67Task 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 @_Z3barv82// CHECK: %[[MODE:.+]] = load i32, ptr %mode83// 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.handle93// CHECK-NEXT: %{{.+}} = call i8 @llvm.coro.suspend94// 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.handle107// CHECK-NEXT: %{{.+}} = call i8 @llvm.coro.suspend108// 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