Commit bdc1476f authored by Eric Niebler's avatar Eric Niebler Committed by Facebook Github Bot

Don't cast function call result to void as it can hide nodiscard warnings

Summary:
When assigning a function whose return type is marked `nodiscard` to a `Function<void(Args...)>`, the fact that we are internally explicitly casting the result of the function call to `void` hides the `nodiscard` warning.

For instance:

```
struct [[nodiscard]] DoNotIgnore {};
Function<void()> fn = [] { return DoNotIgnore{}; };
```

emits no warnings, and when `fn()` is invoked, the `DoNotIgnore` struct gets silently ignored.

This diff causes the warning to be emitted.

It is only enabled on compilers that support `if constexpr`. It could be supported on more compilers at the cost of one or more of the following:

* extra template instantiations
* an additional function dispatch
* SFINAE
* Spamming out 4 more specializations of the `FunctionTraits` template.

Reviewed By: yfeldblum

Differential Revision: D18668177

fbshipit-source-id: 0a2cd1366855a0582ab27bb157998d3a4bf4e5a0
parent eaeaa1fa
...@@ -381,14 +381,30 @@ struct FunctionTraits<ReturnType(Args...)> { ...@@ -381,14 +381,30 @@ struct FunctionTraits<ReturnType(Args...)> {
template <typename Fun> template <typename Fun>
static ReturnType callSmall(CallArg<Args>... args, Data& p) { static ReturnType callSmall(CallArg<Args>... args, Data& p) {
return static_cast<ReturnType>((*static_cast<Fun*>( auto& fn = *static_cast<Fun*>(static_cast<void*>(&p.tiny));
static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...)); #if __cpp_if_constexpr >= 201606L
if constexpr (std::is_void<ReturnType>::value) {
fn(static_cast<Args&&>(args)...);
} else {
return fn(static_cast<Args&&>(args)...);
}
#else
return static_cast<ReturnType>(fn(static_cast<Args&&>(args)...));
#endif
} }
template <typename Fun> template <typename Fun>
static ReturnType callBig(CallArg<Args>... args, Data& p) { static ReturnType callBig(CallArg<Args>... args, Data& p) {
return static_cast<ReturnType>( auto& fn = *static_cast<Fun*>(p.big);
(*static_cast<Fun*>(p.big))(static_cast<Args&&>(args)...)); #if __cpp_if_constexpr >= 201606L
if constexpr (std::is_void<ReturnType>::value) {
fn(static_cast<Args&&>(args)...);
} else {
return fn(static_cast<Args&&>(args)...);
}
#else
return static_cast<ReturnType>(fn(static_cast<Args&&>(args)...));
#endif
} }
static ReturnType uninitCall(CallArg<Args>..., Data&) { static ReturnType uninitCall(CallArg<Args>..., Data&) {
...@@ -418,14 +434,30 @@ struct FunctionTraits<ReturnType(Args...) const> { ...@@ -418,14 +434,30 @@ struct FunctionTraits<ReturnType(Args...) const> {
template <typename Fun> template <typename Fun>
static ReturnType callSmall(CallArg<Args>... args, Data& p) { static ReturnType callSmall(CallArg<Args>... args, Data& p) {
return static_cast<ReturnType>((*static_cast<const Fun*>( auto& fn = *static_cast<const Fun*>(static_cast<void*>(&p.tiny));
static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...)); #if __cpp_if_constexpr >= 201606L
if constexpr (std::is_void<ReturnType>::value) {
fn(static_cast<Args&&>(args)...);
} else {
return fn(static_cast<Args&&>(args)...);
}
#else
return static_cast<ReturnType>(fn(static_cast<Args&&>(args)...));
#endif
} }
template <typename Fun> template <typename Fun>
static ReturnType callBig(CallArg<Args>... args, Data& p) { static ReturnType callBig(CallArg<Args>... args, Data& p) {
return static_cast<ReturnType>( auto& fn = *static_cast<const Fun*>(p.big);
(*static_cast<const Fun*>(p.big))(static_cast<Args&&>(args)...)); #if __cpp_if_constexpr >= 201606L
if constexpr (std::is_void<ReturnType>::value) {
fn(static_cast<Args&&>(args)...);
} else {
return fn(static_cast<Args&&>(args)...);
}
#else
return static_cast<ReturnType>(fn(static_cast<Args&&>(args)...));
#endif
} }
static ReturnType uninitCall(CallArg<Args>..., Data&) { static ReturnType uninitCall(CallArg<Args>..., Data&) {
...@@ -456,14 +488,30 @@ struct FunctionTraits<ReturnType(Args...) noexcept> { ...@@ -456,14 +488,30 @@ struct FunctionTraits<ReturnType(Args...) noexcept> {
template <typename Fun> template <typename Fun>
static ReturnType callSmall(CallArg<Args>... args, Data& p) noexcept { static ReturnType callSmall(CallArg<Args>... args, Data& p) noexcept {
return static_cast<ReturnType>((*static_cast<Fun*>( auto& fn = *static_cast<Fun*>(static_cast<void*>(&p.tiny));
static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...)); #if __cpp_if_constexpr >= 201606L
if constexpr (std::is_void<ReturnType>::value) {
fn(static_cast<Args&&>(args)...);
} else {
return fn(static_cast<Args&&>(args)...);
}
#else
return static_cast<ReturnType>(fn(static_cast<Args&&>(args)...));
#endif
} }
template <typename Fun> template <typename Fun>
static ReturnType callBig(CallArg<Args>... args, Data& p) noexcept { static ReturnType callBig(CallArg<Args>... args, Data& p) noexcept {
return static_cast<ReturnType>( auto& fn = *static_cast<Fun*>(p.big);
(*static_cast<Fun*>(p.big))(static_cast<Args&&>(args)...)); #if __cpp_if_constexpr >= 201606L
if constexpr (std::is_void<ReturnType>::value) {
fn(static_cast<Args&&>(args)...);
} else {
return fn(static_cast<Args&&>(args)...);
}
#else
return static_cast<ReturnType>(fn(static_cast<Args&&>(args)...));
#endif
} }
static ReturnType uninitCall(CallArg<Args>..., Data&) noexcept { static ReturnType uninitCall(CallArg<Args>..., Data&) noexcept {
...@@ -493,14 +541,30 @@ struct FunctionTraits<ReturnType(Args...) const noexcept> { ...@@ -493,14 +541,30 @@ struct FunctionTraits<ReturnType(Args...) const noexcept> {
template <typename Fun> template <typename Fun>
static ReturnType callSmall(CallArg<Args>... args, Data& p) noexcept { static ReturnType callSmall(CallArg<Args>... args, Data& p) noexcept {
return static_cast<ReturnType>((*static_cast<const Fun*>( auto& fn = *static_cast<const Fun*>(static_cast<void*>(&p.tiny));
static_cast<void*>(&p.tiny)))(static_cast<Args&&>(args)...)); #if __cpp_if_constexpr >= 201606L
if constexpr (std::is_void<ReturnType>::value) {
fn(static_cast<Args&&>(args)...);
} else {
return fn(static_cast<Args&&>(args)...);
}
#else
return static_cast<ReturnType>(fn(static_cast<Args&&>(args)...));
#endif
} }
template <typename Fun> template <typename Fun>
static ReturnType callBig(CallArg<Args>... args, Data& p) noexcept { static ReturnType callBig(CallArg<Args>... args, Data& p) noexcept {
return static_cast<ReturnType>( auto& fn = *static_cast<const Fun*>(p.big);
(*static_cast<const Fun*>(p.big))(static_cast<Args&&>(args)...)); #if __cpp_if_constexpr >= 201606L
if constexpr (std::is_void<ReturnType>::value) {
fn(static_cast<Args&&>(args)...);
} else {
return fn(static_cast<Args&&>(args)...);
}
#else
return static_cast<ReturnType>(fn(static_cast<Args&&>(args)...));
#endif
} }
static ReturnType uninitCall(CallArg<Args>..., Data&) noexcept { static ReturnType uninitCall(CallArg<Args>..., Data&) noexcept {
......
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