UnhandledException (uC++)
When a coroutine raises an exception that isn’t caught inside the coroutine, uC++ wraps it in uBaseCoroutine::UnhandledException and delivers it to the coroutine’s last resumer.
Why the last resumer, not the starter?
The starter might be long gone from the logical control flow by the time the exception happens — coroutines can be resumed by many different callers over their lifetime. Delivering to the last resumer targets whoever is currently expecting the coroutine to do something, which is the party most able to react.
After the unhandled exception propagates out, the coroutine terminates — its stack is unwound and it becomes inactive permanently.
Handling it
The resumer can catch it two ways — either as a resumption (handle then continue) or as a termination (unwind past the resume):
_Exception E {};
_Coroutine C {
void main() { _Throw E(); } // thrown, never caught inside C
public:
void mem() { resume(); } // resume triggers the unhandled-exception propagation
};
int main() {
C c;
try {
c.mem(); // resumes C
} _CatchResume( uBaseCoroutine::UnhandledException & ) {
// Option 1: handle as resumption — c.mem() returns normally after this
} catch( uBaseCoroutine::UnhandledException & ) {
// Option 2: handle as termination — stack is unwound to here
}
}