145
|
1 // { dg-do run }
|
|
2
|
|
3 // Test exceptions.
|
|
4
|
|
5 #include "../coro.h"
|
|
6 #include <exception>
|
|
7
|
|
8 int gX = 0;
|
|
9
|
|
10 struct coro1 {
|
|
11 struct promise_type;
|
|
12 using handle_type = coro::coroutine_handle<coro1::promise_type>;
|
|
13 handle_type handle;
|
|
14 coro1 () : handle(0) {}
|
|
15 coro1 (handle_type _handle)
|
|
16 : handle(_handle) {
|
|
17 PRINT("Created coro1 object from handle");
|
|
18 }
|
|
19 coro1 (const coro1 &) = delete; // no copying
|
|
20 coro1 (coro1 &&s) : handle(s.handle) {
|
|
21 s.handle = nullptr;
|
|
22 PRINT("coro1 mv ctor ");
|
|
23 }
|
|
24 coro1 &operator = (coro1 &&s) {
|
|
25 handle = s.handle;
|
|
26 s.handle = nullptr;
|
|
27 PRINT("coro1 op= ");
|
|
28 return *this;
|
|
29 }
|
|
30 ~coro1() {
|
|
31 PRINT("Destroyed coro1");
|
|
32 if ( handle )
|
|
33 handle.destroy();
|
|
34 }
|
|
35
|
|
36 struct suspend_never_prt {
|
|
37 bool await_ready() const noexcept { return true; }
|
|
38 void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp"); }
|
|
39 void await_resume() const noexcept { PRINT ("susp-never-resume");}
|
|
40 };
|
|
41
|
|
42 /* NOTE: this has a DTOR to test that pathway. */
|
|
43 struct suspend_always_prt {
|
|
44 bool await_ready() const noexcept { return false; }
|
|
45 void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp"); }
|
|
46 void await_resume() const noexcept { PRINT ("susp-always-resume"); }
|
|
47 ~suspend_always_prt() { PRINT ("susp-always-DTOR"); }
|
|
48 };
|
|
49
|
|
50 struct promise_type {
|
|
51 int value;
|
|
52 promise_type() { PRINT ("Created Promise"); }
|
|
53 ~promise_type() { PRINT ("Destroyed Promise"); }
|
|
54
|
|
55 auto get_return_object () {
|
|
56 PRINT ("get_return_object: handle from promise");
|
|
57 return handle_type::from_promise (*this);
|
|
58 }
|
|
59 auto initial_suspend () {
|
|
60 PRINT ("get initial_suspend (always)");
|
|
61 return suspend_always_prt{};
|
|
62 }
|
|
63 auto final_suspend () {
|
|
64 PRINT ("get final_suspend (always)");
|
|
65 return suspend_always_prt{};
|
|
66 }
|
|
67 void return_value (int v) {
|
|
68 PRINTF ("return_value () %d\n",v);
|
|
69 value = v;
|
|
70 }
|
|
71 auto yield_value (int v) {
|
|
72 PRINTF ("yield_value () %d and suspend always\n",v);
|
|
73 value = v;
|
|
74 return suspend_always_prt{};
|
|
75 }
|
|
76 /* Some non-matching overloads. */
|
|
77 auto yield_value (suspend_always_prt s, int x) {
|
|
78 return s;
|
|
79 }
|
|
80 auto yield_value (void) {
|
|
81 return 42;//suspend_always_prt{};
|
|
82 }
|
|
83 int get_value (void) { return value; }
|
|
84
|
|
85 void unhandled_exception() {
|
|
86 PRINT ("unhandled_exception: caught one!");
|
|
87 gX = -1;
|
|
88 // returning from here should end up in final_suspend.
|
|
89 }
|
|
90 };
|
|
91 };
|
|
92
|
|
93 // So we want to check that the internal behaviour of try/catch is
|
|
94 // working OK - and that if we have an unhandled exception it is caught
|
|
95 // by the wrapper that we add to the rewritten func.
|
|
96
|
|
97 struct coro1 throw_and_catch () noexcept
|
|
98 {
|
|
99 int caught = 0;
|
|
100
|
|
101 try {
|
|
102 PRINT ("f: about to yield 42");
|
|
103 co_yield 42;
|
|
104
|
|
105 throw (20);
|
|
106
|
|
107 PRINT ("f: about to yield 6174");
|
|
108 co_return 6174;
|
|
109
|
|
110 } catch (int x) {
|
|
111 PRINTF ("f: caught %d\n", x);
|
|
112 caught = x;
|
|
113 }
|
|
114
|
|
115 PRINTF ("f: about to yield what we caught %d\n", caught);
|
|
116 co_yield caught;
|
|
117
|
|
118 throw ("bah");
|
|
119
|
|
120 PRINT ("f: about to return 22");
|
|
121 co_return 22;
|
|
122 }
|
|
123
|
|
124 int main ()
|
|
125 {
|
|
126 PRINT ("main: create coro1");
|
|
127 struct coro1 x = throw_and_catch ();
|
|
128 if (x.handle.done())
|
|
129 abort();
|
|
130 x.handle.resume();
|
|
131 PRINT ("main: got coro, resuming..");
|
|
132 int y = x.handle.promise().get_value();
|
|
133 if ( y != 42 )
|
|
134 abort ();
|
|
135 PRINT ("main: apparently got the expected 42");
|
|
136 if (x.handle.done())
|
|
137 abort();
|
|
138 PRINT ("main: resuming...");
|
|
139 x.handle.resume();
|
|
140
|
|
141 y = x.handle.promise().get_value();
|
|
142 if ( y != 20 )
|
|
143 abort ();
|
|
144 PRINT ("main: apparently got 20, which we expected");
|
|
145 if (x.handle.done())
|
|
146 abort();
|
|
147
|
|
148 PRINT ("main: resuming...");
|
|
149 x.handle.resume();
|
|
150 // This should cause the throw of "bah" which is unhandled.
|
|
151 // We should catch the unhandled exception and then fall through
|
|
152 // to the final suspend point... thus be "done".
|
|
153 if (!x.handle.done())
|
|
154 {
|
|
155 PRINT ("main: apparently not done...");
|
|
156 abort ();
|
|
157 }
|
|
158 // When we caught the unhandled exception we flagged it instead of
|
|
159 // std::terminate-ing.
|
|
160 if (gX != -1)
|
|
161 {
|
|
162 PRINT ("main: apparently failed to catch");
|
|
163 abort ();
|
|
164 }
|
|
165 PRINT ("main: returning");
|
|
166 return 0;
|
|
167 }
|