xref: /llvm-project/clang/test/CodeGenCoroutines/coro-symmetric-transfer-04.cpp (revision 9d1cb18d19862fc0627e4a56e1e491a498e84c71)
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()58 Task 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