Add missing uint32 type to folly::ProgramOptions::gFlagAdders
[folly.git] / folly / ExceptionWrapper.h
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  * Author: Eric Niebler <eniebler@fb.com>
18  */
19
20 #pragma once
21
22 #include <cassert>
23 #include <cstdint>
24 #include <exception>
25 #include <iosfwd>
26 #include <memory>
27 #include <new>
28 #include <type_traits>
29 #include <typeinfo>
30 #include <utility>
31
32 #include <folly/Assume.h>
33 #include <folly/CPortability.h>
34 #include <folly/Demangle.h>
35 #include <folly/ExceptionString.h>
36 #include <folly/FBString.h>
37 #include <folly/Traits.h>
38
39 #ifdef __GNUC__
40 #pragma GCC diagnostic push
41 #pragma GCC diagnostic ignored "-Wpragmas"
42 #pragma GCC diagnostic ignored "-Wpotentially-evaluated-expression"
43 // GCC gets confused about lambda scopes and issues shadow-local warnings for
44 // parameters in totally different functions.
45 #pragma GCC diagnostic ignored "-Wshadow-local"
46 #pragma GCC diagnostic ignored "-Wshadow-compatible-local"
47 #endif
48
49 #define FOLLY_EXCEPTION_WRAPPER_H_INCLUDED
50
51 namespace folly {
52
53 #define FOLLY_REQUIRES_DEF(...) \
54   _t<std::enable_if<static_cast<bool>(__VA_ARGS__), long>>
55
56 #define FOLLY_REQUIRES(...) FOLLY_REQUIRES_DEF(__VA_ARGS__) = __LINE__
57
58 namespace exception_wrapper_detail {
59
60 template <template <class> class T, class... As>
61 using AllOf = StrictConjunction<T<As>...>;
62
63 template <bool If, class T>
64 using AddConstIf = _t<std::conditional<If, const T, T>>;
65
66 template <class Fn, class A>
67 FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN
68 auto fold(Fn&&, A&& a) {
69   return static_cast<A&&>(a);
70 }
71
72 template <class Fn, class A, class B, class... Bs>
73 FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN
74 auto fold(Fn&& fn, A&& a, B&& b, Bs&&... bs) {
75   return fold(
76       // This looks like a use of fn after a move of fn, but in reality, this is
77       // just a cast and not a move. That's because regardless of which fold
78       // overload is selected, fn gets bound to a &&. Had fold taken fn by value
79       // there would indeed be a problem here.
80       static_cast<Fn&&>(fn),
81       static_cast<Fn&&>(fn)(static_cast<A&&>(a), static_cast<B&&>(b)),
82       static_cast<Bs&&>(bs)...);
83 }
84
85 } // namespace exception_wrapper_detail
86
87 //! Throwing exceptions can be a convenient way to handle errors. Storing
88 //! exceptions in an `exception_ptr` makes it easy to handle exceptions in a
89 //! different thread or at a later time. `exception_ptr` can also be used in a
90 //! very generic result/exception wrapper.
91 //!
92 //! However, there are some issues with throwing exceptions and
93 //! `std::exception_ptr`. These issues revolve around `throw` being expensive,
94 //! particularly in a multithreaded environment (see
95 //! ExceptionWrapperBenchmark.cpp).
96 //!
97 //! Imagine we have a library that has an API which returns a result/exception
98 //! wrapper. Let's consider some approaches for implementing this wrapper.
99 //! First, we could store a `std::exception`. This approach loses the derived
100 //! exception type, which can make exception handling more difficult for users
101 //! that prefer rethrowing the exception. We could use a `folly::dynamic` for
102 //! every possible type of exception. This is not very flexible - adding new
103 //! types of exceptions requires a change to the result/exception wrapper. We
104 //! could use an `exception_ptr`. However, constructing an `exception_ptr` as
105 //! well as accessing the error requires a call to throw. That means that there
106 //! will be two calls to throw in order to process the exception. For
107 //! performance sensitive applications, this may be unacceptable.
108 //!
109 //! `exception_wrapper` is designed to handle exception management for both
110 //! convenience and high performance use cases. `make_exception_wrapper` is
111 //! templated on derived type, allowing us to rethrow the exception properly for
112 //! users that prefer convenience. These explicitly named exception types can
113 //! therefore be handled without any peformance penalty. `exception_wrapper` is
114 //! also flexible enough to accept any type. If a caught exception is not of an
115 //! explicitly named type, then `std::exception_ptr` is used to preserve the
116 //! exception state. For performance sensitive applications, the accessor
117 //! methods can test or extract a pointer to a specific exception type with very
118 //! little overhead.
119 //!
120 //! \par Example usage:
121 //! \par
122 //! \code
123 //! exception_wrapper globalExceptionWrapper;
124 //!
125 //! // Thread1
126 //! void doSomethingCrazy() {
127 //!   int rc = doSomethingCrazyWithLameReturnCodes();
128 //!   if (rc == NAILED_IT) {
129 //!     globalExceptionWrapper = exception_wrapper();
130 //!   } else if (rc == FACE_PLANT) {
131 //!     globalExceptionWrapper = make_exception_wrapper<FacePlantException>();
132 //!   } else if (rc == FAIL_WHALE) {
133 //!     globalExceptionWrapper = make_exception_wrapper<FailWhaleException>();
134 //!   }
135 //! }
136 //!
137 //! // Thread2: Exceptions are ok!
138 //! void processResult() {
139 //!   try {
140 //!     globalExceptionWrapper.throw_exception();
141 //!   } catch (const FacePlantException& e) {
142 //!     LOG(ERROR) << "FACEPLANT!";
143 //!   } catch (const FailWhaleException& e) {
144 //!     LOG(ERROR) << "FAILWHALE!";
145 //!   }
146 //! }
147 //!
148 //! // Thread2: Exceptions are bad!
149 //! void processResult() {
150 //!   globalExceptionWrapper.handle(
151 //!       [&](FacePlantException& faceplant) {
152 //!         LOG(ERROR) << "FACEPLANT";
153 //!       },
154 //!       [&](FailWhaleException& failwhale) {
155 //!         LOG(ERROR) << "FAILWHALE!";
156 //!       },
157 //!       [](...) {
158 //!         LOG(FATAL) << "Unrecognized exception";
159 //!       });
160 //! }
161 //! \endcode
162 class exception_wrapper final {
163  private:
164   struct AnyException : std::exception {
165     std::type_info const* typeinfo_;
166     template <class T>
167     /* implicit */ AnyException(T&& t) noexcept : typeinfo_(&typeid(t)) {}
168   };
169
170   template <class Fn>
171   struct arg_type_;
172   template <class Fn>
173   using arg_type = _t<arg_type_<Fn>>;
174
175   // exception_wrapper is implemented as a simple variant over four
176   // different representations:
177   //  0. Empty, no exception.
178   //  1. An small object stored in-situ.
179   //  2. A larger object stored on the heap and referenced with a
180   //     std::shared_ptr.
181   //  3. A std::exception_ptr, together with either:
182   //       a. A pointer to the referenced std::exception object, or
183   //       b. A pointer to a std::type_info object for the referenced exception,
184   //          or for an unspecified type if the type is unknown.
185   // This is accomplished with the help of a union and a pointer to a hand-
186   // rolled virtual table. This virtual table contains pointers to functions
187   // that know which field of the union is active and do the proper action.
188   // The class invariant ensures that the vtable ptr and the union stay in sync.
189   struct VTable {
190     void (*copy_)(exception_wrapper const*, exception_wrapper*);
191     void (*move_)(exception_wrapper*, exception_wrapper*);
192     void (*delete_)(exception_wrapper*);
193     void (*throw_)(exception_wrapper const*);
194     std::type_info const* (*type_)(exception_wrapper const*);
195     std::exception const* (*get_exception_)(exception_wrapper const*);
196     exception_wrapper (*get_exception_ptr_)(exception_wrapper const*);
197   };
198
199   [[noreturn]] static void onNoExceptionError();
200
201   template <class Ret, class... Args>
202   static Ret noop_(Args...);
203
204   static std::type_info const* uninit_type_(exception_wrapper const*);
205
206   static VTable const uninit_;
207
208   template <class Ex>
209   using IsStdException = std::is_base_of<std::exception, _t<std::decay<Ex>>>;
210   template <bool B, class T>
211   using AddConstIf = exception_wrapper_detail::AddConstIf<B, T>;
212   template <class CatchFn>
213   using IsCatchAll =
214       std::is_same<arg_type<_t<std::decay<CatchFn>>>, AnyException>;
215
216   struct Unknown {};
217
218   // Sadly, with the gcc-4.9 platform, std::logic_error and std::runtime_error
219   // do not fit here. They also don't have noexcept copy-ctors, so the internal
220   // storage wouldn't be used anyway. For the gcc-5 platform, both logic_error
221   // and runtime_error can be safely stored internally.
222   struct Buffer {
223     using Storage =
224         _t<std::aligned_storage<2 * sizeof(void*), alignof(std::exception)>>;
225     Storage buff_;
226
227     Buffer() : buff_{} {}
228
229     template <class Ex, class DEx = _t<std::decay<Ex>>>
230     Buffer(in_place_t, Ex&& ex);
231     template <class Ex>
232     Ex& as() noexcept;
233     template <class Ex>
234     Ex const& as() const noexcept;
235   };
236
237   enum class Placement { kInSitu, kOnHeap };
238   template <class T>
239   using PlacementOf = std::integral_constant<
240       Placement,
241       sizeof(T) <= sizeof(Buffer::Storage) &&
242               alignof(T) <= alignof(Buffer::Storage) &&
243               noexcept(T(std::declval<T&&>()))
244           ? Placement::kInSitu
245           : Placement::kOnHeap>;
246
247   using InSituTag = std::integral_constant<Placement, Placement::kInSitu>;
248   using OnHeapTag = std::integral_constant<Placement, Placement::kOnHeap>;
249
250   static std::exception const* as_exception_or_null_(std::exception const& ex);
251   static std::exception const* as_exception_or_null_(AnyException);
252
253   struct ExceptionPtr {
254     std::exception_ptr ptr_;
255     std::uintptr_t exception_or_type_; // odd for type_info
256     static_assert(
257         1 < alignof(std::exception) && 1 < alignof(std::type_info),
258         "Surprise! std::exception and std::type_info don't have alignment "
259         "greater than one. as_int_ below will not work!");
260
261     static std::uintptr_t as_int_(std::exception const& e);
262     static std::uintptr_t as_int_(AnyException e);
263     bool has_exception_() const;
264     std::exception const* as_exception_() const;
265     std::type_info const* as_type_() const;
266     static void copy_(exception_wrapper const* from, exception_wrapper* to);
267     static void move_(exception_wrapper* from, exception_wrapper* to);
268     static void delete_(exception_wrapper* that);
269     [[noreturn]] static void throw_(exception_wrapper const* that);
270     static std::type_info const* type_(exception_wrapper const* that);
271     static std::exception const* get_exception_(exception_wrapper const* that);
272     static exception_wrapper get_exception_ptr_(exception_wrapper const* that);
273     static VTable const ops_;
274   };
275
276   template <class Ex>
277   struct InPlace {
278     static void copy_(exception_wrapper const* from, exception_wrapper* to);
279     static void move_(exception_wrapper* from, exception_wrapper* to);
280     static void delete_(exception_wrapper* that);
281     [[noreturn]] static void throw_(exception_wrapper const* that);
282     static std::type_info const* type_(exception_wrapper const*);
283     static std::exception const* get_exception_(exception_wrapper const* that);
284     static exception_wrapper get_exception_ptr_(exception_wrapper const* that);
285     static constexpr VTable const ops_{copy_,
286                                        move_,
287                                        delete_,
288                                        throw_,
289                                        type_,
290                                        get_exception_,
291                                        get_exception_ptr_};
292   };
293
294   struct SharedPtr {
295     struct Base {
296       std::type_info const* info_;
297       Base() = default;
298       explicit Base(std::type_info const& info) : info_(&info) {}
299       virtual ~Base() {}
300       virtual void throw_() const = 0;
301       virtual std::exception const* get_exception_() const noexcept = 0;
302       virtual exception_wrapper get_exception_ptr_() const noexcept = 0;
303     };
304     template <class Ex>
305     struct Impl final : public Base {
306       Ex ex_;
307       Impl() = default;
308       explicit Impl(Ex const& ex) : Base{typeid(ex)}, ex_(ex) {}
309       explicit Impl(Ex&& ex)
310           : Base{typeid(ex)},
311             ex_(std::move(ex)){}[[noreturn]] void throw_() const override;
312       std::exception const* get_exception_() const noexcept override;
313       exception_wrapper get_exception_ptr_() const noexcept override;
314     };
315     std::shared_ptr<Base> ptr_;
316
317     static void copy_(exception_wrapper const* from, exception_wrapper* to);
318     static void move_(exception_wrapper* from, exception_wrapper* to);
319     static void delete_(exception_wrapper* that);
320     [[noreturn]] static void throw_(exception_wrapper const* that);
321     static std::type_info const* type_(exception_wrapper const* that);
322     static std::exception const* get_exception_(exception_wrapper const* that);
323     static exception_wrapper get_exception_ptr_(exception_wrapper const* that);
324     static VTable const ops_;
325   };
326
327   union {
328     Buffer buff_{};
329     ExceptionPtr eptr_;
330     SharedPtr sptr_;
331   };
332   VTable const* vptr_{&uninit_};
333
334   template <class Ex, class DEx = _t<std::decay<Ex>>>
335   exception_wrapper(Ex&& ex, OnHeapTag);
336
337   template <class Ex, class DEx = _t<std::decay<Ex>>>
338   exception_wrapper(Ex&& ex, InSituTag);
339
340   template <class T>
341   struct IsRegularExceptionType
342       : StrictConjunction<
343             std::is_copy_constructible<T>,
344             Negation<std::is_base_of<exception_wrapper, T>>,
345             Negation<std::is_abstract<T>>> {};
346
347   template <class CatchFn, bool IsConst = false>
348   struct ExceptionTypeOf;
349
350   template <bool IsConst>
351   struct HandleReduce;
352
353   template <bool IsConst>
354   struct HandleStdExceptReduce;
355
356   template <class This, class... CatchFns>
357   static void handle_(std::false_type, This& this_, CatchFns&... fns);
358
359   template <class This, class... CatchFns>
360   static void handle_(std::true_type, This& this_, CatchFns&... fns);
361
362   template <class Ex, class This, class Fn>
363   static bool with_exception_(This& this_, Fn fn_);
364
365  public:
366   //! Default-constructs an empty `exception_wrapper`
367   //! \post `type() == none()`
368   exception_wrapper() noexcept {}
369
370   //! Move-constructs an `exception_wrapper`
371   //! \post `*this` contains the value of `that` prior to the move
372   //! \post `that.type() == none()`
373   exception_wrapper(exception_wrapper&& that) noexcept;
374
375   //! Copy-constructs an `exception_wrapper`
376   //! \post `*this` contains a copy of `that`, and `that` is unmodified
377   //! \post `type() == that.type()`
378   exception_wrapper(exception_wrapper const& that);
379
380   //! Move-assigns an `exception_wrapper`
381   //! \pre `this != &that`
382   //! \post `*this` contains the value of `that` prior to the move
383   //! \post `that.type() == none()`
384   exception_wrapper& operator=(exception_wrapper&& that) noexcept;
385
386   //! Copy-assigns an `exception_wrapper`
387   //! \post `*this` contains a copy of `that`, and `that` is unmodified
388   //! \post `type() == that.type()`
389   exception_wrapper& operator=(exception_wrapper const& that);
390
391   ~exception_wrapper();
392
393   //! \pre `ptr` is empty, or it holds a reference to an exception that is not
394   //!     derived from `std::exception`.
395   //! \post `!ptr || bool(*this)`
396   //! \post `hasThrownException() == true`
397   //! \post `type() == unknown()`
398   explicit exception_wrapper(std::exception_ptr ptr) noexcept;
399
400   //! \pre `ptr` holds a reference to `ex`.
401   //! \post `hasThrownException() == true`
402   //! \post `bool(*this)`
403   //! \post `type() == typeid(ex)`
404   template <class Ex>
405   exception_wrapper(std::exception_ptr ptr, Ex& ex);
406
407   //! \pre `typeid(ex) == typeid(typename decay<Ex>::type)`
408   //! \post `bool(*this)`
409   //! \post `hasThrownException() == false`
410   //! \post `type() == typeid(ex)`
411   //! \note Exceptions of types derived from `std::exception` can be implicitly
412   //!     converted to an `exception_wrapper`.
413   template <
414       class Ex,
415       class Ex_ = _t<std::decay<Ex>>,
416       FOLLY_REQUIRES(
417           Conjunction<IsStdException<Ex_>, IsRegularExceptionType<Ex_>>::value)>
418   /* implicit */ exception_wrapper(Ex&& ex);
419
420   //! \pre `typeid(ex) == typeid(typename decay<Ex>::type)`
421   //! \post `bool(*this)`
422   //! \post `hasThrownException() == false`
423   //! \post `type() == typeid(ex)`
424   //! \note Exceptions of types not derived from `std::exception` can still be
425   //!     used to construct an `exception_wrapper`, but you must specify
426   //!     `folly::in_place` as the first parameter.
427   template <
428       class Ex,
429       class Ex_ = _t<std::decay<Ex>>,
430       FOLLY_REQUIRES(IsRegularExceptionType<Ex_>::value)>
431   exception_wrapper(in_place_t, Ex&& ex);
432
433   //! Swaps the value of `*this` with the value of `that`
434   void swap(exception_wrapper& that) noexcept;
435
436   //! \return `true` if `*this` is not holding an exception.
437   explicit operator bool() const noexcept;
438
439   //! \return `!bool(*this)`
440   bool operator!() const noexcept;
441
442   //! Make this `exception_wrapper` empty
443   //! \post `!*this`
444   void reset();
445
446   //! \return `true` if this `exception_wrapper` holds a reference to an
447   //!     exception that was thrown (i.e., if it was constructed with
448   //!     a `std::exception_ptr`, or if `to_exception_ptr()` was called on a
449   //!     (non-const) reference to `*this`).
450   bool has_exception_ptr() const noexcept;
451
452   //! \return a pointer to the `std::exception` held by `*this`, if it holds
453   //!     one; otherwise, returns `nullptr`.
454   //! \note This function does not mutate the `exception_wrapper` object.
455   //! \note This function never causes an exception to be thrown.
456   std::exception* get_exception() noexcept;
457   //! \overload
458   std::exception const* get_exception() const noexcept;
459
460   //! \returns a pointer to the `Ex` held by `*this`, if it holds an object
461   //!     whose type `From` permits `std::is_convertible<From*, Ex*>`;
462   //!     otherwise, returns `nullptr`.
463   //! \note This function does not mutate the `exception_wrapper` object.
464   //! \note This function may cause an exception to be thrown and immediately
465   //!     caught internally, affecting runtime performance.
466   template <typename Ex>
467   Ex* get_exception() noexcept;
468   //! \overload
469   template <typename Ex>
470   Ex const* get_exception() const noexcept;
471
472   //! \return A `std::exception_ptr` that references either the exception held
473   //!     by `*this`, or a copy of same.
474   //! \note This function may need to throw an exception to complete the action.
475   //! \note The non-const overload of this function mutates `*this` to cache the
476   //!     computed `std::exception_ptr`; that is, this function may cause
477   //!     `has_exception_ptr()` to change from `false` to `true`.
478   std::exception_ptr const& to_exception_ptr() noexcept;
479   //! \overload
480   std::exception_ptr to_exception_ptr() const noexcept;
481
482   //! \return the `typeid` of an unspecified type used by
483   //!     `exception_wrapper::type()` to denote an empty `exception_wrapper`.
484   static std::type_info const& none() noexcept;
485   //! \return the `typeid` of an unspecified type used by
486   //!     `exception_wrapper::type()` to denote an `exception_wrapper` that
487   //!     holds an exception of unknown type.
488   static std::type_info const& unknown() noexcept;
489
490   //! Returns the `typeid` of the wrapped exception object. If there is no
491   //!     wrapped exception object, returns `exception_wrapper::none()`. If
492   //!     this instance wraps an exception of unknown type not derived from
493   //!     `std::exception`, returns `exception_wrapper::unknown()`.
494   std::type_info const& type() const noexcept;
495
496   //! \return If `get_exception() != nullptr`, `class_name() + ": " +
497   //!     get_exception()->what()`; otherwise, `class_name()`.
498   folly::fbstring what() const;
499
500   //! \return If `!*this`, the empty string; otherwise, if
501   //!     `type() == unknown()`, the string `"<unknown exception>"`; otherwise,
502   //!     the result of `type().name()` after demangling.
503   folly::fbstring class_name() const;
504
505   //! \tparam Ex The expression type to check for compatibility with.
506   //! \return `true` if and only if `*this` wraps an exception that would be
507   //!     caught with a `catch(Ex const&)` clause.
508   //! \note If `*this` is empty, this function returns `false`.
509   template <class Ex>
510   bool is_compatible_with() const noexcept;
511
512   //! \pre `bool(*this)`
513   //! Throws the wrapped expression.
514   [[noreturn]] void throw_exception() const;
515
516   //! Call `fn` with the wrapped exception (if any), if `fn` can accept it.
517   //! \par Example
518   //! \code
519   //! exception_wrapper ew{std::runtime_error("goodbye cruel world")};
520   //!
521   //! assert( ew.with_exception([](std::runtime_error& e){/*...*/}) );
522   //!
523   //! assert( !ew.with_exception([](int& e){/*...*/}) );
524   //!
525   //! assert( !exception_wrapper{}.with_exception([](int& e){/*...*/}) );
526   //! \endcode
527   //! \tparam Ex Optionally, the type of the exception that `fn` accepts.
528   //! \tparam Fn The type of a monomophic function object.
529   //! \param fn A function object to call with the wrapped exception
530   //! \return `true` if and only if `fn` was called.
531   //! \note Optionally, you may explicitly specify the type of the exception
532   //!     that `fn` expects, as in
533   //! \code
534   //! ew.with_exception<std::runtime_error>([](auto&& e) { /*...*/; });
535   //! \endcode
536   //! \note The handler may or may not be invoked with an active exception.
537   //!     **Do not try to rethrow the exception with `throw;` from within your
538   //!     handler -- that is, a throw expression with no operand.** This may
539   //!     cause your process to terminate. (It is perfectly ok to throw from
540   //!     a handler so long as you specify the exception to throw, as in
541   //!     `throw e;`.)
542   template <class Ex = void const, class Fn>
543   bool with_exception(Fn fn);
544   //! \overload
545   template <class Ex = void const, class Fn>
546   bool with_exception(Fn fn) const;
547
548   //! Handle the wrapped expression as if with a series of `catch` clauses,
549   //!     propagating the exception if no handler matches.
550   //! \par Example
551   //! \code
552   //! exception_wrapper ew{std::runtime_error("goodbye cruel world")};
553   //!
554   //! ew.handle(
555   //!   [&](std::logic_error const& e) {
556   //!      LOG(DFATAL) << "ruh roh";
557   //!      ew.throw_exception(); // rethrow the active exception without
558   //!                           // slicing it. Will not be caught by other
559   //!                           // handlers in this call.
560   //!   },
561   //!   [&](std::exception const& e) {
562   //!      LOG(ERROR) << ew.what();
563   //!   });
564   //! \endcode
565   //! In the above example, any exception _not_ derived from `std::exception`
566   //!     will be propagated. To specify a catch-all clause, pass a lambda that
567   //!     takes a C-style elipses, as in:
568   //! \code
569   //! ew.handle(/*...* /, [](...) { /* handle unknown exception */ } )
570   //! \endcode
571   //! \pre `!*this`
572   //! \tparam CatchFns... A pack of unary monomorphic function object types.
573   //! \param fns A pack of unary monomorphic function objects to be treated as
574   //!     an ordered list of potential exception handlers.
575   //! \note The handlers may or may not be invoked with an active exception.
576   //!     **Do not try to rethrow the exception with `throw;` from within your
577   //!     handler -- that is, a throw expression with no operand.** This may
578   //!     cause your process to terminate. (It is perfectly ok to throw from
579   //!     a handler so long as you specify the exception to throw, as in
580   //!     `throw e;`.)
581   template <class... CatchFns>
582   void handle(CatchFns... fns);
583   //! \overload
584   template <class... CatchFns>
585   void handle(CatchFns... fns) const;
586 };
587
588 template <class Ex>
589 constexpr exception_wrapper::VTable exception_wrapper::InPlace<Ex>::ops_;
590
591 /**
592  * \return An `exception_wrapper` that wraps an instance of type `Ex`
593  *     that has been constructed with arguments `std::forward<As>(as)...`.
594  */
595 template <class Ex, typename... As>
596 exception_wrapper make_exception_wrapper(As&&... as) {
597   return exception_wrapper{Ex{std::forward<As>(as)...}};
598 }
599
600 /**
601  * Inserts `ew.what()` into the ostream `sout`.
602  * \return `sout`
603  */
604 template <class Ch>
605 std::basic_ostream<Ch>& operator<<(
606     std::basic_ostream<Ch>& sout,
607     exception_wrapper const& ew) {
608   return sout << ew.what();
609 }
610
611 /**
612  * Swaps the value of `a` with the value of `b`.
613  */
614 inline void swap(exception_wrapper& a, exception_wrapper& b) noexcept {
615   a.swap(b);
616 }
617
618 // For consistency with exceptionStr() functions in ExceptionString.h
619 fbstring exceptionStr(exception_wrapper const& ew);
620
621 namespace detail {
622 template <typename F>
623 inline exception_wrapper try_and_catch_(F&& f) {
624   return (f(), exception_wrapper());
625 }
626
627 template <typename F, typename Ex, typename... Exs>
628 inline exception_wrapper try_and_catch_(F&& f) {
629   try {
630     return try_and_catch_<F, Exs...>(std::forward<F>(f));
631   } catch (Ex& ex) {
632     return exception_wrapper(std::current_exception(), ex);
633   }
634 }
635 } // detail
636
637 //! `try_and_catch` is a simple replacement for `try {} catch(){}`` that allows
638 //! you to specify which derived exceptions you would like to catch and store in
639 //! an `exception_wrapper`.
640 //!
641 //! Because we cannot build an equivalent of `std::current_exception()`, we need
642 //! to catch every derived exception that we are interested in catching.
643 //!
644 //! Exceptions should be listed in the reverse order that you would write your
645 //! catch statements (that is, `std::exception&` should be first).
646 //!
647 //! \par Example Usage:
648 //! \code
649 //! // This catches my runtime_error and if I call throw_exception() on ew, it
650 //! // will throw a runtime_error
651 //! auto ew = folly::try_and_catch<std::exception, std::runtime_error>([=]() {
652 //!   if (badThingHappens()) {
653 //!     throw std::runtime_error("ZOMG!");
654 //!   }
655 //! });
656 //!
657 //! // This will catch the exception and if I call throw_exception() on ew, it
658 //! // will throw a std::exception
659 //! auto ew = folly::try_and_catch<std::exception, std::runtime_error>([=]() {
660 //!   if (badThingHappens()) {
661 //!     throw std::exception();
662 //!   }
663 //! });
664 //!
665 //! // This will not catch the exception and it will be thrown.
666 //! auto ew = folly::try_and_catch<std::runtime_error>([=]() {
667 //!   if (badThingHappens()) {
668 //!     throw std::exception();
669 //!   }
670 //! });
671 //! \endcode
672 template <typename... Exceptions, typename F>
673 exception_wrapper try_and_catch(F&& fn) {
674   return detail::try_and_catch_<F, Exceptions...>(std::forward<F>(fn));
675 }
676 } // folly
677
678 #include <folly/ExceptionWrapper-inl.h>
679
680 #undef FOLLY_REQUIRES
681 #undef FOLLY_REQUIRES_DEF
682 #ifdef __GNUC__
683 #pragma GCC diagnostic pop
684 #endif