Cut the ScopeGuard alias now that we have auto
[folly.git] / folly / ExceptionWrapper.h
index dcdf862870863c25585415d15497505f01c4f5fc..fc0cac77529b58165c6029137d5aa7c0bc9bf012 100644 (file)
 #include <typeinfo>
 #include <utility>
 
-#include <folly/Assume.h>
 #include <folly/CPortability.h>
 #include <folly/Demangle.h>
 #include <folly/ExceptionString.h>
 #include <folly/FBString.h>
+#include <folly/Portability.h>
 #include <folly/Traits.h>
+#include <folly/Utility.h>
+#include <folly/lang/Assume.h>
 
 #ifdef __GNUC__
 #pragma GCC diagnostic push
@@ -42,8 +44,7 @@
 #pragma GCC diagnostic ignored "-Wpotentially-evaluated-expression"
 // GCC gets confused about lambda scopes and issues shadow-local warnings for
 // parameters in totally different functions.
-#pragma GCC diagnostic ignored "-Wshadow-local"
-#pragma GCC diagnostic ignored "-Wshadow-compatible-local"
+FOLLY_GCC_DISABLE_NEW_SHADOW_WARNINGS
 #endif
 
 #define FOLLY_EXCEPTION_WRAPPER_H_INCLUDED
@@ -137,7 +138,7 @@ auto fold(Fn&& fn, A&& a, B&& b, Bs&&... bs) {
 //! // Thread2: Exceptions are ok!
 //! void processResult() {
 //!   try {
-//!     globalExceptionWrapper.throwException();
+//!     globalExceptionWrapper.throw_exception();
 //!   } catch (const FacePlantException& e) {
 //!     LOG(ERROR) << "FACEPLANT!";
 //!   } catch (const FailWhaleException& e) {
@@ -161,7 +162,7 @@ auto fold(Fn&& fn, A&& a, B&& b, Bs&&... bs) {
 //! \endcode
 class exception_wrapper final {
  private:
-  struct AnyException : std::exception {
+  struct FOLLY_EXPORT AnyException : std::exception {
     std::type_info const* typeinfo_;
     template <class T>
     /* implicit */ AnyException(T&& t) noexcept : typeinfo_(&typeid(t)) {}
@@ -196,21 +197,14 @@ class exception_wrapper final {
     exception_wrapper (*get_exception_ptr_)(exception_wrapper const*);
   };
 
-  [[noreturn]] static void onNoExceptionError();
+  [[noreturn]] static void onNoExceptionError(char const* name);
 
   template <class Ret, class... Args>
   static Ret noop_(Args...);
 
   static std::type_info const* uninit_type_(exception_wrapper const*);
 
-  static constexpr VTable const uninit_{
-      &noop_<void, exception_wrapper const*, exception_wrapper*>,
-      &noop_<void, exception_wrapper*, exception_wrapper*>,
-      &noop_<void, exception_wrapper*>,
-      &noop_<void, exception_wrapper const*>,
-      &uninit_type_,
-      &noop_<std::exception const*, exception_wrapper const*>,
-      &noop_<exception_wrapper, exception_wrapper const*>};
+  static VTable const uninit_;
 
   template <class Ex>
   using IsStdException = std::is_base_of<std::exception, _t<std::decay<Ex>>>;
@@ -233,26 +227,28 @@ class exception_wrapper final {
 
     Buffer() : buff_{} {}
 
-    template <class Ex, class DEx = _t<std::decay<Ex>>>
-    Buffer(in_place_t, Ex&& ex);
+    template <class Ex, typename... As>
+    Buffer(in_place_type_t<Ex>, As&&... as_);
     template <class Ex>
     Ex& as() noexcept;
     template <class Ex>
     Ex const& as() const noexcept;
   };
 
-  enum class Placement { kInSitu, kOnHeap };
+  struct ThrownTag {};
+  struct InSituTag {};
+  struct OnHeapTag {};
+
   template <class T>
-  using PlacementOf = std::integral_constant<
-      Placement,
-      sizeof(T) <= sizeof(Buffer::Storage) &&
+  using PlacementOf = _t<std::conditional<
+      !IsStdException<T>::value,
+      ThrownTag,
+      _t<std::conditional<
+          sizeof(T) <= sizeof(Buffer::Storage) &&
               alignof(T) <= alignof(Buffer::Storage) &&
-              noexcept(T(std::declval<T&&>()))
-          ? Placement::kInSitu
-          : Placement::kOnHeap>;
-
-  using InSituTag = std::integral_constant<Placement, Placement::kInSitu>;
-  using OnHeapTag = std::integral_constant<Placement, Placement::kOnHeap>;
+              noexcept(T(std::declval<T&&>())),
+          InSituTag,
+          OnHeapTag>>>>;
 
   static std::exception const* as_exception_or_null_(std::exception const& ex);
   static std::exception const* as_exception_or_null_(AnyException);
@@ -265,8 +261,12 @@ class exception_wrapper final {
         "Surprise! std::exception and std::type_info don't have alignment "
         "greater than one. as_int_ below will not work!");
 
-    static std::uintptr_t as_int_(std::exception const& e);
-    static std::uintptr_t as_int_(AnyException e);
+    static std::uintptr_t as_int_(
+        std::exception_ptr const& ptr,
+        std::exception const& e);
+    static std::uintptr_t as_int_(
+        std::exception_ptr const& ptr,
+        AnyException e);
     bool has_exception_() const;
     std::exception const* as_exception_() const;
     std::type_info const* as_type_() const;
@@ -277,17 +277,12 @@ class exception_wrapper final {
     static std::type_info const* type_(exception_wrapper const* that);
     static std::exception const* get_exception_(exception_wrapper const* that);
     static exception_wrapper get_exception_ptr_(exception_wrapper const* that);
-    static constexpr VTable const ops_{copy_,
-                                       move_,
-                                       delete_,
-                                       throw_,
-                                       type_,
-                                       get_exception_,
-                                       get_exception_ptr_};
+    static VTable const ops_;
   };
 
   template <class Ex>
   struct InPlace {
+    static_assert(IsStdException<Ex>::value, "only deriving std::exception");
     static void copy_(exception_wrapper const* from, exception_wrapper* to);
     static void move_(exception_wrapper* from, exception_wrapper* to);
     static void delete_(exception_wrapper* that);
@@ -316,12 +311,13 @@ class exception_wrapper final {
     };
     template <class Ex>
     struct Impl final : public Base {
+      static_assert(IsStdException<Ex>::value, "only deriving std::exception");
       Ex ex_;
       Impl() = default;
-      explicit Impl(Ex const& ex) : Base{typeid(ex)}, ex_(ex) {}
-      explicit Impl(Ex&& ex)
-          : Base{typeid(ex)},
-            ex_(std::move(ex)){}[[noreturn]] void throw_() const override;
+      template <typename... As>
+      explicit Impl(As&&... as)
+          : Base{typeid(Ex)}, ex_(std::forward<As>(as)...) {}
+      [[noreturn]] void throw_() const override;
       std::exception const* get_exception_() const noexcept override;
       exception_wrapper get_exception_ptr_() const noexcept override;
     };
@@ -334,13 +330,7 @@ class exception_wrapper final {
     static std::type_info const* type_(exception_wrapper const* that);
     static std::exception const* get_exception_(exception_wrapper const* that);
     static exception_wrapper get_exception_ptr_(exception_wrapper const* that);
-    static constexpr VTable ops_{copy_,
-                                 move_,
-                                 delete_,
-                                 throw_,
-                                 type_,
-                                 get_exception_,
-                                 get_exception_ptr_};
+    static VTable const ops_;
   };
 
   union {
@@ -350,11 +340,14 @@ class exception_wrapper final {
   };
   VTable const* vptr_{&uninit_};
 
-  template <class Ex, class DEx = _t<std::decay<Ex>>>
-  exception_wrapper(Ex&& ex, OnHeapTag);
+  template <class Ex, typename... As>
+  exception_wrapper(ThrownTag, in_place_type_t<Ex>, As&&... as);
 
-  template <class Ex, class DEx = _t<std::decay<Ex>>>
-  exception_wrapper(Ex&& ex, InSituTag);
+  template <class Ex, typename... As>
+  exception_wrapper(OnHeapTag, in_place_type_t<Ex>, As&&... as);
+
+  template <class Ex, typename... As>
+  exception_wrapper(InSituTag, in_place_type_t<Ex>, As&&... as);
 
   template <class T>
   struct IsRegularExceptionType
@@ -382,6 +375,9 @@ class exception_wrapper final {
   static bool with_exception_(This& this_, Fn fn_);
 
  public:
+  static exception_wrapper from_exception_ptr(
+      std::exception_ptr const& eptr) noexcept;
+
   //! Default-constructs an empty `exception_wrapper`
   //! \post `type() == none()`
   exception_wrapper() noexcept {}
@@ -433,7 +429,7 @@ class exception_wrapper final {
       class Ex,
       class Ex_ = _t<std::decay<Ex>>,
       FOLLY_REQUIRES(
-          Conjunction<IsStdException<Ex_>, IsRegularExceptionType<Ex_>>())>
+          Conjunction<IsStdException<Ex_>, IsRegularExceptionType<Ex_>>::value)>
   /* implicit */ exception_wrapper(Ex&& ex);
 
   //! \pre `typeid(ex) == typeid(typename decay<Ex>::type)`
@@ -446,13 +442,19 @@ class exception_wrapper final {
   template <
       class Ex,
       class Ex_ = _t<std::decay<Ex>>,
-      FOLLY_REQUIRES(IsRegularExceptionType<Ex_>())>
+      FOLLY_REQUIRES(IsRegularExceptionType<Ex_>::value)>
   exception_wrapper(in_place_t, Ex&& ex);
 
+  template <
+      class Ex,
+      typename... As,
+      FOLLY_REQUIRES(IsRegularExceptionType<Ex>::value)>
+  exception_wrapper(in_place_type_t<Ex>, As&&... as);
+
   //! Swaps the value of `*this` with the value of `that`
   void swap(exception_wrapper& that) noexcept;
 
-  //! \return `true` if `*this` is not holding an exception.
+  //! \return `true` if `*this` is holding an exception.
   explicit operator bool() const noexcept;
 
   //! \return `!bool(*this)`
@@ -476,6 +478,18 @@ class exception_wrapper final {
   //! \overload
   std::exception const* get_exception() const noexcept;
 
+  //! \returns a pointer to the `Ex` held by `*this`, if it holds an object
+  //!     whose type `From` permits `std::is_convertible<From*, Ex*>`;
+  //!     otherwise, returns `nullptr`.
+  //! \note This function does not mutate the `exception_wrapper` object.
+  //! \note This function may cause an exception to be thrown and immediately
+  //!     caught internally, affecting runtime performance.
+  template <typename Ex>
+  Ex* get_exception() noexcept;
+  //! \overload
+  template <typename Ex>
+  Ex const* get_exception() const noexcept;
+
   //! \return A `std::exception_ptr` that references either the exception held
   //!     by `*this`, or a copy of same.
   //! \note This function may need to throw an exception to complete the action.
@@ -518,7 +532,7 @@ class exception_wrapper final {
 
   //! \pre `bool(*this)`
   //! Throws the wrapped expression.
-  [[noreturn]] void throwException() const;
+  [[noreturn]] void throw_exception() const;
 
   //! Call `fn` with the wrapped exception (if any), if `fn` can accept it.
   //! \par Example
@@ -561,7 +575,7 @@ class exception_wrapper final {
   //! ew.handle(
   //!   [&](std::logic_error const& e) {
   //!      LOG(DFATAL) << "ruh roh";
-  //!      ew.throwException(); // rethrow the active exception without
+  //!      ew.throw_exception(); // rethrow the active exception without
   //!                           // slicing it. Will not be caught by other
   //!                           // handlers in this call.
   //!   },
@@ -601,7 +615,7 @@ constexpr exception_wrapper::VTable exception_wrapper::InPlace<Ex>::ops_;
  */
 template <class Ex, typename... As>
 exception_wrapper make_exception_wrapper(As&&... as) {
-  return exception_wrapper{Ex{std::forward<As>(as)...}};
+  return exception_wrapper{in_place_type<Ex>, std::forward<As>(as)...};
 }
 
 /**
@@ -639,7 +653,7 @@ inline exception_wrapper try_and_catch_(F&& f) {
     return exception_wrapper(std::current_exception(), ex);
   }
 }
-} // detail
+} // namespace detail
 
 //! `try_and_catch` is a simple replacement for `try {} catch(){}`` that allows
 //! you to specify which derived exceptions you would like to catch and store in
@@ -653,7 +667,7 @@ inline exception_wrapper try_and_catch_(F&& f) {
 //!
 //! \par Example Usage:
 //! \code
-//! // This catches my runtime_error and if I call throwException() on ew, it
+//! // This catches my runtime_error and if I call throw_exception() on ew, it
 //! // will throw a runtime_error
 //! auto ew = folly::try_and_catch<std::exception, std::runtime_error>([=]() {
 //!   if (badThingHappens()) {
@@ -661,7 +675,7 @@ inline exception_wrapper try_and_catch_(F&& f) {
 //!   }
 //! });
 //!
-//! // This will catch the exception and if I call throwException() on ew, it
+//! // This will catch the exception and if I call throw_exception() on ew, it
 //! // will throw a std::exception
 //! auto ew = folly::try_and_catch<std::exception, std::runtime_error>([=]() {
 //!   if (badThingHappens()) {
@@ -680,7 +694,7 @@ template <typename... Exceptions, typename F>
 exception_wrapper try_and_catch(F&& fn) {
   return detail::try_and_catch_<F, Exceptions...>(std::forward<F>(fn));
 }
-} // folly
+} // namespace folly
 
 #include <folly/ExceptionWrapper-inl.h>