Commit 44739203 authored by Junqi Wang's avatar Junqi Wang Committed by Facebook GitHub Bot

Back out "exception_wrapper thrown variant via abi/runtime"

Summary: Original commit changeset: ce083cec4c31

Differential Revision: D28558687

fbshipit-source-id: 5cf4ac838c80428902280f3f9ccdd1174410fbe6
parent d7e90075
...@@ -127,6 +127,56 @@ inline std::exception const* exception_wrapper::as_exception_or_null_( ...@@ -127,6 +127,56 @@ inline std::exception const* exception_wrapper::as_exception_or_null_(
return nullptr; return nullptr;
} }
static_assert(
!kMicrosoftAbiVer || (kMicrosoftAbiVer >= 1900 && kMicrosoftAbiVer <= 2000),
"exception_wrapper is untested and possibly broken on your version of "
"MSVC");
inline std::uintptr_t exception_wrapper::ExceptionPtr::as_int_(
std::exception_ptr const& ptr, std::exception const& e) noexcept {
if (!kMicrosoftAbiVer) {
return reinterpret_cast<std::uintptr_t>(&e);
} else {
// On Windows, as of MSVC2017, all thrown exceptions are copied to the stack
// first. Thus, we cannot depend on exception references associated with an
// exception_ptr to be live for the duration of the exception_ptr. We need
// to directly access the heap allocated memory inside the exception_ptr.
//
// std::exception_ptr is an opaque reinterpret_cast of
// std::shared_ptr<__ExceptionPtr>
// __ExceptionPtr is a non-virtual class with two members, a union and a
// bool. The union contains the now-undocumented EHExceptionRecord, which
// contains a struct which contains a void* which points to the heap
// allocated exception.
// We derive the offset to pExceptionObject via manual means.
FOLLY_PACK_PUSH
struct Win32ExceptionPtr {
char offset[8 + 4 * sizeof(void*)];
void* exceptionObject;
} FOLLY_PACK_ATTR;
FOLLY_PACK_POP
auto* win32ExceptionPtr =
reinterpret_cast<std::shared_ptr<Win32ExceptionPtr> const*>(&ptr)
->get();
return reinterpret_cast<std::uintptr_t>(win32ExceptionPtr->exceptionObject);
}
}
inline std::uintptr_t exception_wrapper::ExceptionPtr::as_int_(
std::exception_ptr const&, AnyException e) noexcept {
return reinterpret_cast<std::uintptr_t>(e.typeinfo_) + 1;
}
inline bool exception_wrapper::ExceptionPtr::has_exception_() const {
return 0 == exception_or_type_ % 2;
}
inline std::exception const* exception_wrapper::ExceptionPtr::as_exception_()
const {
return reinterpret_cast<std::exception const*>(exception_or_type_);
}
inline std::type_info const* exception_wrapper::ExceptionPtr::as_type_() const {
return reinterpret_cast<std::type_info const*>(exception_or_type_ - 1);
}
inline void exception_wrapper::ExceptionPtr::copy_( inline void exception_wrapper::ExceptionPtr::copy_(
exception_wrapper const* from, exception_wrapper* to) { exception_wrapper const* from, exception_wrapper* to) {
::new (static_cast<void*>(&to->eptr_)) ExceptionPtr(from->eptr_); ::new (static_cast<void*>(&to->eptr_)) ExceptionPtr(from->eptr_);
...@@ -146,11 +196,14 @@ inline void exception_wrapper::ExceptionPtr::delete_(exception_wrapper* that) { ...@@ -146,11 +196,14 @@ inline void exception_wrapper::ExceptionPtr::delete_(exception_wrapper* that) {
} }
inline std::type_info const* exception_wrapper::ExceptionPtr::type_( inline std::type_info const* exception_wrapper::ExceptionPtr::type_(
exception_wrapper const* that) { exception_wrapper const* that) {
return exception_ptr_get_type(that->eptr_.ptr_); if (auto e = get_exception_(that)) {
return &typeid(*e);
}
return that->eptr_.as_type_();
} }
inline std::exception const* exception_wrapper::ExceptionPtr::get_exception_( inline std::exception const* exception_wrapper::ExceptionPtr::get_exception_(
exception_wrapper const* that) { exception_wrapper const* that) {
return exception_ptr_get_object<std::exception>(that->eptr_.ptr_); return that->eptr_.has_exception_() ? that->eptr_.as_exception_() : nullptr;
} }
inline exception_wrapper exception_wrapper::ExceptionPtr::get_exception_ptr_( inline exception_wrapper exception_wrapper::ExceptionPtr::get_exception_ptr_(
exception_wrapper const* that) { exception_wrapper const* that) {
...@@ -195,8 +248,8 @@ inline exception_wrapper exception_wrapper::InPlace<Ex>::get_exception_ptr_( ...@@ -195,8 +248,8 @@ inline exception_wrapper exception_wrapper::InPlace<Ex>::get_exception_ptr_(
exception_wrapper const* that) { exception_wrapper const* that) {
try { try {
throw_(that); throw_(that);
} catch (...) { } catch (Ex const& ex) {
return exception_wrapper{std::current_exception()}; return exception_wrapper{std::current_exception(), ex};
} }
} }
...@@ -215,8 +268,8 @@ inline exception_wrapper ...@@ -215,8 +268,8 @@ inline exception_wrapper
exception_wrapper::SharedPtr::Impl<Ex>::get_exception_ptr_() const noexcept { exception_wrapper::SharedPtr::Impl<Ex>::get_exception_ptr_() const noexcept {
try { try {
throw_(); throw_();
} catch (...) { } catch (Ex& ex) {
return exception_wrapper{std::current_exception()}; return exception_wrapper{std::current_exception(), ex};
} }
} }
inline void exception_wrapper::SharedPtr::copy_( inline void exception_wrapper::SharedPtr::copy_(
...@@ -254,7 +307,7 @@ inline exception_wrapper exception_wrapper::SharedPtr::get_exception_ptr_( ...@@ -254,7 +307,7 @@ inline exception_wrapper exception_wrapper::SharedPtr::get_exception_ptr_(
template <class Ex, typename... As> template <class Ex, typename... As>
inline exception_wrapper::exception_wrapper( inline exception_wrapper::exception_wrapper(
ThrownTag, in_place_type_t<Ex>, As&&... as) ThrownTag, in_place_type_t<Ex>, As&&... as)
: eptr_{std::make_exception_ptr(Ex(std::forward<As>(as)...))}, : eptr_{std::make_exception_ptr(Ex(std::forward<As>(as)...)), reinterpret_cast<std::uintptr_t>(std::addressof(typeid(Ex))) + 1u},
vptr_(&ExceptionPtr::ops_) {} vptr_(&ExceptionPtr::ops_) {}
template <class Ex, typename... As> template <class Ex, typename... As>
...@@ -302,17 +355,9 @@ inline exception_wrapper::~exception_wrapper() { ...@@ -302,17 +355,9 @@ inline exception_wrapper::~exception_wrapper() {
template <class Ex> template <class Ex>
inline exception_wrapper::exception_wrapper( inline exception_wrapper::exception_wrapper(
std::exception_ptr const& ptr, Ex& ex) noexcept std::exception_ptr ptr, Ex& ex) noexcept
: exception_wrapper{folly::copy(ptr), ex} {} : eptr_{ptr, ExceptionPtr::as_int_(ptr, ex)}, vptr_(&ExceptionPtr::ops_) {
template <class Ex>
inline exception_wrapper::exception_wrapper(
std::exception_ptr&& ptr, Ex& ex) noexcept
: eptr_{std::move(ptr)}, vptr_(&ExceptionPtr::ops_) {
assert(eptr_.ptr_); assert(eptr_.ptr_);
(void)ex;
assert(exception_ptr_get_object<Ex>(eptr_.ptr_));
assert(exception_ptr_get_object<Ex>(eptr_.ptr_) == &ex || kIsWindows);
} }
namespace exception_wrapper_detail { namespace exception_wrapper_detail {
...@@ -412,6 +457,9 @@ inline std::exception_ptr exception_wrapper::to_exception_ptr() const noexcept { ...@@ -412,6 +457,9 @@ inline std::exception_ptr exception_wrapper::to_exception_ptr() const noexcept {
inline std::type_info const& exception_wrapper::none() noexcept { inline std::type_info const& exception_wrapper::none() noexcept {
return typeid(void); return typeid(void);
} }
inline std::type_info const& exception_wrapper::unknown() noexcept {
return typeid(Unknown);
}
inline std::type_info const& exception_wrapper::type() const noexcept { inline std::type_info const& exception_wrapper::type() const noexcept {
return *vptr_->type_(this); return *vptr_->type_(this);
...@@ -426,7 +474,9 @@ inline folly::fbstring exception_wrapper::what() const { ...@@ -426,7 +474,9 @@ inline folly::fbstring exception_wrapper::what() const {
inline folly::fbstring exception_wrapper::class_name() const { inline folly::fbstring exception_wrapper::class_name() const {
auto& ti = type(); auto& ti = type();
return ti == none() ? "" : folly::demangle(ti); return ti == none() ? ""
: ti == unknown() ? "<unknown exception>"
: folly::demangle(ti);
} }
template <class Ex> template <class Ex>
......
...@@ -37,6 +37,18 @@ exception_wrapper::VTable const exception_wrapper::ExceptionPtr::ops_{ ...@@ -37,6 +37,18 @@ exception_wrapper::VTable const exception_wrapper::ExceptionPtr::ops_{
exception_wrapper::VTable const exception_wrapper::SharedPtr::ops_{ exception_wrapper::VTable const exception_wrapper::SharedPtr::ops_{
copy_, move_, delete_, throw_, type_, get_exception_, get_exception_ptr_}; copy_, move_, delete_, throw_, type_, get_exception_, get_exception_ptr_};
namespace {
std::exception const* get_std_exception_(std::exception_ptr eptr) noexcept {
try {
std::rethrow_exception(eptr);
} catch (const std::exception& ex) {
return &ex;
} catch (...) {
return nullptr;
}
}
} // namespace
exception_wrapper exception_wrapper::from_exception_ptr( exception_wrapper exception_wrapper::from_exception_ptr(
std::exception_ptr const& ptr) noexcept { std::exception_ptr const& ptr) noexcept {
return from_exception_ptr(folly::copy(ptr)); return from_exception_ptr(folly::copy(ptr));
...@@ -44,16 +56,31 @@ exception_wrapper exception_wrapper::from_exception_ptr( ...@@ -44,16 +56,31 @@ exception_wrapper exception_wrapper::from_exception_ptr(
exception_wrapper exception_wrapper::from_exception_ptr( exception_wrapper exception_wrapper::from_exception_ptr(
std::exception_ptr&& ptr) noexcept { std::exception_ptr&& ptr) noexcept {
return !ptr ? exception_wrapper() : exception_wrapper(std::move(ptr)); if (!ptr) {
return exception_wrapper();
}
try {
std::rethrow_exception(std::move(ptr));
} catch (std::exception& e) {
return exception_wrapper(std::current_exception(), e);
} catch (...) {
return exception_wrapper(std::current_exception());
}
} }
exception_wrapper::exception_wrapper(std::exception_ptr const& ptr) noexcept exception_wrapper::exception_wrapper(std::exception_ptr ptr) noexcept
: exception_wrapper{folly::copy(ptr)} {} : exception_wrapper{} {
exception_wrapper::exception_wrapper(std::exception_ptr&& ptr) noexcept {
if (ptr) { if (ptr) {
::new (&eptr_) ExceptionPtr{std::move(ptr)}; if (auto e = get_std_exception_(ptr)) {
vptr_ = &ExceptionPtr::ops_; LOG(DFATAL)
<< "Performance error: Please construct exception_wrapper with a "
"reference to the std::exception along with the "
"std::exception_ptr.";
*this = exception_wrapper{std::move(ptr), *e};
} else {
Unknown uk;
*this = exception_wrapper{ptr, uk};
}
} }
} }
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include <utility> #include <utility>
#include <folly/CPortability.h> #include <folly/CPortability.h>
#include <folly/CppAttributes.h>
#include <folly/Demangle.h> #include <folly/Demangle.h>
#include <folly/ExceptionString.h> #include <folly/ExceptionString.h>
#include <folly/FBString.h> #include <folly/FBString.h>
...@@ -39,7 +38,6 @@ ...@@ -39,7 +38,6 @@
#include <folly/Traits.h> #include <folly/Traits.h>
#include <folly/Utility.h> #include <folly/Utility.h>
#include <folly/lang/Assume.h> #include <folly/lang/Assume.h>
#include <folly/lang/Exception.h>
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
...@@ -179,7 +177,10 @@ class exception_wrapper final { ...@@ -179,7 +177,10 @@ class exception_wrapper final {
// 1. An small object stored in-situ. // 1. An small object stored in-situ.
// 2. A larger object stored on the heap and referenced with a // 2. A larger object stored on the heap and referenced with a
// std::shared_ptr. // std::shared_ptr.
// 3. A std::exception_ptr. // 3. A std::exception_ptr, together with either:
// a. A pointer to the referenced std::exception object, or
// b. A pointer to a std::type_info object for the referenced exception,
// or for an unspecified type if the type is unknown.
// This is accomplished with the help of a union and a pointer to a hand- // This is accomplished with the help of a union and a pointer to a hand-
// rolled virtual table. This virtual table contains pointers to functions // rolled virtual table. This virtual table contains pointers to functions
// that know which field of the union is active and do the proper action. // that know which field of the union is active and do the proper action.
...@@ -211,6 +212,8 @@ class exception_wrapper final { ...@@ -211,6 +212,8 @@ class exception_wrapper final {
using IsCatchAll = using IsCatchAll =
std::is_same<arg_type<std::decay_t<CatchFn>>, AnyException>; std::is_same<arg_type<std::decay_t<CatchFn>>, AnyException>;
struct Unknown {};
// Sadly, with the gcc-4.9 platform, std::logic_error and std::runtime_error // Sadly, with the gcc-4.9 platform, std::logic_error and std::runtime_error
// do not fit here. They also don't have noexcept copy-ctors, so the internal // do not fit here. They also don't have noexcept copy-ctors, so the internal
// storage wouldn't be used anyway. For the gcc-5 platform, both logic_error // storage wouldn't be used anyway. For the gcc-5 platform, both logic_error
...@@ -252,7 +255,19 @@ class exception_wrapper final { ...@@ -252,7 +255,19 @@ class exception_wrapper final {
struct ExceptionPtr { struct ExceptionPtr {
std::exception_ptr ptr_; std::exception_ptr ptr_;
std::uintptr_t exception_or_type_; // odd for type_info
static_assert(
1 < alignof(std::exception) && 1 < alignof(std::type_info),
"Surprise! std::exception and std::type_info don't have alignment "
"greater than one. as_int_ below will not work!");
static std::uintptr_t as_int_(
std::exception_ptr const& ptr, std::exception const& e) noexcept;
static std::uintptr_t as_int_(
std::exception_ptr const& ptr, AnyException e) noexcept;
bool has_exception_() const;
std::exception const* as_exception_() const;
std::type_info const* as_type_() const;
static void copy_(exception_wrapper const* from, exception_wrapper* to); static void copy_(exception_wrapper const* from, exception_wrapper* to);
static void move_(exception_wrapper* from, exception_wrapper* to); static void move_(exception_wrapper* from, exception_wrapper* to);
static void delete_(exception_wrapper* that); static void delete_(exception_wrapper* that);
...@@ -393,19 +408,19 @@ class exception_wrapper final { ...@@ -393,19 +408,19 @@ class exception_wrapper final {
~exception_wrapper(); ~exception_wrapper();
//! \pre `ptr` is empty, or it holds a reference to an exception that is not
//! derived from `std::exception`.
//! \post `!ptr || bool(*this)` //! \post `!ptr || bool(*this)`
//! \post `hasThrownException() == bool(ptr)` //! \post `hasThrownException() == true`
explicit exception_wrapper(std::exception_ptr const& ptr) noexcept; //! \post `type() == unknown()`
explicit exception_wrapper(std::exception_ptr&& ptr) noexcept; explicit exception_wrapper(std::exception_ptr ptr) noexcept;
//! \pre `ptr` holds a reference to `ex`. //! \pre `ptr` holds a reference to `ex`.
//! \post `hasThrownException() == true` //! \post `hasThrownException() == true`
//! \post `bool(*this)` //! \post `bool(*this)`
//! \post `type() == typeid(ex)` //! \post `type() == typeid(ex)`
template <class Ex> template <class Ex>
exception_wrapper(std::exception_ptr const& ptr, Ex& ex) noexcept; exception_wrapper(std::exception_ptr ptr, Ex& ex) noexcept;
template <class Ex>
exception_wrapper(std::exception_ptr&& ptr, Ex& ex) noexcept;
//! \pre `typeid(ex) == typeid(typename decay<Ex>::type)` //! \pre `typeid(ex) == typeid(typename decay<Ex>::type)`
//! \post `bool(*this)` //! \post `bool(*this)`
...@@ -491,16 +506,23 @@ class exception_wrapper final { ...@@ -491,16 +506,23 @@ class exception_wrapper final {
//! \return the `typeid` of an unspecified type used by //! \return the `typeid` of an unspecified type used by
//! `exception_wrapper::type()` to denote an empty `exception_wrapper`. //! `exception_wrapper::type()` to denote an empty `exception_wrapper`.
static std::type_info const& none() noexcept; static std::type_info const& none() noexcept;
//! \return the `typeid` of an unspecified type used by
//! `exception_wrapper::type()` to denote an `exception_wrapper` that
//! holds an exception of unknown type.
static std::type_info const& unknown() noexcept;
//! Returns the `typeid` of the wrapped exception object. If there is no //! Returns the `typeid` of the wrapped exception object. If there is no
//! wrapped exception object, returns `exception_wrapper::none()`. //! wrapped exception object, returns `exception_wrapper::none()`. If
//! this instance wraps an exception of unknown type not derived from
//! `std::exception`, returns `exception_wrapper::unknown()`.
std::type_info const& type() const noexcept; std::type_info const& type() const noexcept;
//! \return If `get_exception() != nullptr`, `class_name() + ": " + //! \return If `get_exception() != nullptr`, `class_name() + ": " +
//! get_exception()->what()`; otherwise, `class_name()`. //! get_exception()->what()`; otherwise, `class_name()`.
folly::fbstring what() const; folly::fbstring what() const;
//! \return If `!*this`, the empty string; otherwise, //! \return If `!*this`, the empty string; otherwise, if
//! `type() == unknown()`, the string `"<unknown exception>"`; otherwise,
//! the result of `type().name()` after demangling. //! the result of `type().name()` after demangling.
folly::fbstring class_name() const; folly::fbstring class_name() const;
...@@ -636,8 +658,8 @@ template <typename F, typename Ex, typename... Exs> ...@@ -636,8 +658,8 @@ template <typename F, typename Ex, typename... Exs>
inline exception_wrapper try_and_catch_(F&& f) { inline exception_wrapper try_and_catch_(F&& f) {
try { try {
return try_and_catch_<F, Exs...>(std::forward<F>(f)); return try_and_catch_<F, Exs...>(std::forward<F>(f));
} catch (Ex&) { } catch (Ex& ex) {
return exception_wrapper(std::current_exception()); return exception_wrapper(std::current_exception(), ex);
} }
} }
} // namespace detail } // namespace detail
...@@ -687,6 +709,8 @@ exception_wrapper try_and_catch(F&& fn) noexcept { ...@@ -687,6 +709,8 @@ exception_wrapper try_and_catch(F&& fn) noexcept {
try { try {
static_cast<F&&>(fn)(); static_cast<F&&>(fn)();
return exception_wrapper{}; return exception_wrapper{};
} catch (std::exception const& ex) {
return exception_wrapper{std::current_exception(), ex};
} catch (...) { } catch (...) {
return exception_wrapper{std::current_exception()}; return exception_wrapper{std::current_exception()};
} }
......
...@@ -239,13 +239,13 @@ TEST(ExceptionWrapper, get_or_make_exception_ptr_test) { ...@@ -239,13 +239,13 @@ TEST(ExceptionWrapper, get_or_make_exception_ptr_test) {
TEST(ExceptionWrapper, from_exception_ptr_empty) { TEST(ExceptionWrapper, from_exception_ptr_empty) {
auto ep = std::exception_ptr(); auto ep = std::exception_ptr();
auto ew = exception_wrapper{ep}; auto ew = exception_wrapper::from_exception_ptr(ep);
EXPECT_FALSE(bool(ew)); EXPECT_FALSE(bool(ew));
} }
TEST(ExceptionWrapper, from_exception_ptr_exn) { TEST(ExceptionWrapper, from_exception_ptr_exn) {
auto ep = std::make_exception_ptr(std::runtime_error("foo")); auto ep = std::make_exception_ptr(std::runtime_error("foo"));
auto ew = exception_wrapper{ep}; auto ew = exception_wrapper::from_exception_ptr(ep);
EXPECT_TRUE(bool(ew)); EXPECT_TRUE(bool(ew));
EXPECT_EQ(ep, folly::as_const(ew).to_exception_ptr()); EXPECT_EQ(ep, folly::as_const(ew).to_exception_ptr());
EXPECT_EQ(ep, ew.to_exception_ptr()); EXPECT_EQ(ep, ew.to_exception_ptr());
...@@ -254,7 +254,7 @@ TEST(ExceptionWrapper, from_exception_ptr_exn) { ...@@ -254,7 +254,7 @@ TEST(ExceptionWrapper, from_exception_ptr_exn) {
TEST(ExceptionWrapper, from_exception_ptr_any) { TEST(ExceptionWrapper, from_exception_ptr_any) {
auto ep = std::make_exception_ptr<int>(12); auto ep = std::make_exception_ptr<int>(12);
auto ew = exception_wrapper{ep}; auto ew = exception_wrapper::from_exception_ptr(ep);
EXPECT_TRUE(bool(ew)); EXPECT_TRUE(bool(ew));
EXPECT_EQ(ep, folly::as_const(ew).to_exception_ptr()); EXPECT_EQ(ep, folly::as_const(ew).to_exception_ptr());
EXPECT_EQ(ep, ew.to_exception_ptr()); EXPECT_EQ(ep, ew.to_exception_ptr());
...@@ -420,7 +420,7 @@ TEST(ExceptionWrapper, with_non_std_exception_test) { ...@@ -420,7 +420,7 @@ TEST(ExceptionWrapper, with_non_std_exception_test) {
TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) { TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
auto ep = std::make_exception_ptr<int>(12); auto ep = std::make_exception_ptr<int>(12);
auto ew = exception_wrapper(ep); auto ew = exception_wrapper(ep); // concrete type is erased
EXPECT_TRUE(bool(ew)); EXPECT_TRUE(bool(ew));
EXPECT_EQ(nullptr, ew.get_exception()); EXPECT_EQ(nullptr, ew.get_exception());
EXPECT_EQ(nullptr, ew.get_exception<std::exception>()); EXPECT_EQ(nullptr, ew.get_exception<std::exception>());
...@@ -428,8 +428,9 @@ TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) { ...@@ -428,8 +428,9 @@ TEST(ExceptionWrapper, with_exception_ptr_any_nil_test) {
EXPECT_EQ(12, *ew.get_exception<int>()); EXPECT_EQ(12, *ew.get_exception<int>());
EXPECT_EQ(ep, folly::as_const(ew).to_exception_ptr()); EXPECT_EQ(ep, folly::as_const(ew).to_exception_ptr());
EXPECT_EQ(ep, ew.to_exception_ptr()); EXPECT_EQ(ep, ew.to_exception_ptr());
EXPECT_EQ("int", ew.class_name()); EXPECT_EQ("<unknown exception>", ew.class_name()); // because concrete type is
EXPECT_EQ("int", ew.what()); // erased
EXPECT_EQ("<unknown exception>", ew.what());
EXPECT_FALSE(ew.is_compatible_with<std::exception>()); EXPECT_FALSE(ew.is_compatible_with<std::exception>());
EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>()); EXPECT_FALSE(ew.is_compatible_with<std::runtime_error>());
EXPECT_TRUE(ew.is_compatible_with<int>()); EXPECT_TRUE(ew.is_compatible_with<int>());
...@@ -538,16 +539,23 @@ TEST(ExceptionWrapper, implicitConstruction) { ...@@ -538,16 +539,23 @@ TEST(ExceptionWrapper, implicitConstruction) {
} }
namespace { namespace {
struct BaseNonStdException { struct BaseException {
virtual ~BaseNonStdException() {} virtual ~BaseException() {}
}; };
struct DerivedNonStdException : BaseNonStdException {}; struct DerivedException : BaseException {};
exception_wrapper testNonStdException() {
try {
throw DerivedException{};
} catch (const BaseException& e) {
return exception_wrapper{std::current_exception(), e};
}
}
} // namespace } // namespace
TEST(ExceptionWrapper, base_derived_non_std_exception_test) { TEST(ExceptionWrapper, base_derived_non_std_exception_test) {
exception_wrapper ew{std::make_exception_ptr(DerivedNonStdException{})}; auto ew = testNonStdException();
EXPECT_TRUE(ew.type() == typeid(DerivedNonStdException)); EXPECT_TRUE(ew.type() == typeid(DerivedException));
EXPECT_TRUE(ew.with_exception([](const DerivedNonStdException&) {})); EXPECT_TRUE(ew.with_exception([](const DerivedException&) {}));
} }
namespace { namespace {
...@@ -834,26 +842,26 @@ TEST(ExceptionWrapper, handle_non_std_exception_big) { ...@@ -834,26 +842,26 @@ TEST(ExceptionWrapper, handle_non_std_exception_big) {
} }
TEST(ExceptionWrapper, handle_non_std_exception_rethrow_base_derived) { TEST(ExceptionWrapper, handle_non_std_exception_rethrow_base_derived) {
exception_wrapper ew{std::make_exception_ptr(DerivedNonStdException{})}; auto ew = testNonStdException();
bool handled = false; bool handled = false;
EXPECT_THROW( EXPECT_THROW(
ew.handle( ew.handle(
[&](const DerivedNonStdException& e) { [&](const DerivedException& e) {
handled = true; handled = true;
throw e; throw e;
}, },
[](const BaseNonStdException&) { ADD_FAILURE(); }), [](const BaseException&) { ADD_FAILURE(); }),
DerivedNonStdException); DerivedException);
EXPECT_TRUE(handled); EXPECT_TRUE(handled);
handled = false; handled = false;
EXPECT_THROW( EXPECT_THROW(
ew.handle( ew.handle(
[&](const DerivedNonStdException& e) { [&](const DerivedException& e) {
handled = true; handled = true;
throw e; throw e;
}, },
[](...) { ADD_FAILURE(); }), [](...) { ADD_FAILURE(); }),
DerivedNonStdException); DerivedException);
EXPECT_TRUE(handled); EXPECT_TRUE(handled);
} }
......
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