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;
constexpr auto kIsWindows = false;
#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
constexpr auto kMscVer = _MSC_VER;
#else
......
......@@ -36,6 +36,14 @@ template <typename Ex>
#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
namespace detail {
template <typename T>
......@@ -51,6 +59,11 @@ template <typename Ex, typename... Args>
[[noreturn]] FOLLY_NOINLINE FOLLY_COLD void throw_exception_(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
// clang-format on
......@@ -67,4 +80,16 @@ throw_exception(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
......@@ -16,39 +16,80 @@
#include <folly/lang/Exception.h>
#include <algorithm>
#include <cstring>
#include <string>
#include <folly/Portability.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 {
private:
char const* what_;
public:
explicit MyException(char const* what) : MyException(what, 0) {}
MyException(char const* what, std::size_t strip) : what_(what + strip) {}
explicit MyException(char const* const what) : MyException(what, 0) {}
MyException(char const* const what, std::size_t const strip)
: what_(what + strip) {}
char const* what() const noexcept override {
return what_;
}
};
} // namespace
class ThrowExceptionTest : public testing::Test {};
class ExceptionTest : public testing::Test {};
TEST_F(ThrowExceptionTest, example) {
TEST_F(ExceptionTest, throw_exception_direct) {
try {
folly::throw_exception<MyException>("hello world"); // 1-arg form
folly::throw_exception<MyException>("hello world");
ADD_FAILURE();
} catch (MyException const& ex) {
EXPECT_STREQ("hello world", ex.what());
}
}
TEST_F(ExceptionTest, throw_exception_variadic) {
try {
folly::throw_exception<MyException>("hello world", 6); // 2-arg form
folly::throw_exception<MyException>("hello world", 6);
ADD_FAILURE();
} catch (MyException const& ex) {
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