Commit a711f13b authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

folly::terminate_with

Summary: [Folly] `folly::terminate_with`, to terminate as if by forwarding to `folly::throw_exception` but in a `noexcept` context.

Reviewed By: marshallcline

Differential Revision: D8345962

fbshipit-source-id: bc5cf5d3a3e1f085dd2989c940a6ea753a520cbf
parent 1e13bc0f
...@@ -354,6 +354,18 @@ constexpr auto kIsWindows = true; ...@@ -354,6 +354,18 @@ constexpr auto kIsWindows = true;
constexpr auto kIsWindows = false; constexpr auto kIsWindows = false;
#endif #endif
#if __GLIBCXX__
constexpr auto kIsGlibcxx = true;
#else
constexpr auto kIsGlibcxx = false;
#endif
#if _LIBCPP_VERSION
constexpr auto kIsLibcpp = true;
#else
constexpr auto kIsLibcpp = false;
#endif
#if _MSC_VER #if _MSC_VER
constexpr auto kMscVer = _MSC_VER; constexpr auto kMscVer = _MSC_VER;
#else #else
......
...@@ -36,6 +36,14 @@ template <typename Ex> ...@@ -36,6 +36,14 @@ template <typename Ex>
#endif #endif
} }
/// terminate_with
///
/// Terminates as if by forwarding to throw_exception but in a noexcept context.
template <typename Ex>
[[noreturn]] FOLLY_NOINLINE FOLLY_COLD void terminate_with(Ex&& ex) noexcept {
throw_exception(static_cast<Ex&&>(ex));
}
// clang-format off // clang-format off
namespace detail { namespace detail {
template <typename T> template <typename T>
...@@ -51,6 +59,11 @@ template <typename Ex, typename... Args> ...@@ -51,6 +59,11 @@ template <typename Ex, typename... Args>
[[noreturn]] FOLLY_NOINLINE FOLLY_COLD void throw_exception_(Args&&... args) { [[noreturn]] FOLLY_NOINLINE FOLLY_COLD void throw_exception_(Args&&... args) {
throw_exception(Ex(static_cast<Args&&>(args)...)); throw_exception(Ex(static_cast<Args&&>(args)...));
} }
template <typename Ex, typename... Args>
[[noreturn]] FOLLY_NOINLINE FOLLY_COLD void terminate_with_(
Args&&... args) noexcept {
throw_exception(Ex(static_cast<Args&&>(args)...));
}
} // namespace detail } // namespace detail
// clang-format on // clang-format on
...@@ -67,4 +80,16 @@ throw_exception(Args&&... args) { ...@@ -67,4 +80,16 @@ throw_exception(Args&&... args) {
detail::to_exception_arg_(static_cast<Args&&>(args))...); detail::to_exception_arg_(static_cast<Args&&>(args))...);
} }
/// terminate_with
///
/// Terminates as if by forwarding to throw_exception but in a noexcept context.
// clang-format off
template <typename Ex, typename... Args>
[[noreturn]] FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN void
terminate_with(Args&&... args) noexcept {
detail::terminate_with_<Ex>(
detail::to_exception_arg_(static_cast<Args&&>(args))...);
}
// clang-format on
} // namespace folly } // namespace folly
...@@ -16,39 +16,80 @@ ...@@ -16,39 +16,80 @@
#include <folly/lang/Exception.h> #include <folly/lang/Exception.h>
#include <algorithm>
#include <cstring>
#include <string>
#include <folly/Portability.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
namespace { template <typename Ex>
static std::string type_pretty_name() {
auto const name = __PRETTY_FUNCTION__;
auto const size = std::strlen(name);
auto const eq = std::find(name, name + size, '=');
auto const sc = std::find(name, name + size, ';');
auto const br = std::find(name, name + size, ']');
auto const bpos = name + size - eq >= 2 ? eq + 2 : name + size;
auto const epos = std::min(sc, br);
return epos < bpos ? "" : std::string(bpos, epos - bpos);
}
template <typename Ex>
static std::string message_for_terminate_with(std::string const& what) {
auto const name = type_pretty_name<Ex>();
auto const prefix =
std::string("terminate called after throwing an instance of ");
// clang-format off
return
folly::kIsGlibcxx ? prefix + "'" + name + "'\\s+what\\(\\):\\s+" + what :
folly::kIsLibcpp ? prefix + name + ": " + what :
"" /* empty regex matches anything */;
// clang-format on
}
class MyException : public std::exception { class MyException : public std::exception {
private: private:
char const* what_; char const* what_;
public: public:
explicit MyException(char const* what) : MyException(what, 0) {} explicit MyException(char const* const what) : MyException(what, 0) {}
MyException(char const* what, std::size_t strip) : what_(what + strip) {} MyException(char const* const what, std::size_t const strip)
: what_(what + strip) {}
char const* what() const noexcept override { char const* what() const noexcept override {
return what_; return what_;
} }
}; };
} // namespace class ExceptionTest : public testing::Test {};
class ThrowExceptionTest : public testing::Test {};
TEST_F(ThrowExceptionTest, example) { TEST_F(ExceptionTest, throw_exception_direct) {
try { try {
folly::throw_exception<MyException>("hello world"); // 1-arg form folly::throw_exception<MyException>("hello world");
ADD_FAILURE(); ADD_FAILURE();
} catch (MyException const& ex) { } catch (MyException const& ex) {
EXPECT_STREQ("hello world", ex.what()); EXPECT_STREQ("hello world", ex.what());
} }
}
TEST_F(ExceptionTest, throw_exception_variadic) {
try { try {
folly::throw_exception<MyException>("hello world", 6); // 2-arg form folly::throw_exception<MyException>("hello world", 6);
ADD_FAILURE(); ADD_FAILURE();
} catch (MyException const& ex) { } catch (MyException const& ex) {
EXPECT_STREQ("world", ex.what()); EXPECT_STREQ("world", ex.what());
} }
} }
TEST_F(ExceptionTest, terminate_with_direct) {
EXPECT_DEATH(
folly::terminate_with<MyException>("hello world"),
message_for_terminate_with<MyException>("hello world"));
}
TEST_F(ExceptionTest, terminate_with_variadic) {
EXPECT_DEATH(
folly::terminate_with<MyException>("hello world", 6),
message_for_terminate_with<MyException>("world"));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment