gmock-actions: properly support non-moveable results in is_callable_r.

Previously this excluded callables that return non-moveable types. This is the
same as the
[libc++ std::is_invocable_r bug](https://github.com/llvm/llvm-project/issues/55346)
fixed by
[this commit](https://github.com/llvm/llvm-project/commit/c3a24882903d): it's
wrong to use std::is_convertible for checking the return type, since (despite
its name) that doesn't check the standard-defined notion of "implicitly
convertible". Instead we must base the check on whether the source type can be
used as an argument to a function that accepts the destination type.

PiperOrigin-RevId: 451341205
Change-Id: I2530051312a0361ea7a2ce26993ae973c9242089
This commit is contained in:
Aaron Jacobs
2022-05-27 02:23:19 -07:00
committed by Copybara-Service
parent 56246cdb94
commit 28356773cb
2 changed files with 79 additions and 4 deletions

View File

@@ -192,13 +192,15 @@ TEST(TypeTraits, IsInvocableRV) {
};
// The first overload is callable for const and non-const rvalues and lvalues.
// It can be used to obtain an int, void, or anything int is convertible too.
// It can be used to obtain an int, cv void, or anything int is convertible
// to.
static_assert(internal::is_callable_r<int, C>::value, "");
static_assert(internal::is_callable_r<int, C&>::value, "");
static_assert(internal::is_callable_r<int, const C>::value, "");
static_assert(internal::is_callable_r<int, const C&>::value, "");
static_assert(internal::is_callable_r<void, C>::value, "");
static_assert(internal::is_callable_r<const volatile void, C>::value, "");
static_assert(internal::is_callable_r<char, C>::value, "");
// It's possible to provide an int. If it's given to an lvalue, the result is
@@ -217,6 +219,32 @@ TEST(TypeTraits, IsInvocableRV) {
static_assert(!internal::is_callable_r<void, C, std::string>::value, "");
static_assert(!internal::is_callable_r<void, C, int, int>::value, "");
// In C++17 and above, where it's guaranteed that functions can return
// non-moveable objects, everything should work fine for non-moveable rsult
// types too.
#if defined(__cplusplus) && __cplusplus >= 201703L
{
struct NonMoveable {
NonMoveable() = default;
NonMoveable(NonMoveable&&) = delete;
};
static_assert(!std::is_move_constructible_v<NonMoveable>);
struct Callable {
NonMoveable operator()() { return NonMoveable(); }
};
static_assert(internal::is_callable_r<NonMoveable, Callable>::value);
static_assert(internal::is_callable_r<void, Callable>::value);
static_assert(
internal::is_callable_r<const volatile void, Callable>::value);
static_assert(!internal::is_callable_r<int, Callable>::value);
static_assert(!internal::is_callable_r<NonMoveable, Callable, int>::value);
}
#endif // C++17 and above
// Nothing should choke when we try to call other arguments besides directly
// callable objects, but they should not show up as callable.
static_assert(!internal::is_callable_r<void, int>::value, "");