ExceptionWrapper-inl.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. *
  18. * Author: Eric Niebler <eniebler@fb.com>
  19. */
  20. #include <folly/Portability.h>
  21. namespace folly {
  22. template <class Fn>
  23. struct exception_wrapper::arg_type_
  24. : public arg_type_<decltype(&Fn::operator())> {};
  25. template <class Ret, class Class, class Arg>
  26. struct exception_wrapper::arg_type_<Ret (Class::*)(Arg)> {
  27. using type = Arg;
  28. };
  29. template <class Ret, class Class, class Arg>
  30. struct exception_wrapper::arg_type_<Ret (Class::*)(Arg) const> {
  31. using type = Arg;
  32. };
  33. template <class Ret, class Arg>
  34. struct exception_wrapper::arg_type_<Ret(Arg)> {
  35. using type = Arg;
  36. };
  37. template <class Ret, class Arg>
  38. struct exception_wrapper::arg_type_<Ret (*)(Arg)> {
  39. using type = Arg;
  40. };
  41. template <class Ret, class Class>
  42. struct exception_wrapper::arg_type_<Ret (Class::*)(...)> {
  43. using type = AnyException;
  44. };
  45. template <class Ret, class Class>
  46. struct exception_wrapper::arg_type_<Ret (Class::*)(...) const> {
  47. using type = AnyException;
  48. };
  49. template <class Ret>
  50. struct exception_wrapper::arg_type_<Ret(...)> {
  51. using type = AnyException;
  52. };
  53. template <class Ret>
  54. struct exception_wrapper::arg_type_<Ret (*)(...)> {
  55. using type = AnyException;
  56. };
  57. template <class Ret, class... Args>
  58. inline Ret exception_wrapper::noop_(Args...) {
  59. return Ret();
  60. }
  61. inline std::type_info const* exception_wrapper::uninit_type_(
  62. exception_wrapper const*) {
  63. return &typeid(void);
  64. }
  65. template <class Ex, typename... As>
  66. inline exception_wrapper::Buffer::Buffer(in_place_type_t<Ex>, As&&... as_) {
  67. ::new (static_cast<void*>(&buff_)) Ex(std::forward<As>(as_)...);
  68. }
  69. template <class Ex>
  70. inline Ex& exception_wrapper::Buffer::as() noexcept {
  71. return *static_cast<Ex*>(static_cast<void*>(&buff_));
  72. }
  73. template <class Ex>
  74. inline Ex const& exception_wrapper::Buffer::as() const noexcept {
  75. return *static_cast<Ex const*>(static_cast<void const*>(&buff_));
  76. }
  77. inline std::exception const* exception_wrapper::as_exception_or_null_(
  78. std::exception const& ex) {
  79. return &ex;
  80. }
  81. inline std::exception const* exception_wrapper::as_exception_or_null_(
  82. AnyException) {
  83. return nullptr;
  84. }
  85. static_assert(
  86. !kMicrosoftAbiVer || (kMicrosoftAbiVer >= 1900 && kMicrosoftAbiVer <= 2000),
  87. "exception_wrapper is untested and possibly broken on your version of "
  88. "MSVC");
  89. inline std::uintptr_t exception_wrapper::ExceptionPtr::as_int_(
  90. std::exception_ptr const& ptr,
  91. std::exception const& e) noexcept {
  92. if (!kMicrosoftAbiVer) {
  93. return reinterpret_cast<std::uintptr_t>(&e);
  94. } else {
  95. // On Windows, as of MSVC2017, all thrown exceptions are copied to the stack
  96. // first. Thus, we cannot depend on exception references associated with an
  97. // exception_ptr to be live for the duration of the exception_ptr. We need
  98. // to directly access the heap allocated memory inside the exception_ptr.
  99. //
  100. // std::exception_ptr is an opaque reinterpret_cast of
  101. // std::shared_ptr<__ExceptionPtr>
  102. // __ExceptionPtr is a non-virtual class with two members, a union and a
  103. // bool. The union contains the now-undocumented EHExceptionRecord, which
  104. // contains a struct which contains a void* which points to the heap
  105. // allocated exception.
  106. // We derive the offset to pExceptionObject via manual means.
  107. FOLLY_PACK_PUSH
  108. struct Win32ExceptionPtr {
  109. char offset[8 + 4 * sizeof(void*)];
  110. void* exceptionObject;
  111. } FOLLY_PACK_ATTR;
  112. FOLLY_PACK_POP
  113. auto* win32ExceptionPtr =
  114. reinterpret_cast<std::shared_ptr<Win32ExceptionPtr> const*>(&ptr)
  115. ->get();
  116. return reinterpret_cast<std::uintptr_t>(win32ExceptionPtr->exceptionObject);
  117. }
  118. }
  119. inline std::uintptr_t exception_wrapper::ExceptionPtr::as_int_(
  120. std::exception_ptr const&,
  121. AnyException e) noexcept {
  122. return reinterpret_cast<std::uintptr_t>(e.typeinfo_) + 1;
  123. }
  124. inline bool exception_wrapper::ExceptionPtr::has_exception_() const {
  125. return 0 == exception_or_type_ % 2;
  126. }
  127. inline std::exception const* exception_wrapper::ExceptionPtr::as_exception_()
  128. const {
  129. return reinterpret_cast<std::exception const*>(exception_or_type_);
  130. }
  131. inline std::type_info const* exception_wrapper::ExceptionPtr::as_type_() const {
  132. return reinterpret_cast<std::type_info const*>(exception_or_type_ - 1);
  133. }
  134. inline void exception_wrapper::ExceptionPtr::copy_(
  135. exception_wrapper const* from,
  136. exception_wrapper* to) {
  137. ::new (static_cast<void*>(&to->eptr_)) ExceptionPtr(from->eptr_);
  138. }
  139. inline void exception_wrapper::ExceptionPtr::move_(
  140. exception_wrapper* from,
  141. exception_wrapper* to) {
  142. ::new (static_cast<void*>(&to->eptr_)) ExceptionPtr(std::move(from->eptr_));
  143. delete_(from);
  144. }
  145. inline void exception_wrapper::ExceptionPtr::delete_(exception_wrapper* that) {
  146. that->eptr_.~ExceptionPtr();
  147. that->vptr_ = &uninit_;
  148. }
  149. [[noreturn]] inline void exception_wrapper::ExceptionPtr::throw_(
  150. exception_wrapper const* that) {
  151. std::rethrow_exception(that->eptr_.ptr_);
  152. }
  153. inline std::type_info const* exception_wrapper::ExceptionPtr::type_(
  154. exception_wrapper const* that) {
  155. if (auto e = get_exception_(that)) {
  156. return &typeid(*e);
  157. }
  158. return that->eptr_.as_type_();
  159. }
  160. inline std::exception const* exception_wrapper::ExceptionPtr::get_exception_(
  161. exception_wrapper const* that) {
  162. return that->eptr_.has_exception_() ? that->eptr_.as_exception_() : nullptr;
  163. }
  164. inline exception_wrapper exception_wrapper::ExceptionPtr::get_exception_ptr_(
  165. exception_wrapper const* that) {
  166. return *that;
  167. }
  168. template <class Ex>
  169. inline void exception_wrapper::InPlace<Ex>::copy_(
  170. exception_wrapper const* from,
  171. exception_wrapper* to) {
  172. ::new (static_cast<void*>(std::addressof(to->buff_.as<Ex>())))
  173. Ex(from->buff_.as<Ex>());
  174. }
  175. template <class Ex>
  176. inline void exception_wrapper::InPlace<Ex>::move_(
  177. exception_wrapper* from,
  178. exception_wrapper* to) {
  179. ::new (static_cast<void*>(std::addressof(to->buff_.as<Ex>())))
  180. Ex(std::move(from->buff_.as<Ex>()));
  181. delete_(from);
  182. }
  183. template <class Ex>
  184. inline void exception_wrapper::InPlace<Ex>::delete_(exception_wrapper* that) {
  185. that->buff_.as<Ex>().~Ex();
  186. that->vptr_ = &uninit_;
  187. }
  188. template <class Ex>
  189. [[noreturn]] inline void exception_wrapper::InPlace<Ex>::throw_(
  190. exception_wrapper const* that) {
  191. throw that->buff_.as<Ex>(); // @nolint
  192. }
  193. template <class Ex>
  194. inline std::type_info const* exception_wrapper::InPlace<Ex>::type_(
  195. exception_wrapper const*) {
  196. return &typeid(Ex);
  197. }
  198. template <class Ex>
  199. inline std::exception const* exception_wrapper::InPlace<Ex>::get_exception_(
  200. exception_wrapper const* that) {
  201. return as_exception_or_null_(that->buff_.as<Ex>());
  202. }
  203. template <class Ex>
  204. inline exception_wrapper exception_wrapper::InPlace<Ex>::get_exception_ptr_(
  205. exception_wrapper const* that) {
  206. try {
  207. throw_(that);
  208. } catch (Ex const& ex) {
  209. return exception_wrapper{std::current_exception(), ex};
  210. }
  211. }
  212. template <class Ex>
  213. [[noreturn]] inline void exception_wrapper::SharedPtr::Impl<Ex>::throw_()
  214. const {
  215. throw ex_; // @nolint
  216. }
  217. template <class Ex>
  218. inline std::exception const*
  219. exception_wrapper::SharedPtr::Impl<Ex>::get_exception_() const noexcept {
  220. return as_exception_or_null_(ex_);
  221. }
  222. template <class Ex>
  223. inline exception_wrapper
  224. exception_wrapper::SharedPtr::Impl<Ex>::get_exception_ptr_() const noexcept {
  225. try {
  226. throw_();
  227. } catch (Ex& ex) {
  228. return exception_wrapper{std::current_exception(), ex};
  229. }
  230. }
  231. inline void exception_wrapper::SharedPtr::copy_(
  232. exception_wrapper const* from,
  233. exception_wrapper* to) {
  234. ::new (static_cast<void*>(std::addressof(to->sptr_))) SharedPtr(from->sptr_);
  235. }
  236. inline void exception_wrapper::SharedPtr::move_(
  237. exception_wrapper* from,
  238. exception_wrapper* to) {
  239. ::new (static_cast<void*>(std::addressof(to->sptr_)))
  240. SharedPtr(std::move(from->sptr_));
  241. delete_(from);
  242. }
  243. inline void exception_wrapper::SharedPtr::delete_(exception_wrapper* that) {
  244. that->sptr_.~SharedPtr();
  245. that->vptr_ = &uninit_;
  246. }
  247. [[noreturn]] inline void exception_wrapper::SharedPtr::throw_(
  248. exception_wrapper const* that) {
  249. that->sptr_.ptr_->throw_();
  250. folly::assume_unreachable();
  251. }
  252. inline std::type_info const* exception_wrapper::SharedPtr::type_(
  253. exception_wrapper const* that) {
  254. return that->sptr_.ptr_->info_;
  255. }
  256. inline std::exception const* exception_wrapper::SharedPtr::get_exception_(
  257. exception_wrapper const* that) {
  258. return that->sptr_.ptr_->get_exception_();
  259. }
  260. inline exception_wrapper exception_wrapper::SharedPtr::get_exception_ptr_(
  261. exception_wrapper const* that) {
  262. return that->sptr_.ptr_->get_exception_ptr_();
  263. }
  264. template <class Ex, typename... As>
  265. inline exception_wrapper::exception_wrapper(
  266. ThrownTag,
  267. in_place_type_t<Ex>,
  268. As&&... as)
  269. : eptr_{std::make_exception_ptr(Ex(std::forward<As>(as)...)),
  270. reinterpret_cast<std::uintptr_t>(std::addressof(typeid(Ex))) + 1u},
  271. vptr_(&ExceptionPtr::ops_) {}
  272. template <class Ex, typename... As>
  273. inline exception_wrapper::exception_wrapper(
  274. OnHeapTag,
  275. in_place_type_t<Ex>,
  276. As&&... as)
  277. : sptr_{std::make_shared<SharedPtr::Impl<Ex>>(std::forward<As>(as)...)},
  278. vptr_(&SharedPtr::ops_) {}
  279. template <class Ex, typename... As>
  280. inline exception_wrapper::exception_wrapper(
  281. InSituTag,
  282. in_place_type_t<Ex>,
  283. As&&... as)
  284. : buff_{in_place_type<Ex>, std::forward<As>(as)...},
  285. vptr_(&InPlace<Ex>::ops_) {}
  286. inline exception_wrapper::exception_wrapper(exception_wrapper&& that) noexcept
  287. : exception_wrapper{} {
  288. (vptr_ = that.vptr_)->move_(&that, this); // Move into *this, won't throw
  289. }
  290. inline exception_wrapper::exception_wrapper(
  291. exception_wrapper const& that) noexcept
  292. : exception_wrapper{} {
  293. that.vptr_->copy_(&that, this); // Copy into *this, won't throw
  294. vptr_ = that.vptr_;
  295. }
  296. // If `this == &that`, this move assignment operator leaves the object in a
  297. // valid but unspecified state.
  298. inline exception_wrapper& exception_wrapper::operator=(
  299. exception_wrapper&& that) noexcept {
  300. vptr_->delete_(this); // Free the current exception
  301. (vptr_ = that.vptr_)->move_(&that, this); // Move into *this, won't throw
  302. return *this;
  303. }
  304. inline exception_wrapper& exception_wrapper::operator=(
  305. exception_wrapper const& that) noexcept {
  306. exception_wrapper(that).swap(*this);
  307. return *this;
  308. }
  309. inline exception_wrapper::~exception_wrapper() {
  310. reset();
  311. }
  312. template <class Ex>
  313. inline exception_wrapper::exception_wrapper(
  314. std::exception_ptr ptr,
  315. Ex& ex) noexcept
  316. : eptr_{ptr, ExceptionPtr::as_int_(ptr, ex)}, vptr_(&ExceptionPtr::ops_) {
  317. assert(eptr_.ptr_);
  318. }
  319. namespace exception_wrapper_detail {
  320. template <class Ex>
  321. Ex&& dont_slice(Ex&& ex) {
  322. assert(typeid(ex) == typeid(_t<std::decay<Ex>>) ||
  323. !"Dynamic and static exception types don't match. Exception would "
  324. "be sliced when storing in exception_wrapper.");
  325. return std::forward<Ex>(ex);
  326. }
  327. } // namespace exception_wrapper_detail
  328. template <
  329. class Ex,
  330. class Ex_,
  331. FOLLY_REQUIRES_DEF(Conjunction<
  332. exception_wrapper::IsStdException<Ex_>,
  333. exception_wrapper::IsRegularExceptionType<Ex_>>::value)>
  334. inline exception_wrapper::exception_wrapper(Ex&& ex)
  335. : exception_wrapper{
  336. PlacementOf<Ex_>{},
  337. in_place_type<Ex_>,
  338. exception_wrapper_detail::dont_slice(std::forward<Ex>(ex))} {}
  339. template <
  340. class Ex,
  341. class Ex_,
  342. FOLLY_REQUIRES_DEF(exception_wrapper::IsRegularExceptionType<Ex_>::value)>
  343. inline exception_wrapper::exception_wrapper(in_place_t, Ex&& ex)
  344. : exception_wrapper{
  345. PlacementOf<Ex_>{},
  346. in_place_type<Ex_>,
  347. exception_wrapper_detail::dont_slice(std::forward<Ex>(ex))} {}
  348. template <
  349. class Ex,
  350. typename... As,
  351. FOLLY_REQUIRES_DEF(exception_wrapper::IsRegularExceptionType<Ex>::value)>
  352. inline exception_wrapper::exception_wrapper(in_place_type_t<Ex>, As&&... as)
  353. : exception_wrapper{PlacementOf<Ex>{},
  354. in_place_type<Ex>,
  355. std::forward<As>(as)...} {}
  356. inline void exception_wrapper::swap(exception_wrapper& that) noexcept {
  357. exception_wrapper tmp(std::move(that));
  358. that = std::move(*this);
  359. *this = std::move(tmp);
  360. }
  361. inline exception_wrapper::operator bool() const noexcept {
  362. return vptr_ != &uninit_;
  363. }
  364. inline bool exception_wrapper::operator!() const noexcept {
  365. return !static_cast<bool>(*this);
  366. }
  367. inline void exception_wrapper::reset() {
  368. vptr_->delete_(this);
  369. }
  370. inline bool exception_wrapper::has_exception_ptr() const noexcept {
  371. return vptr_ == &ExceptionPtr::ops_;
  372. }
  373. inline std::exception* exception_wrapper::get_exception() noexcept {
  374. return const_cast<std::exception*>(vptr_->get_exception_(this));
  375. }
  376. inline std::exception const* exception_wrapper::get_exception() const noexcept {
  377. return vptr_->get_exception_(this);
  378. }
  379. template <typename Ex>
  380. inline Ex* exception_wrapper::get_exception() noexcept {
  381. Ex* object{nullptr};
  382. with_exception([&](Ex& ex) { object = &ex; });
  383. return object;
  384. }
  385. template <typename Ex>
  386. inline Ex const* exception_wrapper::get_exception() const noexcept {
  387. Ex const* object{nullptr};
  388. with_exception([&](Ex const& ex) { object = &ex; });
  389. return object;
  390. }
  391. inline std::exception_ptr const&
  392. exception_wrapper::to_exception_ptr() noexcept {
  393. // Computing an exception_ptr is expensive so cache the result.
  394. return (*this = vptr_->get_exception_ptr_(this)).eptr_.ptr_;
  395. }
  396. inline std::exception_ptr exception_wrapper::to_exception_ptr() const noexcept {
  397. return vptr_->get_exception_ptr_(this).eptr_.ptr_;
  398. }
  399. inline std::type_info const& exception_wrapper::none() noexcept {
  400. return typeid(void);
  401. }
  402. inline std::type_info const& exception_wrapper::unknown() noexcept {
  403. return typeid(Unknown);
  404. }
  405. inline std::type_info const& exception_wrapper::type() const noexcept {
  406. return *vptr_->type_(this);
  407. }
  408. inline folly::fbstring exception_wrapper::what() const {
  409. if (auto e = get_exception()) {
  410. return class_name() + ": " + e->what();
  411. }
  412. return class_name();
  413. }
  414. inline folly::fbstring exception_wrapper::class_name() const {
  415. auto& ti = type();
  416. return ti == none()
  417. ? ""
  418. : ti == unknown() ? "<unknown exception>" : folly::demangle(ti);
  419. }
  420. template <class Ex>
  421. inline bool exception_wrapper::is_compatible_with() const noexcept {
  422. return with_exception([](Ex const&) {});
  423. }
  424. [[noreturn]] inline void exception_wrapper::throw_exception() const {
  425. vptr_->throw_(this);
  426. onNoExceptionError(__func__);
  427. }
  428. template <class Ex>
  429. [[noreturn]] inline void exception_wrapper::throw_with_nested(Ex&& ex) const {
  430. try {
  431. throw_exception();
  432. } catch (...) {
  433. std::throw_with_nested(std::forward<Ex>(ex));
  434. }
  435. }
  436. template <class CatchFn, bool IsConst>
  437. struct exception_wrapper::ExceptionTypeOf {
  438. using type = arg_type<_t<std::decay<CatchFn>>>;
  439. static_assert(
  440. std::is_reference<type>::value,
  441. "Always catch exceptions by reference.");
  442. static_assert(
  443. !IsConst || std::is_const<_t<std::remove_reference<type>>>::value,
  444. "handle() or with_exception() called on a const exception_wrapper "
  445. "and asked to catch a non-const exception. Handler will never fire. "
  446. "Catch exception by const reference to fix this.");
  447. };
  448. // Nests a throw in the proper try/catch blocks
  449. template <bool IsConst>
  450. struct exception_wrapper::HandleReduce {
  451. bool* handled_;
  452. template <
  453. class ThrowFn,
  454. class CatchFn,
  455. FOLLY_REQUIRES(!IsCatchAll<CatchFn>::value)>
  456. auto operator()(ThrowFn&& th, CatchFn& ca) const {
  457. using Ex = _t<ExceptionTypeOf<CatchFn, IsConst>>;
  458. return [th = std::forward<ThrowFn>(th), &ca, handled_ = handled_] {
  459. try {
  460. th();
  461. } catch (Ex& e) {
  462. // If we got here because a catch function threw, rethrow.
  463. if (*handled_) {
  464. throw;
  465. }
  466. *handled_ = true;
  467. ca(e);
  468. }
  469. };
  470. }
  471. template <
  472. class ThrowFn,
  473. class CatchFn,
  474. FOLLY_REQUIRES(IsCatchAll<CatchFn>::value)>
  475. auto operator()(ThrowFn&& th, CatchFn& ca) const {
  476. return [th = std::forward<ThrowFn>(th), &ca, handled_ = handled_] {
  477. try {
  478. th();
  479. } catch (...) {
  480. // If we got here because a catch function threw, rethrow.
  481. if (*handled_) {
  482. throw;
  483. }
  484. *handled_ = true;
  485. ca();
  486. }
  487. };
  488. }
  489. };
  490. // When all the handlers expect types derived from std::exception, we can
  491. // sometimes invoke the handlers without throwing any exceptions.
  492. template <bool IsConst>
  493. struct exception_wrapper::HandleStdExceptReduce {
  494. using StdEx = AddConstIf<IsConst, std::exception>;
  495. template <
  496. class ThrowFn,
  497. class CatchFn,
  498. FOLLY_REQUIRES(!IsCatchAll<CatchFn>::value)>
  499. auto operator()(ThrowFn&& th, CatchFn& ca) const {
  500. using Ex = _t<ExceptionTypeOf<CatchFn, IsConst>>;
  501. return
  502. [th = std::forward<ThrowFn>(th), &ca](auto&& continuation) -> StdEx* {
  503. if (auto e = const_cast<StdEx*>(th(continuation))) {
  504. if (auto e2 = dynamic_cast<_t<std::add_pointer<Ex>>>(e)) {
  505. ca(*e2);
  506. } else {
  507. return e;
  508. }
  509. }
  510. return nullptr;
  511. };
  512. }
  513. template <
  514. class ThrowFn,
  515. class CatchFn,
  516. FOLLY_REQUIRES(IsCatchAll<CatchFn>::value)>
  517. auto operator()(ThrowFn&& th, CatchFn& ca) const {
  518. return [th = std::forward<ThrowFn>(th), &ca](auto &&) -> StdEx* {
  519. // The following continuation causes ca() to execute if *this contains
  520. // an exception /not/ derived from std::exception.
  521. auto continuation = [&ca](StdEx* e) {
  522. return e != nullptr ? e : ((void)ca(), nullptr);
  523. };
  524. if (th(continuation) != nullptr) {
  525. ca();
  526. }
  527. return nullptr;
  528. };
  529. }
  530. };
  531. // Called when some types in the catch clauses are not derived from
  532. // std::exception.
  533. template <class This, class... CatchFns>
  534. inline void
  535. exception_wrapper::handle_(std::false_type, This& this_, CatchFns&... fns) {
  536. bool handled = false;
  537. auto impl = exception_wrapper_detail::fold(
  538. HandleReduce<std::is_const<This>::value>{&handled},
  539. [&] { this_.throw_exception(); },
  540. fns...);
  541. impl();
  542. }
  543. // Called when all types in the catch clauses are either derived from
  544. // std::exception or a catch-all clause.
  545. template <class This, class... CatchFns>
  546. inline void
  547. exception_wrapper::handle_(std::true_type, This& this_, CatchFns&... fns) {
  548. using StdEx = exception_wrapper_detail::
  549. AddConstIf<std::is_const<This>::value, std::exception>;
  550. auto impl = exception_wrapper_detail::fold(
  551. HandleStdExceptReduce<std::is_const<This>::value>{},
  552. [&](auto&& continuation) {
  553. return continuation(
  554. const_cast<StdEx*>(this_.vptr_->get_exception_(&this_)));
  555. },
  556. fns...);
  557. // This continuation gets evaluated if CatchFns... does not include a
  558. // catch-all handler. It is a no-op.
  559. auto continuation = [](StdEx* ex) { return ex; };
  560. if (nullptr != impl(continuation)) {
  561. this_.throw_exception();
  562. }
  563. }
  564. namespace exception_wrapper_detail {
  565. template <class Ex, class Fn>
  566. struct catch_fn {
  567. Fn fn_;
  568. auto operator()(Ex& ex) {
  569. return fn_(ex);
  570. }
  571. };
  572. template <class Ex, class Fn>
  573. inline catch_fn<Ex, Fn> catch_(Ex*, Fn fn) {
  574. return {std::move(fn)};
  575. }
  576. template <class Fn>
  577. inline Fn catch_(void const*, Fn fn) {
  578. return fn;
  579. }
  580. } // namespace exception_wrapper_detail
  581. template <class Ex, class This, class Fn>
  582. inline bool exception_wrapper::with_exception_(This& this_, Fn fn_) {
  583. if (!this_) {
  584. return false;
  585. }
  586. bool handled = true;
  587. auto fn = exception_wrapper_detail::catch_(
  588. static_cast<Ex*>(nullptr), std::move(fn_));
  589. auto&& all = [&](...) { handled = false; };
  590. handle_(IsStdException<arg_type<decltype(fn)>>{}, this_, fn, all);
  591. return handled;
  592. }
  593. template <class Ex, class Fn>
  594. inline bool exception_wrapper::with_exception(Fn fn) {
  595. return with_exception_<Ex>(*this, std::move(fn));
  596. }
  597. template <class Ex, class Fn>
  598. inline bool exception_wrapper::with_exception(Fn fn) const {
  599. return with_exception_<Ex const>(*this, std::move(fn));
  600. }
  601. template <class... CatchFns>
  602. inline void exception_wrapper::handle(CatchFns... fns) {
  603. using AllStdEx =
  604. exception_wrapper_detail::AllOf<IsStdException, arg_type<CatchFns>...>;
  605. if (!*this) {
  606. onNoExceptionError(__func__);
  607. }
  608. this->handle_(AllStdEx{}, *this, fns...);
  609. }
  610. template <class... CatchFns>
  611. inline void exception_wrapper::handle(CatchFns... fns) const {
  612. using AllStdEx =
  613. exception_wrapper_detail::AllOf<IsStdException, arg_type<CatchFns>...>;
  614. if (!*this) {
  615. onNoExceptionError(__func__);
  616. }
  617. this->handle_(AllStdEx{}, *this, fns...);
  618. }
  619. } // namespace folly