123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677 |
- /*
- * Copyright 2017-present Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /*
- *
- * Author: Eric Niebler <eniebler@fb.com>
- */
- #include <folly/Portability.h>
- namespace folly {
- template <class Fn>
- struct exception_wrapper::arg_type_
- : public arg_type_<decltype(&Fn::operator())> {};
- template <class Ret, class Class, class Arg>
- struct exception_wrapper::arg_type_<Ret (Class::*)(Arg)> {
- using type = Arg;
- };
- template <class Ret, class Class, class Arg>
- struct exception_wrapper::arg_type_<Ret (Class::*)(Arg) const> {
- using type = Arg;
- };
- template <class Ret, class Arg>
- struct exception_wrapper::arg_type_<Ret(Arg)> {
- using type = Arg;
- };
- template <class Ret, class Arg>
- struct exception_wrapper::arg_type_<Ret (*)(Arg)> {
- using type = Arg;
- };
- template <class Ret, class Class>
- struct exception_wrapper::arg_type_<Ret (Class::*)(...)> {
- using type = AnyException;
- };
- template <class Ret, class Class>
- struct exception_wrapper::arg_type_<Ret (Class::*)(...) const> {
- using type = AnyException;
- };
- template <class Ret>
- struct exception_wrapper::arg_type_<Ret(...)> {
- using type = AnyException;
- };
- template <class Ret>
- struct exception_wrapper::arg_type_<Ret (*)(...)> {
- using type = AnyException;
- };
- template <class Ret, class... Args>
- inline Ret exception_wrapper::noop_(Args...) {
- return Ret();
- }
- inline std::type_info const* exception_wrapper::uninit_type_(
- exception_wrapper const*) {
- return &typeid(void);
- }
- template <class Ex, typename... As>
- inline exception_wrapper::Buffer::Buffer(in_place_type_t<Ex>, As&&... as_) {
- ::new (static_cast<void*>(&buff_)) Ex(std::forward<As>(as_)...);
- }
- template <class Ex>
- inline Ex& exception_wrapper::Buffer::as() noexcept {
- return *static_cast<Ex*>(static_cast<void*>(&buff_));
- }
- template <class Ex>
- inline Ex const& exception_wrapper::Buffer::as() const noexcept {
- return *static_cast<Ex const*>(static_cast<void const*>(&buff_));
- }
- inline std::exception const* exception_wrapper::as_exception_or_null_(
- std::exception const& ex) {
- return &ex;
- }
- inline std::exception const* exception_wrapper::as_exception_or_null_(
- AnyException) {
- 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_(
- exception_wrapper const* from,
- exception_wrapper* to) {
- ::new (static_cast<void*>(&to->eptr_)) ExceptionPtr(from->eptr_);
- }
- inline void exception_wrapper::ExceptionPtr::move_(
- exception_wrapper* from,
- exception_wrapper* to) {
- ::new (static_cast<void*>(&to->eptr_)) ExceptionPtr(std::move(from->eptr_));
- delete_(from);
- }
- inline void exception_wrapper::ExceptionPtr::delete_(exception_wrapper* that) {
- that->eptr_.~ExceptionPtr();
- that->vptr_ = &uninit_;
- }
- [[noreturn]] inline void exception_wrapper::ExceptionPtr::throw_(
- exception_wrapper const* that) {
- std::rethrow_exception(that->eptr_.ptr_);
- }
- inline std::type_info const* exception_wrapper::ExceptionPtr::type_(
- exception_wrapper const* that) {
- if (auto e = get_exception_(that)) {
- return &typeid(*e);
- }
- return that->eptr_.as_type_();
- }
- inline std::exception const* exception_wrapper::ExceptionPtr::get_exception_(
- exception_wrapper const* that) {
- return that->eptr_.has_exception_() ? that->eptr_.as_exception_() : nullptr;
- }
- inline exception_wrapper exception_wrapper::ExceptionPtr::get_exception_ptr_(
- exception_wrapper const* that) {
- return *that;
- }
- template <class Ex>
- inline void exception_wrapper::InPlace<Ex>::copy_(
- exception_wrapper const* from,
- exception_wrapper* to) {
- ::new (static_cast<void*>(std::addressof(to->buff_.as<Ex>())))
- Ex(from->buff_.as<Ex>());
- }
- template <class Ex>
- inline void exception_wrapper::InPlace<Ex>::move_(
- exception_wrapper* from,
- exception_wrapper* to) {
- ::new (static_cast<void*>(std::addressof(to->buff_.as<Ex>())))
- Ex(std::move(from->buff_.as<Ex>()));
- delete_(from);
- }
- template <class Ex>
- inline void exception_wrapper::InPlace<Ex>::delete_(exception_wrapper* that) {
- that->buff_.as<Ex>().~Ex();
- that->vptr_ = &uninit_;
- }
- template <class Ex>
- [[noreturn]] inline void exception_wrapper::InPlace<Ex>::throw_(
- exception_wrapper const* that) {
- throw that->buff_.as<Ex>(); // @nolint
- }
- template <class Ex>
- inline std::type_info const* exception_wrapper::InPlace<Ex>::type_(
- exception_wrapper const*) {
- return &typeid(Ex);
- }
- template <class Ex>
- inline std::exception const* exception_wrapper::InPlace<Ex>::get_exception_(
- exception_wrapper const* that) {
- return as_exception_or_null_(that->buff_.as<Ex>());
- }
- template <class Ex>
- inline exception_wrapper exception_wrapper::InPlace<Ex>::get_exception_ptr_(
- exception_wrapper const* that) {
- try {
- throw_(that);
- } catch (Ex const& ex) {
- return exception_wrapper{std::current_exception(), ex};
- }
- }
- template <class Ex>
- [[noreturn]] inline void exception_wrapper::SharedPtr::Impl<Ex>::throw_()
- const {
- throw ex_; // @nolint
- }
- template <class Ex>
- inline std::exception const*
- exception_wrapper::SharedPtr::Impl<Ex>::get_exception_() const noexcept {
- return as_exception_or_null_(ex_);
- }
- template <class Ex>
- inline exception_wrapper
- exception_wrapper::SharedPtr::Impl<Ex>::get_exception_ptr_() const noexcept {
- try {
- throw_();
- } catch (Ex& ex) {
- return exception_wrapper{std::current_exception(), ex};
- }
- }
- inline void exception_wrapper::SharedPtr::copy_(
- exception_wrapper const* from,
- exception_wrapper* to) {
- ::new (static_cast<void*>(std::addressof(to->sptr_))) SharedPtr(from->sptr_);
- }
- inline void exception_wrapper::SharedPtr::move_(
- exception_wrapper* from,
- exception_wrapper* to) {
- ::new (static_cast<void*>(std::addressof(to->sptr_)))
- SharedPtr(std::move(from->sptr_));
- delete_(from);
- }
- inline void exception_wrapper::SharedPtr::delete_(exception_wrapper* that) {
- that->sptr_.~SharedPtr();
- that->vptr_ = &uninit_;
- }
- [[noreturn]] inline void exception_wrapper::SharedPtr::throw_(
- exception_wrapper const* that) {
- that->sptr_.ptr_->throw_();
- folly::assume_unreachable();
- }
- inline std::type_info const* exception_wrapper::SharedPtr::type_(
- exception_wrapper const* that) {
- return that->sptr_.ptr_->info_;
- }
- inline std::exception const* exception_wrapper::SharedPtr::get_exception_(
- exception_wrapper const* that) {
- return that->sptr_.ptr_->get_exception_();
- }
- inline exception_wrapper exception_wrapper::SharedPtr::get_exception_ptr_(
- exception_wrapper const* that) {
- return that->sptr_.ptr_->get_exception_ptr_();
- }
- template <class Ex, typename... As>
- inline exception_wrapper::exception_wrapper(
- ThrownTag,
- in_place_type_t<Ex>,
- 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_) {}
- template <class Ex, typename... As>
- inline exception_wrapper::exception_wrapper(
- OnHeapTag,
- in_place_type_t<Ex>,
- As&&... as)
- : sptr_{std::make_shared<SharedPtr::Impl<Ex>>(std::forward<As>(as)...)},
- vptr_(&SharedPtr::ops_) {}
- template <class Ex, typename... As>
- inline exception_wrapper::exception_wrapper(
- InSituTag,
- in_place_type_t<Ex>,
- As&&... as)
- : buff_{in_place_type<Ex>, std::forward<As>(as)...},
- vptr_(&InPlace<Ex>::ops_) {}
- inline exception_wrapper::exception_wrapper(exception_wrapper&& that) noexcept
- : exception_wrapper{} {
- (vptr_ = that.vptr_)->move_(&that, this); // Move into *this, won't throw
- }
- inline exception_wrapper::exception_wrapper(
- exception_wrapper const& that) noexcept
- : exception_wrapper{} {
- that.vptr_->copy_(&that, this); // Copy into *this, won't throw
- vptr_ = that.vptr_;
- }
- // If `this == &that`, this move assignment operator leaves the object in a
- // valid but unspecified state.
- inline exception_wrapper& exception_wrapper::operator=(
- exception_wrapper&& that) noexcept {
- vptr_->delete_(this); // Free the current exception
- (vptr_ = that.vptr_)->move_(&that, this); // Move into *this, won't throw
- return *this;
- }
- inline exception_wrapper& exception_wrapper::operator=(
- exception_wrapper const& that) noexcept {
- exception_wrapper(that).swap(*this);
- return *this;
- }
- inline exception_wrapper::~exception_wrapper() {
- reset();
- }
- template <class Ex>
- inline exception_wrapper::exception_wrapper(
- std::exception_ptr ptr,
- Ex& ex) noexcept
- : eptr_{ptr, ExceptionPtr::as_int_(ptr, ex)}, vptr_(&ExceptionPtr::ops_) {
- assert(eptr_.ptr_);
- }
- namespace exception_wrapper_detail {
- template <class Ex>
- Ex&& dont_slice(Ex&& ex) {
- assert(typeid(ex) == typeid(_t<std::decay<Ex>>) ||
- !"Dynamic and static exception types don't match. Exception would "
- "be sliced when storing in exception_wrapper.");
- return std::forward<Ex>(ex);
- }
- } // namespace exception_wrapper_detail
- template <
- class Ex,
- class Ex_,
- FOLLY_REQUIRES_DEF(Conjunction<
- exception_wrapper::IsStdException<Ex_>,
- exception_wrapper::IsRegularExceptionType<Ex_>>::value)>
- inline exception_wrapper::exception_wrapper(Ex&& ex)
- : exception_wrapper{
- PlacementOf<Ex_>{},
- in_place_type<Ex_>,
- exception_wrapper_detail::dont_slice(std::forward<Ex>(ex))} {}
- template <
- class Ex,
- class Ex_,
- FOLLY_REQUIRES_DEF(exception_wrapper::IsRegularExceptionType<Ex_>::value)>
- inline exception_wrapper::exception_wrapper(in_place_t, Ex&& ex)
- : exception_wrapper{
- PlacementOf<Ex_>{},
- in_place_type<Ex_>,
- exception_wrapper_detail::dont_slice(std::forward<Ex>(ex))} {}
- template <
- class Ex,
- typename... As,
- FOLLY_REQUIRES_DEF(exception_wrapper::IsRegularExceptionType<Ex>::value)>
- inline exception_wrapper::exception_wrapper(in_place_type_t<Ex>, As&&... as)
- : exception_wrapper{PlacementOf<Ex>{},
- in_place_type<Ex>,
- std::forward<As>(as)...} {}
- inline void exception_wrapper::swap(exception_wrapper& that) noexcept {
- exception_wrapper tmp(std::move(that));
- that = std::move(*this);
- *this = std::move(tmp);
- }
- inline exception_wrapper::operator bool() const noexcept {
- return vptr_ != &uninit_;
- }
- inline bool exception_wrapper::operator!() const noexcept {
- return !static_cast<bool>(*this);
- }
- inline void exception_wrapper::reset() {
- vptr_->delete_(this);
- }
- inline bool exception_wrapper::has_exception_ptr() const noexcept {
- return vptr_ == &ExceptionPtr::ops_;
- }
- inline std::exception* exception_wrapper::get_exception() noexcept {
- return const_cast<std::exception*>(vptr_->get_exception_(this));
- }
- inline std::exception const* exception_wrapper::get_exception() const noexcept {
- return vptr_->get_exception_(this);
- }
- template <typename Ex>
- inline Ex* exception_wrapper::get_exception() noexcept {
- Ex* object{nullptr};
- with_exception([&](Ex& ex) { object = &ex; });
- return object;
- }
- template <typename Ex>
- inline Ex const* exception_wrapper::get_exception() const noexcept {
- Ex const* object{nullptr};
- with_exception([&](Ex const& ex) { object = &ex; });
- return object;
- }
- inline std::exception_ptr const&
- exception_wrapper::to_exception_ptr() noexcept {
- // Computing an exception_ptr is expensive so cache the result.
- return (*this = vptr_->get_exception_ptr_(this)).eptr_.ptr_;
- }
- inline std::exception_ptr exception_wrapper::to_exception_ptr() const noexcept {
- return vptr_->get_exception_ptr_(this).eptr_.ptr_;
- }
- inline std::type_info const& exception_wrapper::none() noexcept {
- 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 {
- return *vptr_->type_(this);
- }
- inline folly::fbstring exception_wrapper::what() const {
- if (auto e = get_exception()) {
- return class_name() + ": " + e->what();
- }
- return class_name();
- }
- inline folly::fbstring exception_wrapper::class_name() const {
- auto& ti = type();
- return ti == none()
- ? ""
- : ti == unknown() ? "<unknown exception>" : folly::demangle(ti);
- }
- template <class Ex>
- inline bool exception_wrapper::is_compatible_with() const noexcept {
- return with_exception([](Ex const&) {});
- }
- [[noreturn]] inline void exception_wrapper::throw_exception() const {
- vptr_->throw_(this);
- 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>>>;
- static_assert(
- std::is_reference<type>::value,
- "Always catch exceptions by reference.");
- static_assert(
- !IsConst || std::is_const<_t<std::remove_reference<type>>>::value,
- "handle() or with_exception() called on a const exception_wrapper "
- "and asked to catch a non-const exception. Handler will never fire. "
- "Catch exception by const reference to fix this.");
- };
- // Nests a throw in the proper try/catch blocks
- template <bool IsConst>
- struct exception_wrapper::HandleReduce {
- bool* handled_;
- template <
- class ThrowFn,
- class CatchFn,
- FOLLY_REQUIRES(!IsCatchAll<CatchFn>::value)>
- auto operator()(ThrowFn&& th, CatchFn& ca) const {
- using Ex = _t<ExceptionTypeOf<CatchFn, IsConst>>;
- return [th = std::forward<ThrowFn>(th), &ca, handled_ = handled_] {
- try {
- th();
- } catch (Ex& e) {
- // If we got here because a catch function threw, rethrow.
- if (*handled_) {
- throw;
- }
- *handled_ = true;
- ca(e);
- }
- };
- }
- template <
- class ThrowFn,
- class CatchFn,
- FOLLY_REQUIRES(IsCatchAll<CatchFn>::value)>
- auto operator()(ThrowFn&& th, CatchFn& ca) const {
- return [th = std::forward<ThrowFn>(th), &ca, handled_ = handled_] {
- try {
- th();
- } catch (...) {
- // If we got here because a catch function threw, rethrow.
- if (*handled_) {
- throw;
- }
- *handled_ = true;
- ca();
- }
- };
- }
- };
- // When all the handlers expect types derived from std::exception, we can
- // sometimes invoke the handlers without throwing any exceptions.
- template <bool IsConst>
- struct exception_wrapper::HandleStdExceptReduce {
- using StdEx = AddConstIf<IsConst, std::exception>;
- template <
- class ThrowFn,
- class CatchFn,
- FOLLY_REQUIRES(!IsCatchAll<CatchFn>::value)>
- auto operator()(ThrowFn&& th, CatchFn& ca) const {
- using Ex = _t<ExceptionTypeOf<CatchFn, IsConst>>;
- return
- [th = std::forward<ThrowFn>(th), &ca](auto&& continuation) -> StdEx* {
- if (auto e = const_cast<StdEx*>(th(continuation))) {
- if (auto e2 = dynamic_cast<_t<std::add_pointer<Ex>>>(e)) {
- ca(*e2);
- } else {
- return e;
- }
- }
- return nullptr;
- };
- }
- template <
- class ThrowFn,
- class CatchFn,
- FOLLY_REQUIRES(IsCatchAll<CatchFn>::value)>
- auto operator()(ThrowFn&& th, CatchFn& ca) const {
- return [th = std::forward<ThrowFn>(th), &ca](auto &&) -> StdEx* {
- // The following continuation causes ca() to execute if *this contains
- // an exception /not/ derived from std::exception.
- auto continuation = [&ca](StdEx* e) {
- return e != nullptr ? e : ((void)ca(), nullptr);
- };
- if (th(continuation) != nullptr) {
- ca();
- }
- return nullptr;
- };
- }
- };
- // Called when some types in the catch clauses are not derived from
- // std::exception.
- template <class This, class... CatchFns>
- inline void
- exception_wrapper::handle_(std::false_type, This& this_, CatchFns&... fns) {
- bool handled = false;
- auto impl = exception_wrapper_detail::fold(
- HandleReduce<std::is_const<This>::value>{&handled},
- [&] { this_.throw_exception(); },
- fns...);
- impl();
- }
- // Called when all types in the catch clauses are either derived from
- // std::exception or a catch-all clause.
- template <class This, class... CatchFns>
- inline void
- exception_wrapper::handle_(std::true_type, This& this_, CatchFns&... fns) {
- using StdEx = exception_wrapper_detail::
- AddConstIf<std::is_const<This>::value, std::exception>;
- auto impl = exception_wrapper_detail::fold(
- HandleStdExceptReduce<std::is_const<This>::value>{},
- [&](auto&& continuation) {
- return continuation(
- const_cast<StdEx*>(this_.vptr_->get_exception_(&this_)));
- },
- fns...);
- // This continuation gets evaluated if CatchFns... does not include a
- // catch-all handler. It is a no-op.
- auto continuation = [](StdEx* ex) { return ex; };
- if (nullptr != impl(continuation)) {
- this_.throw_exception();
- }
- }
- namespace exception_wrapper_detail {
- template <class Ex, class Fn>
- struct catch_fn {
- Fn fn_;
- auto operator()(Ex& ex) {
- return fn_(ex);
- }
- };
- template <class Ex, class Fn>
- inline catch_fn<Ex, Fn> catch_(Ex*, Fn fn) {
- return {std::move(fn)};
- }
- template <class Fn>
- inline Fn catch_(void const*, Fn fn) {
- return fn;
- }
- } // namespace exception_wrapper_detail
- template <class Ex, class This, class Fn>
- inline bool exception_wrapper::with_exception_(This& this_, Fn fn_) {
- if (!this_) {
- return false;
- }
- bool handled = true;
- auto fn = exception_wrapper_detail::catch_(
- static_cast<Ex*>(nullptr), std::move(fn_));
- auto&& all = [&](...) { handled = false; };
- handle_(IsStdException<arg_type<decltype(fn)>>{}, this_, fn, all);
- return handled;
- }
- template <class Ex, class Fn>
- inline bool exception_wrapper::with_exception(Fn fn) {
- return with_exception_<Ex>(*this, std::move(fn));
- }
- template <class Ex, class Fn>
- inline bool exception_wrapper::with_exception(Fn fn) const {
- return with_exception_<Ex const>(*this, std::move(fn));
- }
- template <class... CatchFns>
- inline void exception_wrapper::handle(CatchFns... fns) {
- using AllStdEx =
- exception_wrapper_detail::AllOf<IsStdException, arg_type<CatchFns>...>;
- if (!*this) {
- onNoExceptionError(__func__);
- }
- this->handle_(AllStdEx{}, *this, fns...);
- }
- template <class... CatchFns>
- inline void exception_wrapper::handle(CatchFns... fns) const {
- using AllStdEx =
- exception_wrapper_detail::AllOf<IsStdException, arg_type<CatchFns>...>;
- if (!*this) {
- onNoExceptionError(__func__);
- }
- this->handle_(AllStdEx{}, *this, fns...);
- }
- } // namespace folly
|