Commit 1bdec475 authored by Christopher Dykes's avatar Christopher Dykes Committed by Facebook Github Bot

Fix folly::Function under C++17 exception specifier rules

Summary: Under C++17's exception specifier rules (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html) we need additional specializations to achieve the desired effect.

Reviewed By: yfeldblum

Differential Revision: D6214359

fbshipit-source-id: a007c2fcea1496bdfe4fdf923b39c1611c6ad9bc
parent e75cf21f
...@@ -237,6 +237,12 @@ template <typename ReturnType, typename... Args> ...@@ -237,6 +237,12 @@ template <typename ReturnType, typename... Args>
Function<ReturnType(Args...) const> constCastFunction( Function<ReturnType(Args...) const> constCastFunction(
Function<ReturnType(Args...)>&&) noexcept; Function<ReturnType(Args...)>&&) noexcept;
#if FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE
template <typename ReturnType, typename... Args>
Function<ReturnType(Args...) const noexcept> constCastFunction(
Function<ReturnType(Args...) noexcept>&&) noexcept;
#endif
namespace detail { namespace detail {
namespace function { namespace function {
...@@ -371,6 +377,98 @@ struct FunctionTraits<ReturnType(Args...) const> { ...@@ -371,6 +377,98 @@ struct FunctionTraits<ReturnType(Args...) const> {
}; };
}; };
#if FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE
template <typename ReturnType, typename... Args>
struct FunctionTraits<ReturnType(Args...) noexcept> {
using Call = ReturnType (*)(Data&, Args&&...) noexcept;
using IsConst = std::false_type;
using ConstSignature = ReturnType(Args...) const noexcept;
using NonConstSignature = ReturnType(Args...) noexcept;
using OtherSignature = ConstSignature;
template <typename F, typename G = typename std::decay<F>::type>
using ResultOf = decltype(
static_cast<ReturnType>(std::declval<G&>()(std::declval<Args>()...)));
template <typename Fun>
static ReturnType callSmall(Data& p, Args&&... args) noexcept {
return static_cast<ReturnType>((*static_cast<Fun*>(
static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...));
}
template <typename Fun>
static ReturnType callBig(Data& p, Args&&... args) noexcept {
return static_cast<ReturnType>(
(*static_cast<Fun*>(p.big))(static_cast<Args&&>(args)...));
}
static ReturnType uninitCall(Data&, Args&&...) noexcept {
throw std::bad_function_call();
}
ReturnType operator()(Args... args) noexcept {
auto& fn = *static_cast<Function<NonConstSignature>*>(this);
return fn.call_(fn.data_, static_cast<Args&&>(args)...);
}
class SharedProxy {
std::shared_ptr<Function<NonConstSignature>> sp_;
public:
explicit SharedProxy(Function<NonConstSignature>&& func)
: sp_(std::make_shared<Function<NonConstSignature>>(std::move(func))) {}
ReturnType operator()(Args&&... args) const {
return (*sp_)(static_cast<Args&&>(args)...);
}
};
};
template <typename ReturnType, typename... Args>
struct FunctionTraits<ReturnType(Args...) const noexcept> {
using Call = ReturnType (*)(Data&, Args&&...) noexcept;
using IsConst = std::true_type;
using ConstSignature = ReturnType(Args...) const noexcept;
using NonConstSignature = ReturnType(Args...) noexcept;
using OtherSignature = NonConstSignature;
template <typename F, typename G = typename std::decay<F>::type>
using ResultOf = decltype(static_cast<ReturnType>(
std::declval<const G&>()(std::declval<Args>()...)));
template <typename Fun>
static ReturnType callSmall(Data& p, Args&&... args) noexcept {
return static_cast<ReturnType>((*static_cast<const Fun*>(
static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...));
}
template <typename Fun>
static ReturnType callBig(Data& p, Args&&... args) noexcept {
return static_cast<ReturnType>(
(*static_cast<const Fun*>(p.big))(static_cast<Args&&>(args)...));
}
static ReturnType uninitCall(Data&, Args&&...) noexcept {
throw std::bad_function_call();
}
ReturnType operator()(Args... args) const noexcept {
auto& fn = *static_cast<const Function<ConstSignature>*>(this);
return fn.call_(fn.data_, static_cast<Args&&>(args)...);
}
class SharedProxy {
std::shared_ptr<Function<ConstSignature>> sp_;
public:
explicit SharedProxy(Function<ConstSignature>&& func)
: sp_(std::make_shared<Function<ConstSignature>>(std::move(func))) {}
ReturnType operator()(Args&&... args) const {
return (*sp_)(static_cast<Args&&>(args)...);
}
};
};
#endif
template <typename Fun> template <typename Fun>
bool execSmall(Op o, Data* src, Data* dst) { bool execSmall(Op o, Data* src, Data* dst) {
switch (o) { switch (o) {
...@@ -743,6 +841,21 @@ Function<ReturnType(Args...) const> constCastFunction( ...@@ -743,6 +841,21 @@ Function<ReturnType(Args...) const> constCastFunction(
return std::move(that); return std::move(that);
} }
#if FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE
template <typename ReturnType, typename... Args>
Function<ReturnType(Args...) const noexcept> constCastFunction(
Function<ReturnType(Args...) noexcept>&& that) noexcept {
return Function<ReturnType(Args...) const noexcept>{
std::move(that), detail::function::CoerceTag{}};
}
template <typename ReturnType, typename... Args>
Function<ReturnType(Args...) const noexcept> constCastFunction(
Function<ReturnType(Args...) const noexcept>&& that) noexcept {
return std::move(that);
}
#endif
namespace detail { namespace detail {
namespace function { namespace function {
template <typename Fun, typename FunctionType, typename = void> template <typename Fun, typename FunctionType, typename = void>
......
...@@ -429,3 +429,8 @@ constexpr auto kMscVer = 0; ...@@ -429,3 +429,8 @@ constexpr auto kMscVer = 0;
#if __cpp_coroutines >= 201703L || (_MSC_VER && _RESUMABLE_FUNCTIONS_SUPPORTED) #if __cpp_coroutines >= 201703L || (_MSC_VER && _RESUMABLE_FUNCTIONS_SUPPORTED)
#define FOLLY_HAS_COROUTINES 1 #define FOLLY_HAS_COROUTINES 1
#endif #endif
// MSVC 2017.5
#if __cpp_noexcept_function_type >= 201510 || _MSC_FULL_VER >= 191225816
#define FOLLY_HAVE_NOEXCEPT_FUNCTION_TYPE 1
#endif
...@@ -66,16 +66,20 @@ void moveTopException(StackTraceStack& from, StackTraceStack& to) { ...@@ -66,16 +66,20 @@ void moveTopException(StackTraceStack& from, StackTraceStack& to) {
struct Initializer { struct Initializer {
Initializer() { Initializer() {
registerCxaThrowCallback( registerCxaThrowCallback([](
[](void*, std::type_info*, void (*)(void*)) { addActiveException(); }); void*, std::type_info*, void (*)(void*)) noexcept {
addActiveException();
});
registerCxaBeginCatchCallback( registerCxaBeginCatchCallback([](void*) noexcept {
[](void*) { moveTopException(activeExceptions, caughtExceptions); }); moveTopException(activeExceptions, caughtExceptions);
});
registerCxaRethrowCallback( registerCxaRethrowCallback([]() noexcept {
[]() { moveTopException(caughtExceptions, activeExceptions); }); moveTopException(caughtExceptions, activeExceptions);
});
registerCxaEndCatchCallback([]() { registerCxaEndCatchCallback([]() noexcept {
if (invalid) { if (invalid) {
return; return;
} }
...@@ -97,8 +101,9 @@ struct Initializer { ...@@ -97,8 +101,9 @@ struct Initializer {
} }
}); });
registerRethrowExceptionCallback( registerRethrowExceptionCallback([](std::exception_ptr) noexcept {
[](std::exception_ptr) { addActiveException(); }); addActiveException();
});
try { try {
::folly::exception_tracer::installHandlers(); ::folly::exception_tracer::installHandlers();
......
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