[clang] Implement lifetime analysis for lifetime_capture_by(X) (#115921)
[llvm-project.git] / clang / test / CodeGenCoroutines / pr56329.cpp
blobd00022a6c4dec1ff3833dc3319b55b27207e03b1
1 // Test for PR56919. Tests the we won't contain the resumption of final suspend point.
2 //
3 // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %s -O3 -emit-llvm -o - | FileCheck %s
4 // This test is expected to fail on PowerPC.
5 // XFAIL: target=powerpc{{.*}}
7 #include "Inputs/coroutine.h"
9 void _exit(int status) __attribute__ ((__noreturn__));
11 class Promise;
13 // An object that can be co_awaited, but we always resume immediately from
14 // await_suspend.
15 struct ResumeFromAwaitSuspend{};
17 struct Task {
18 using promise_type = Promise;
19 Promise& promise;
22 struct Promise {
23 static std::coroutine_handle<Promise> GetHandle(Promise& promise) {
24 return std::coroutine_handle<Promise>::from_promise(promise);
27 void unhandled_exception() {}
28 Task get_return_object() { return Task{*this}; }
29 void return_void() {}
31 // Always suspend before starting the coroutine body. We actually run the body
32 // when we are co_awaited.
33 std::suspend_always initial_suspend() { return {}; }
35 // We support awaiting tasks. We do so by configuring them to resume us when
36 // they are finished, and then resuming them from their initial suspend.
37 auto await_transform(Task&& task) {
38 struct Awaiter {
39 bool await_ready() { return false; }
41 std::coroutine_handle<> await_suspend(
42 const std::coroutine_handle<> handle) {
43 // Tell the child to resume the parent once it finishes.
44 child.resume_at_final_suspend = GetHandle(parent);
46 // Run the child.
47 return GetHandle(child);
50 void await_resume() {
51 // The child is now at its final suspend point, and can be destroyed.
52 return GetHandle(child).destroy();
55 Promise& parent;
56 Promise& child;
59 return Awaiter{
60 .parent = *this,
61 .child = task.promise,
65 // Make evaluation of `co_await ResumeFromAwaitSuspend{}` go through the
66 // await_suspend path, but cause it to resume immediately by returning our own
67 // handle to resume.
68 auto await_transform(ResumeFromAwaitSuspend) {
69 struct Awaiter {
70 bool await_ready() { return false; }
72 std::coroutine_handle<> await_suspend(const std::coroutine_handle<> h) {
73 return h;
76 void await_resume() {}
79 return Awaiter{};
82 // Always suspend at the final suspend point, transferring control back to our
83 // caller. We expect never to be resumed from the final suspend.
84 auto final_suspend() noexcept {
85 struct FinalSuspendAwaitable final {
86 bool await_ready() noexcept { return false; }
88 std::coroutine_handle<> await_suspend(std::coroutine_handle<>) noexcept {
89 return promise.resume_at_final_suspend;
92 void await_resume() noexcept {
93 _exit(1);
96 Promise& promise;
99 return FinalSuspendAwaitable{.promise = *this};
102 // The handle we will resume once we hit final suspend.
103 std::coroutine_handle<> resume_at_final_suspend;
106 Task Inner();
108 Task Outer() {
109 co_await ResumeFromAwaitSuspend();
110 co_await Inner();
113 // CHECK: define{{.*}}@_Z5Outerv.resume(
114 // CHECK-NOT: }
115 // CHECK-NOT: _exit
116 // CHECK: musttail call
117 // CHECK: musttail call
118 // CHECK: musttail call
119 // CHECK-NEXT: ret void
120 // CHECK-EMPTY:
121 // CHECK-NEXT: unreachable:
122 // CHECK-NEXT: unreachable
123 // CHECK-NEXT: }