// REQUIRES: x86_64-linux // This tests that the coroutine elide optimization could happen succesfully with ThinLTO. // This test is adapted from coro-elide.cpp and splits functions into two files. // // RUN: split-file %s %t // RUN: %clang --target=x86_64-linux -std=c++20 -O2 -flto=thin -I %S -c %t/coro-elide-callee.cpp -o %t/coro-elide-callee.bc // RUN: %clang --target=x86_64-linux -std=c++20 -O2 -flto=thin -I %S -c %t/coro-elide-caller.cpp -o %t/coro-elide-caller.bc // RUN: llvm-lto --thinlto %t/coro-elide-callee.bc %t/coro-elide-caller.bc -o %t/summary // RUN: %clang_cc1 -O2 -x ir %t/coro-elide-caller.bc -fthinlto-index=%t/summary.thinlto.bc -emit-llvm -o - | FileCheck %s //--- coro-elide-task.h #pragma once #include "Inputs/coroutine.h" struct Task { struct promise_type { struct FinalAwaiter { bool await_ready() const noexcept { return false; } template std::coroutine_handle<> await_suspend(std::coroutine_handle h) noexcept { if (!h) return std::noop_coroutine(); return h.promise().continuation; } void await_resume() noexcept {} }; Task get_return_object() noexcept { return std::coroutine_handle::from_promise(*this); } std::suspend_always initial_suspend() noexcept { return {}; } FinalAwaiter final_suspend() noexcept { return {}; } void unhandled_exception() noexcept {} void return_value(int x) noexcept { _value = x; } std::coroutine_handle<> continuation; int _value; }; Task(std::coroutine_handle handle) : handle(handle) {} ~Task() { if (handle) handle.destroy(); } struct Awaiter { bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle continuation) noexcept {} int await_resume() noexcept { return 43; } }; auto operator co_await() { return Awaiter{}; } private: std::coroutine_handle handle; }; //--- coro-elide-callee.cpp #include "coro-elide-task.h" Task task0() { co_return 43; } //--- coro-elide-caller.cpp #include "coro-elide-task.h" Task task0(); Task task1() { co_return co_await task0(); } // CHECK-LABEL: define{{.*}} void @_Z5task1v.resume // CHECK-NOT: {{.*}}_Znwm