// This tests that the coroutine heap allocation elision optimization could happen succesfully. // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O2 -emit-llvm %s -o - | FileCheck %s #include "Inputs/coroutine.h" #include "Inputs/numeric.h" template struct generator { struct promise_type { T current_value; std::suspend_always yield_value(T value) { this->current_value = value; return {}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } generator get_return_object() { return generator{this}; }; void unhandled_exception() {} void return_void() {} }; struct iterator { std::coroutine_handle _Coro; bool _Done; iterator(std::coroutine_handle Coro, bool Done) : _Coro(Coro), _Done(Done) {} iterator &operator++() { _Coro.resume(); _Done = _Coro.done(); return *this; } bool operator==(iterator const &_Right) const { return _Done == _Right._Done; } bool operator!=(iterator const &_Right) const { return !(*this == _Right); } T const &operator*() const { return _Coro.promise().current_value; } T const *operator->() const { return &(operator*()); } }; iterator begin() { p.resume(); return {p, p.done()}; } iterator end() { return {p, true}; } generator(generator const &) = delete; generator(generator &&rhs) : p(rhs.p) { rhs.p = nullptr; } ~generator() { if (p) p.destroy(); } private: explicit generator(promise_type *p) : p(std::coroutine_handle::from_promise(*p)) {} std::coroutine_handle p; }; template generator seq() { for (T i = {};; ++i) co_yield i; } template generator take_until(generator &g, T limit) { for (auto &&v : g) if (v < limit) co_yield v; else break; } template generator multiply(generator &g, T factor) { for (auto &&v : g) co_yield v *factor; } template generator add(generator &g, T adder) { for (auto &&v : g) co_yield v + adder; } int main() { auto s = seq(); auto t = take_until(s, 10); auto m = multiply(t, 2); auto a = add(m, 110); return std::accumulate(a.begin(), a.end(), 0); } // CHECK-LABEL: define{{.*}} i32 @main( // CHECK: ret i32 1190 // CHECK-NOT: call{{.*}}_Znwm