Test the class which represents exception_t against true before running unhandled exception handlers.

* This allows cheap cancellation of the control flow by passing
  a default constructed `exception_t` object to `set_exception`.
* Since possible representatives like
    - `std::exception_ptr`
    - `std::error_code`
    - `std::error_condition`
  can be default constructed we have to test them anyway before possibly
  rethrowing them.
This commit is contained in:
Denis Blank 2019-11-16 17:13:23 +01:00
parent cacb84371a
commit 117a716de1

View File

@ -708,25 +708,34 @@ struct final_callback : util::non_copyable {
void operator()(Args... /*args*/) && {
}
void operator()(exception_arg_t, exception_t error) && {
(void)error;
void operator()(exception_arg_t, exception_t exception) && {
// Only handle the exception when it is present, otherwise handle it as
// a cancellation of the control flow.
// This behaviour is intentionally correct for
// - `std::exception_ptr`
// - `std::error_code`
// - `std::error_condition`
// which allow to be default constructed and then return false
// by their corresponding `operator bool()`.
if (bool(exception)) {
#ifndef CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS
// There were unhandled errors inside the asynchronous call chain!
// Define `CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS` in order
// to ignore unhandled errors!"
// There were unhandled errors inside the asynchronous call chain!
// Define `CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS` in order
// to ignore unhandled errors!"
#if defined(CONTINUABLE_HAS_EXCEPTIONS)
try {
std::rethrow_exception(error);
} catch (std::exception const& exception) {
(void)exception;
CTI_DETAIL_TRAP();
} catch (...) {
CTI_DETAIL_TRAP();
}
try {
std::rethrow_exception(exception);
} catch (std::exception const& unhandled) {
(void)unhandled;
CTI_DETAIL_TRAP();
} catch (...) {
CTI_DETAIL_TRAP();
}
#else
CTI_DETAIL_TRAP();
CTI_DETAIL_TRAP();
#endif
#endif // CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS
}
}
void set_value(Args... args) noexcept {