Commit c4c3ce43 authored by Dmitry Koterov's avatar Dmitry Koterov Committed by Facebook Github Bot

Added exception_wrapper::throw_with_nested()

Summary:
This adds a missing feature. Nested exceptions are cool, see examples in https://en.cppreference.com/w/cpp/error/rethrow_if_nested (bottom of the page).

In short, nested exceptions allow people to add "contextual" information to exceptions. Previously we had to write the `try { ew.throw_exception(); } catch (...) { std::throw_with_nested(xxx); }` boilerplate if we used an exception_wrapper (e.g. in futures-oriented code); with this diff, we're able to just run `ew.throw_with_nested(xxx)`.

Reviewed By: yfeldblum

Differential Revision: D10219994

fbshipit-source-id: cdf0fbe8e4608f6c87d326631e8ffb4919c20711
parent d452f229
......@@ -468,6 +468,15 @@ inline bool exception_wrapper::is_compatible_with() const noexcept {
onNoExceptionError(__func__);
}
template <class Ex>
[[noreturn]] inline void exception_wrapper::throw_with_nested(Ex&& ex) const {
try {
throw_exception();
} catch (...) {
std::throw_with_nested(std::forward<Ex>(ex));
}
}
template <class CatchFn, bool IsConst>
struct exception_wrapper::ExceptionTypeOf {
using type = arg_type<_t<std::decay<CatchFn>>>;
......
......@@ -532,10 +532,17 @@ class exception_wrapper final {
template <class Ex>
bool is_compatible_with() const noexcept;
//! \pre `bool(*this)`
//! Throws the wrapped expression.
//! \pre `bool(*this)`
[[noreturn]] void throw_exception() const;
//! Throws the wrapped expression nested into another exception.
//! \pre `bool(*this)`
//! \tparam ex Exception in *this will be thrown nested into ex;
// see std::throw_with_nested() for details on this semantic.
template <class Ex>
[[noreturn]] void throw_with_nested(Ex&& ex) const;
//! Call `fn` with the wrapped exception (if any), if `fn` can accept it.
//! \par Example
//! \code
......
......@@ -87,6 +87,23 @@ TEST(ExceptionWrapper, throw_test) {
}
}
// Tests that when we call throw_with_nested, we can unnest it later.
TEST(ExceptionWrapper, throw_with_nested) {
auto ew = make_exception_wrapper<std::runtime_error>("inner");
try {
ew.throw_with_nested(std::runtime_error("outer"));
ADD_FAILURE();
} catch (std::runtime_error& outer) {
EXPECT_STREQ(outer.what(), "outer");
try {
std::rethrow_if_nested(outer);
ADD_FAILURE();
} catch (std::runtime_error& inner) {
EXPECT_STREQ(inner.what(), "inner");
}
}
}
TEST(ExceptionWrapper, members) {
auto ew = exception_wrapper();
EXPECT_FALSE(bool(ew));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment