1 //  { dg-do run }
2 
3 // Check that we correctly operate when the coroutine object is templated.
4 
5 #include "../coro.h"
6 
7 template <typename T>
8 struct coro1 {
9   struct promise_type;
10   using handle_type = coro::coroutine_handle<coro1::promise_type>;
11   handle_type handle;
coro1coro112   coro1 () : handle(0) {}
coro1coro113   coro1 (handle_type _handle)
14     : handle(_handle) {
15         PRINT ("Created coro1 object from handle");
16   }
17   coro1 (const coro1 &) = delete; // no copying
coro1coro118   coro1 (coro1 &&s) : handle(s.handle) {
19     s.handle = nullptr;
20     PRINT ("Moved coro1");
21   }
22   coro1 &operator = (coro1 &&s) {
23     handle = s.handle;
24     s.handle = nullptr;
25     return *this;
26   }
~coro1coro127   ~coro1() {
28     PRINT ("Destroyed coro1");
29     if ( handle )
30       handle.destroy();
31   }
32 
33   struct suspend_never_prt {
~suspend_never_prtcoro1::suspend_never_prt34     ~suspend_never_prt() {}
await_readycoro1::suspend_never_prt35     bool await_ready() const noexcept { return true; }
await_suspendcoro1::suspend_never_prt36     void await_suspend(handle_type h) const noexcept { PRINT ("susp-never-susp");}
await_resumecoro1::suspend_never_prt37     void await_resume() const noexcept {PRINT ("susp-never-resume");}
38   };
39 
40   struct  suspend_always_prt {
41     T x;
await_readycoro1::suspend_always_prt42     bool await_ready() const noexcept { return false; }
await_suspendcoro1::suspend_always_prt43     void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp");}
await_resumecoro1::suspend_always_prt44     void await_resume() const noexcept {PRINT ("susp-always-resume");}
45   };
46 
47   /* This returns the int it was constructed with.  */
48   struct suspend_always_intprt {
49     T x;
suspend_always_intprtcoro1::suspend_always_intprt50     suspend_always_intprt() : x((T)5) { PRINT ("suspend_always_intprt def ctor"); }
suspend_always_intprtcoro1::suspend_always_intprt51     suspend_always_intprt(T _x) : x(_x)
52       { PRINTF ("suspend_always_intprt ctor with %ld\n", (long)x); }
~suspend_always_intprtcoro1::suspend_always_intprt53     ~suspend_always_intprt() {}
await_readycoro1::suspend_always_intprt54     bool await_ready() const noexcept { return false; }
await_suspendcoro1::suspend_always_intprt55     void await_suspend(coro::coroutine_handle<>) const noexcept { PRINT ("susp-always-susp-int");}
await_resumecoro1::suspend_always_intprt56     int await_resume() const noexcept { PRINT ("susp-always-resume-int"); return x;}
57   };
58 
59   struct promise_type {
60   T value;
promise_typecoro1::promise_type61   promise_type()  { PRINT ("Created Promise"); }
~promise_typecoro1::promise_type62   ~promise_type() { PRINT ("Destroyed Promise"); }
63 
get_return_objectcoro1::promise_type64   coro1 get_return_object() {
65     PRINT ("get_return_object: from handle from promise");
66     return coro1 (handle_type::from_promise (*this));
67   }
68 
initial_suspendcoro1::promise_type69   auto initial_suspend() {
70     PRINT ("get initial_suspend ");
71     return suspend_never_prt{};
72   }
73 
final_suspendcoro1::promise_type74   auto final_suspend() noexcept {
75     PRINT ("get final_suspend");
76     return suspend_always_prt{};
77   }
78 
return_valuecoro1::promise_type79   void return_value (int v) {
80     PRINTF ("return_value () %ld\n", (long) v);
81     value = v;
82   }
83 
await_transformcoro1::promise_type84   auto await_transform (T v) {
85     PRINTF ("await_transform a T () %ld\n", (long)v);
86     return suspend_always_intprt (v);
87   }
88 
get_valuecoro1::promise_type89   T get_value () { return value; }
unhandled_exceptioncoro1::promise_type90   void unhandled_exception() { PRINT ("** unhandled exception"); }
91   };
92 };
93 
94 /* Valued with an await_transform.  */
95 int gX = 2;
96 
97 template <typename T>
f()98 coro1<T> f ()
99 {
100   for (int i = 0; i < 4; ++i)
101     {
102       gX += co_await 10;
103     }
104   co_return gX;
105 }
106 
main()107 int main ()
108 {
109   PRINT ("main: create coro1");
110   auto f_coro = f<int>();
111 
112   PRINT ("main: got coro1 - checking gX");
113   if (gX != 2)
114     {
115       PRINTF ("main: gX is wrong : %d, should be 2\n", gX);
116       abort ();
117     }
118   PRINT ("main: gX OK -- looping");
119   do {
120     f_coro.handle.resume();
121   } while (!f_coro.handle.done());
122 
123   int y = f_coro.handle.promise().get_value();
124 
125   if (y != 42)
126     {
127       PRINTF ("main: y is wrong : %d, should be 42\n", y);
128       abort ();
129     }
130   puts ("main: done");
131   return 0;
132 }
133