1 // This tests that the coroutine heap allocation elision optimization could happen succesfully.
2 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O2 -emit-llvm %s -o - | FileCheck %s
3 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -O2 -emit-llvm %s \
4 // RUN: -fcxx-exceptions -fexceptions -o - | FileCheck %s
6 #include "Inputs/coroutine.h"
7 #include "Inputs/numeric.h"
9 template <typename T
> struct generator
{
12 std::suspend_always
yield_value(T value
) {
13 this->current_value
= value
;
16 std::suspend_always
initial_suspend() { return {}; }
17 std::suspend_always
final_suspend() noexcept
{ return {}; }
18 generator
get_return_object() { return generator
{this}; };
19 void unhandled_exception() {}
24 std::coroutine_handle
<promise_type
> _Coro
;
27 iterator(std::coroutine_handle
<promise_type
> Coro
, bool Done
)
28 : _Coro(Coro
), _Done(Done
) {}
30 iterator
&operator++() {
36 bool operator==(iterator
const &_Right
) const {
37 return _Done
== _Right
._Done
;
40 bool operator!=(iterator
const &_Right
) const { return !(*this == _Right
); }
41 T
const &operator*() const { return _Coro
.promise().current_value
; }
42 T
const *operator->() const { return &(operator*()); }
50 iterator
end() { return {p
, true}; }
52 generator(generator
const &) = delete;
53 generator(generator
&&rhs
) : p(rhs
.p
) { rhs
.p
= nullptr; }
61 explicit generator(promise_type
*p
)
62 : p(std::coroutine_handle
<promise_type
>::from_promise(*p
)) {}
64 std::coroutine_handle
<promise_type
> p
;
74 generator
<T
> take_until(generator
<T
> &g
, T limit
) {
83 generator
<T
> multiply(generator
<T
> &g
, T factor
) {
89 generator
<T
> add(generator
<T
> &g
, T adder
) {
96 auto t
= take_until(s
, 10);
97 auto m
= multiply(t
, 2);
99 return std::accumulate(a
.begin(), a
.end(), 0);
102 // CHECK-LABEL: define{{.*}} i32 @main(
103 // CHECK: ret i32 1190
104 // CHECK-NOT: call{{.*}}_Znwm