diff --git a/include/continuable/detail/base.hpp b/include/continuable/detail/base.hpp index 3a569e2..8f64afe 100644 --- a/include/continuable/detail/base.hpp +++ b/include/continuable/detail/base.hpp @@ -387,9 +387,9 @@ struct error_callback, Callback, Executor, } }; -/// Workaround for GCC bug: +/// Once this was a workaround for GCC bug: /// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095 -struct empty_callback { +struct final_callback { template void operator()(Args... /*args*/) { } @@ -398,7 +398,14 @@ struct empty_callback { void set_value(Args... /*args*/) { } - void set_exception(types::error_type /*error*/) { + void set_exception(types::error_type error) { + (void)error; +#ifndef CONTINUABLE_WITH_UNHANDLED_ERRORS + // There were unhandled errors inside the asynchronous call chain! + // Define `CONTINUABLE_WITH_UNHANDLED_ERRORS` in order + // to ignore unhandled errors!" + util::trap(); +#endif // CONTINUABLE_WITH_UNHANDLED_ERRORS } }; } // namespace callbacks @@ -518,7 +525,7 @@ auto chain_error_handler(Continuation&& continuation, Callback&& callback, template void finalize_continuation(Continuation&& continuation) { attorney::invoke_continuation(std::forward(continuation), - callbacks::empty_callback{}); + callbacks::final_callback{}); } /// Workaround for GCC bug: diff --git a/include/continuable/detail/hints.hpp b/include/continuable/detail/hints.hpp index cb5a200..498b5cc 100644 --- a/include/continuable/detail/hints.hpp +++ b/include/continuable/detail/hints.hpp @@ -34,6 +34,7 @@ #include #include +#include #include namespace cti { diff --git a/include/continuable/detail/transforms.hpp b/include/continuable/detail/transforms.hpp index 956aa98..ea8489c 100644 --- a/include/continuable/detail/transforms.hpp +++ b/include/continuable/detail/transforms.hpp @@ -37,6 +37,7 @@ #include #include #include +#include namespace cti { namespace detail { @@ -92,13 +93,19 @@ public: void operator()(Args... args) { this->resolve(promise_, std::move(args)...); } -#if !defined(CONTINUABLE_WITH_CUSTOM_ERROR_TYPE) && \ - !defined(CONTINUABLE_WITH_NO_EXCEPTIONS) + /// Resolves the promise through the exception void operator()(types::dispatch_error_tag, types::error_type error) { +#if !defined(CONTINUABLE_WITH_CUSTOM_ERROR_TYPE) && \ + !defined(CONTINUABLE_WITH_NO_EXCEPTIONS) promise_.set_exception(error); - } +#else + // Can't forward a std::error_condition or custom error type + // to a std::promise. Handle the error first in order + // to prevent this trap! + util::trap(); #endif + } /// Returns the future from the promise auto get_future() { diff --git a/include/continuable/detail/util.hpp b/include/continuable/detail/util.hpp index dc5a57d..2c701f9 100644 --- a/include/continuable/detail/util.hpp +++ b/include/continuable/detail/util.hpp @@ -241,6 +241,27 @@ private: /// Is true when the automatic invocation on destruction is disabled bool frozen_ : 1; }; + +/// Hint for the compiler that this point should be unreachable +[[noreturn]] inline void unreachable() { +#ifdef _MSC_VER + __assume(false); +#elif __has_builtin(__builtin_unreachable) + __builtin_unreachable(); +#endif +} + +/// Causes the application to exit abnormally because we are +/// in an invalid state. +[[noreturn]] inline void trap() { +#ifdef _MSC_VER + __debugbreak(); +#elif __has_builtin(__builtin_trap) + __builtin_trap(); +#else + *(volatile int*)0 = 0; +#endif +} } // namespace util } // namespace detail } // namespace cti