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{{.*}} 6 7 #include "Inputs/coroutine.h" 8 9 void _exit(int status) __attribute__ ((__noreturn__)); 10 11 class Promise; 12 13 // An object that can be co_awaited, but we always resume immediately from 14 // await_suspend. 15 struct ResumeFromAwaitSuspend{}; 16 17 struct Task { 18 using promise_type = Promise; 19 Promise& promise; 20 }; 21 22 struct Promise { GetHandlePromise23 static std::coroutine_handle<Promise> GetHandle(Promise& promise) { 24 return std::coroutine_handle<Promise>::from_promise(promise); 25 } 26 unhandled_exceptionPromise27 void unhandled_exception() {} get_return_objectPromise28 Task get_return_object() { return Task{*this}; } return_voidPromise29 void return_void() {} 30 31 // Always suspend before starting the coroutine body. We actually run the body 32 // when we are co_awaited. initial_suspendPromise33 std::suspend_always initial_suspend() { return {}; } 34 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. await_transformPromise37 auto await_transform(Task&& task) { 38 struct Awaiter { 39 bool await_ready() { return false; } 40 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); 45 46 // Run the child. 47 return GetHandle(child); 48 } 49 50 void await_resume() { 51 // The child is now at its final suspend point, and can be destroyed. 52 return GetHandle(child).destroy(); 53 } 54 55 Promise& parent; 56 Promise& child; 57 }; 58 59 return Awaiter{ 60 .parent = *this, 61 .child = task.promise, 62 }; 63 } 64 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. await_transformPromise68 auto await_transform(ResumeFromAwaitSuspend) { 69 struct Awaiter { 70 bool await_ready() { return false; } 71 72 std::coroutine_handle<> await_suspend(const std::coroutine_handle<> h) { 73 return h; 74 } 75 76 void await_resume() {} 77 }; 78 79 return Awaiter{}; 80 } 81 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. final_suspendPromise84 auto final_suspend() noexcept { 85 struct FinalSuspendAwaitable final { 86 bool await_ready() noexcept { return false; } 87 88 std::coroutine_handle<> await_suspend(std::coroutine_handle<>) noexcept { 89 return promise.resume_at_final_suspend; 90 } 91 92 void await_resume() noexcept { 93 _exit(1); 94 } 95 96 Promise& promise; 97 }; 98 99 return FinalSuspendAwaitable{.promise = *this}; 100 } 101 102 // The handle we will resume once we hit final suspend. 103 std::coroutine_handle<> resume_at_final_suspend; 104 }; 105 106 Task Inner(); 107 Outer()108Task Outer() { 109 co_await ResumeFromAwaitSuspend(); 110 co_await Inner(); 111 } 112 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: } 124