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