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; coro1coro114 coro1 () : handle(0) {} coro1coro115 coro1 (handle_type _handle) 16 : handle(_handle) { 17 PRINT("Created coro1 object from handle"); 18 } 19 coro1 (const coro1 &) = delete; // no copying coro1coro120 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 } ~coro1coro130 ~coro1() { 31 PRINT("Destroyed coro1"); 32 if ( handle ) 33 handle.destroy(); 34 } 35 36 struct suspend_never_prt { await_readycoro1::suspend_never_prt37 bool await_ready() const noexcept { return true; } await_suspendcoro1::suspend_never_prt38 void await_suspend(handle_type) const noexcept { PRINT ("susp-never-susp"); } await_resumecoro1::suspend_never_prt39 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 { await_readycoro1::suspend_always_prt44 bool await_ready() const noexcept { return false; } await_suspendcoro1::suspend_always_prt45 void await_suspend(handle_type) const noexcept { PRINT ("susp-always-susp"); } await_resumecoro1::suspend_always_prt46 void await_resume() const noexcept { PRINT ("susp-always-resume"); } ~suspend_always_prtcoro1::suspend_always_prt47 ~suspend_always_prt() { PRINT ("susp-always-DTOR"); } 48 }; 49 50 struct promise_type { 51 int value; promise_typecoro1::promise_type52 promise_type() { PRINT ("Created Promise"); } ~promise_typecoro1::promise_type53 ~promise_type() { PRINT ("Destroyed Promise"); } 54 get_return_objectcoro1::promise_type55 auto get_return_object () { 56 PRINT ("get_return_object: handle from promise"); 57 return handle_type::from_promise (*this); 58 } initial_suspendcoro1::promise_type59 auto initial_suspend () { 60 PRINT ("get initial_suspend (always)"); 61 return suspend_always_prt{}; 62 } final_suspendcoro1::promise_type63 auto final_suspend () noexcept { 64 PRINT ("get final_suspend (always)"); 65 return suspend_always_prt{}; 66 } return_valuecoro1::promise_type67 void return_value (int v) { 68 PRINTF ("return_value () %d\n",v); 69 value = v; 70 } yield_valuecoro1::promise_type71 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. */ yield_valuecoro1::promise_type77 auto yield_value (suspend_always_prt s, int x) { 78 return s; 79 } yield_valuecoro1::promise_type80 auto yield_value (void) { 81 return 42;//suspend_always_prt{}; 82 } get_valuecoro1::promise_type83 int get_value (void) { return value; } 84 unhandled_exceptioncoro1::promise_type85 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 throw_and_catch()97struct 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 main()124int 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 } 168