|  | // Test for PR56919. Tests the we won't contain the resumption of final suspend point. | 
|  | // | 
|  | // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %s -O3 -emit-llvm -o - | FileCheck %s | 
|  | // This test is expected to fail on PowerPC. | 
|  | // XFAIL: target=powerpc{{.*}} | 
|  |  | 
|  | #include "Inputs/coroutine.h" | 
|  |  | 
|  | void _exit(int status) __attribute__ ((__noreturn__)); | 
|  |  | 
|  | class Promise; | 
|  |  | 
|  | // An object that can be co_awaited, but we always resume immediately from | 
|  | // await_suspend. | 
|  | struct ResumeFromAwaitSuspend{}; | 
|  |  | 
|  | struct Task { | 
|  | using promise_type = Promise; | 
|  | Promise& promise; | 
|  | }; | 
|  |  | 
|  | struct Promise { | 
|  | static std::coroutine_handle<Promise> GetHandle(Promise& promise) { | 
|  | return std::coroutine_handle<Promise>::from_promise(promise); | 
|  | } | 
|  |  | 
|  | void unhandled_exception() {} | 
|  | Task get_return_object() { return Task{*this}; } | 
|  | void return_void() {} | 
|  |  | 
|  | // Always suspend before starting the coroutine body. We actually run the body | 
|  | // when we are co_awaited. | 
|  | std::suspend_always initial_suspend() { return {}; } | 
|  |  | 
|  | // We support awaiting tasks. We do so by configuring them to resume us when | 
|  | // they are finished, and then resuming them from their initial suspend. | 
|  | auto await_transform(Task&& task) { | 
|  | struct Awaiter { | 
|  | bool await_ready() { return false; } | 
|  |  | 
|  | std::coroutine_handle<> await_suspend( | 
|  | const std::coroutine_handle<> handle) { | 
|  | // Tell the child to resume the parent once it finishes. | 
|  | child.resume_at_final_suspend = GetHandle(parent); | 
|  |  | 
|  | // Run the child. | 
|  | return GetHandle(child); | 
|  | } | 
|  |  | 
|  | void await_resume() { | 
|  | // The child is now at its final suspend point, and can be destroyed. | 
|  | return GetHandle(child).destroy(); | 
|  | } | 
|  |  | 
|  | Promise& parent; | 
|  | Promise& child; | 
|  | }; | 
|  |  | 
|  | return Awaiter{ | 
|  | .parent = *this, | 
|  | .child = task.promise, | 
|  | }; | 
|  | } | 
|  |  | 
|  | // Make evaluation of `co_await ResumeFromAwaitSuspend{}` go through the | 
|  | // await_suspend path, but cause it to resume immediately by returning our own | 
|  | // handle to resume. | 
|  | auto await_transform(ResumeFromAwaitSuspend) { | 
|  | struct Awaiter { | 
|  | bool await_ready() { return false; } | 
|  |  | 
|  | std::coroutine_handle<> await_suspend(const std::coroutine_handle<> h) { | 
|  | return h; | 
|  | } | 
|  |  | 
|  | void await_resume() {} | 
|  | }; | 
|  |  | 
|  | return Awaiter{}; | 
|  | } | 
|  |  | 
|  | // Always suspend at the final suspend point, transferring control back to our | 
|  | // caller. We expect never to be resumed from the final suspend. | 
|  | auto final_suspend() noexcept { | 
|  | struct FinalSuspendAwaitable final { | 
|  | bool await_ready() noexcept { return false; } | 
|  |  | 
|  | std::coroutine_handle<> await_suspend(std::coroutine_handle<>) noexcept { | 
|  | return promise.resume_at_final_suspend; | 
|  | } | 
|  |  | 
|  | void await_resume() noexcept { | 
|  | _exit(1); | 
|  | } | 
|  |  | 
|  | Promise& promise; | 
|  | }; | 
|  |  | 
|  | return FinalSuspendAwaitable{.promise = *this}; | 
|  | } | 
|  |  | 
|  | // The handle we will resume once we hit final suspend. | 
|  | std::coroutine_handle<> resume_at_final_suspend; | 
|  | }; | 
|  |  | 
|  | Task Inner(); | 
|  |  | 
|  | Task Outer() { | 
|  | co_await ResumeFromAwaitSuspend(); | 
|  | co_await Inner(); | 
|  | } | 
|  |  | 
|  | // CHECK: define{{.*}}@_Z5Outerv.resume( | 
|  | // CHECK-NOT: } | 
|  | // CHECK-NOT: _exit | 
|  | // CHECK: musttail call | 
|  | // CHECK: musttail call | 
|  | // CHECK: musttail call | 
|  | // CHECK-NEXT: ret void | 
|  | // CHECK-EMPTY: | 
|  | // CHECK-NEXT: unreachable: | 
|  | // CHECK-NEXT: unreachable | 
|  | // CHECK-NEXT: } |