1 // This tests that the symmetric transfer at the final suspend point could happen successfully. 2 // Based on https://github.com/llvm/llvm-project/pull/85271#issuecomment-2007554532 3 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O2 -emit-llvm %s -o - | FileCheck %s 4 5 #include "Inputs/coroutine.h" 6 7 struct Task { 8 struct promise_type { 9 struct FinalAwaiter { await_readyTask::promise_type::FinalAwaiter10 bool await_ready() const noexcept { return false; } 11 template <typename PromiseType> await_suspendTask::promise_type::FinalAwaiter12 std::coroutine_handle<> await_suspend(std::coroutine_handle<PromiseType> h) noexcept { 13 return h.promise().continuation; 14 } await_resumeTask::promise_type::FinalAwaiter15 void await_resume() noexcept {} 16 }; get_return_objectTask::promise_type17 Task get_return_object() noexcept { 18 return std::coroutine_handle<promise_type>::from_promise(*this); 19 } initial_suspendTask::promise_type20 std::suspend_always initial_suspend() noexcept { return {}; } final_suspendTask::promise_type21 FinalAwaiter final_suspend() noexcept { return {}; } unhandled_exceptionTask::promise_type22 void unhandled_exception() noexcept {} return_valueTask::promise_type23 void return_value(int x) noexcept { 24 _value = x; 25 } 26 std::coroutine_handle<> continuation; 27 int _value; 28 }; 29 TaskTask30 Task(std::coroutine_handle<promise_type> handle) : handle(handle), stuff(123) {} 31 32 struct Awaiter { 33 std::coroutine_handle<promise_type> handle; AwaiterTask::Awaiter34 Awaiter(std::coroutine_handle<promise_type> handle) : handle(handle) {} await_readyTask::Awaiter35 bool await_ready() const noexcept { return false; } await_suspendTask::Awaiter36 std::coroutine_handle<void> await_suspend(std::coroutine_handle<void> continuation) noexcept { 37 handle.promise().continuation = continuation; 38 return handle; 39 } await_resumeTask::Awaiter40 int await_resume() noexcept { 41 int ret = handle.promise()._value; 42 handle.destroy(); 43 return ret; 44 } 45 }; 46 operator co_awaitTask47 auto operator co_await() { 48 auto handle_ = handle; 49 handle = nullptr; 50 return Awaiter(handle_); 51 } 52 53 private: 54 std::coroutine_handle<promise_type> handle; 55 int stuff; 56 }; 57 task0()58Task task0() { 59 co_return 43; 60 } 61 62 // CHECK-LABEL: define{{.*}} void @_Z5task0v.resume 63 // This checks we are still in the scope of the current function. 64 // CHECK-NOT: {{^}}} 65 // CHECK: musttail call fastcc void 66 // CHECK-NEXT: ret void 67