// Copyright 2022 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/functional/any_invocable.h" #include #include #include #include #include #include "gtest/gtest.h" #include "absl/base/config.h" #include "absl/meta/type_traits.h" #include "absl/utility/utility.h" static_assert(absl::internal_any_invocable::kStorageSize >= sizeof(void*), "These tests assume that the small object storage is at least " "the size of a pointer."); namespace { // Helper macro used to avoid spelling `noexcept` in language versions older // than C++17, where it is not part of the type system, in order to avoid // compilation failures and internal compiler errors. #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L #define ABSL_INTERNAL_NOEXCEPT_SPEC(noex) noexcept(noex) #else #define ABSL_INTERNAL_NOEXCEPT_SPEC(noex) #endif // A dummy type we use when passing qualifiers to metafunctions struct _ {}; template struct Wrapper { template ::value>> Wrapper(U&&); // NOLINT }; // This will cause a recursive trait instantiation if the SFINAE checks are // not ordered correctly for constructibility. static_assert(std::is_constructible>, Wrapper>>::value, ""); // A metafunction that takes the cv and l-value reference qualifiers that were // associated with a function type (here passed via qualifiers of an object // type), and . template struct QualifiersForThisImpl { static_assert(std::is_object::value, ""); using type = absl::conditional_t::value, const This, This>&; }; template struct QualifiersForThisImpl : QualifiersForThisImpl {}; template struct QualifiersForThisImpl { static_assert(std::is_object::value, ""); using type = absl::conditional_t::value, const This, This>&&; }; template using QualifiersForThis = typename QualifiersForThisImpl::type; // A metafunction that takes the cv and l-value reference qualifier of T and // applies them to U's function type qualifiers. template struct GiveQualifiersToFunImpl; template struct GiveQualifiersToFunImpl { using type = absl::conditional_t::value, R(P...) const, R(P...)>; }; template struct GiveQualifiersToFunImpl { using type = absl::conditional_t::value, R(P...) const&, R(P...)&>; }; template struct GiveQualifiersToFunImpl { using type = absl::conditional_t::value, R(P...) const&&, R(P...) &&>; }; // If noexcept is a part of the type system, then provide the noexcept forms. #if defined(__cpp_noexcept_function_type) template struct GiveQualifiersToFunImpl { using type = absl::conditional_t::value, R(P...) const noexcept, R(P...) noexcept>; }; template struct GiveQualifiersToFunImpl { using type = absl::conditional_t::value, R(P...) const & noexcept, R(P...) & noexcept>; }; template struct GiveQualifiersToFunImpl { using type = absl::conditional_t::value, R(P...) const && noexcept, R(P...) && noexcept>; }; #endif // defined(__cpp_noexcept_function_type) template using GiveQualifiersToFun = typename GiveQualifiersToFunImpl::type; // This is used in template parameters to decide whether or not to use a type // that fits in the small object optimization storage. enum class ObjSize { small, large }; // A base type that is used with classes as a means to insert an // appropriately-sized dummy datamember when Size is ObjSize::large so that the // user's class type is guaranteed to not fit in small object storage. template struct TypeErasedPadding; template <> struct TypeErasedPadding {}; template <> struct TypeErasedPadding { char dummy_data[absl::internal_any_invocable::kStorageSize + 1] = {}; }; struct Int { Int(int v) noexcept : value(v) {} // NOLINT #ifndef _MSC_VER Int(Int&&) noexcept { // NOTE: Prior to C++17, this not being called requires optimizations to // take place when performing the top-level invocation. In practice, // most supported compilers perform this optimization prior to C++17. std::abort(); } #else Int(Int&& v) noexcept = default; #endif operator int() && noexcept { return value; } // NOLINT int MemberFunctionAdd(int const& b, int c) noexcept { // NOLINT return value + b + c; } int value; }; enum class Movable { no, yes, nothrow, trivial }; enum class NothrowCall { no, yes }; enum class Destructible { nothrow, trivial }; enum class ObjAlign : std::size_t { normal = absl::internal_any_invocable::kAlignment, large = absl::internal_any_invocable::kAlignment * 2, }; // A function-object template that has knobs for each property that can affect // how the object is stored in AnyInvocable. template struct add; #define ABSL_INTERNALS_ADD(qual) \ template \ struct alignas(static_cast(Alignment)) \ add : TypeErasedPadding { \ explicit add(int state_init) : state(state_init) {} \ explicit add(std::initializer_list state_init, int tail) \ : state(std::accumulate(std::begin(state_init), std::end(state_init), \ 0) + \ tail) {} \ add(add&& other) = default; /*NOLINT*/ \ Int operator()(int a, int b, int c) qual \ ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes) { \ return state + a + b + c; \ } \ int state; \ }; \ \ template \ struct alignas(static_cast(Alignment)) \ add : TypeErasedPadding { \ explicit add(int state_init) : state(state_init) {} \ explicit add(std::initializer_list state_init, int tail) \ : state(std::accumulate(std::begin(state_init), std::end(state_init), \ 0) + \ tail) {} \ ~add() noexcept {} \ add(add&& other) = default; /*NOLINT*/ \ Int operator()(int a, int b, int c) qual \ ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes) { \ return state + a + b + c; \ } \ int state; \ } // Explicitly specify an empty argument. // MSVC (at least up to _MSC_VER 1931, if not beyond) warns that // ABSL_INTERNALS_ADD() is an undefined zero-arg overload. #define ABSL_INTERNALS_NOARG ABSL_INTERNALS_ADD(ABSL_INTERNALS_NOARG); #undef ABSL_INTERNALS_NOARG ABSL_INTERNALS_ADD(const); ABSL_INTERNALS_ADD(&); ABSL_INTERNALS_ADD(const&); ABSL_INTERNALS_ADD(&&); // NOLINT ABSL_INTERNALS_ADD(const&&); // NOLINT #undef ABSL_INTERNALS_ADD template struct add : private add { using Base = add; explicit add(int state_init) : Base(state_init) {} explicit add(std::initializer_list state_init, int tail) : Base(state_init, tail) {} add(add&&) = delete; using Base::operator(); using Base::state; }; template struct add : private add { using Base = add; explicit add(int state_init) : Base(state_init) {} explicit add(std::initializer_list state_init, int tail) : Base(state_init, tail) {} add(add&& other) noexcept(false) : Base(other.state) {} // NOLINT using Base::operator(); using Base::state; }; template struct add : private add { using Base = add; explicit add(int state_init) : Base(state_init) {} explicit add(std::initializer_list state_init, int tail) : Base(state_init, tail) {} add(add&& other) noexcept : Base(other.state) {} using Base::operator(); using Base::state; }; // Actual non-member functions rather than function objects Int add_function(Int&& a, int b, int c) noexcept { return a.value + b + c; } Int mult_function(Int&& a, int b, int c) noexcept { return a.value * b * c; } Int square_function(Int const&& a) noexcept { return a.value * a.value; } template using AnyInvocable = absl::AnyInvocable; // Instantiations of this template contains all of the compile-time parameters // for a given instantiation of the AnyInvocable test suite. template struct TestParams { static constexpr Movable kMovability = Movability; static constexpr Destructible kDestructibility = Destructibility; using Qualifiers = Qual; static constexpr NothrowCall kCallExceptionSpec = CallExceptionSpec; static constexpr bool kIsNoexcept = kCallExceptionSpec == NothrowCall::yes; static constexpr bool kIsRvalueQualified = std::is_rvalue_reference::value; static constexpr ObjSize kSize = Size; static constexpr ObjAlign kAlignment = Alignment; // These types are used when testing with member object pointer Invocables using UnqualifiedUnaryFunType = int(Int const&&) ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes); using UnaryFunType = GiveQualifiersToFun; using MemObjPtrType = int(Int::*); using UnaryAnyInvType = AnyInvocable; using UnaryThisParamType = QualifiersForThis; template static UnaryThisParamType ToUnaryThisParam(T&& fun) { return static_cast(fun); } // This function type intentionally uses 3 "kinds" of parameter types. // - A user-defined type // - A reference type // - A scalar type // // These were chosen because internal forwarding takes place on parameters // differently depending based on type properties (scalars are forwarded by // value). using ResultType = Int; using AnyInvocableFunTypeNotNoexcept = Int(Int, const int&, int); using UnqualifiedFunType = typename std::conditional::type; using FunType = GiveQualifiersToFun; using MemFunPtrType = typename std::conditional::type; using AnyInvType = AnyInvocable; using AddType = add; using ThisParamType = QualifiersForThis; template static ThisParamType ToThisParam(T&& fun) { return static_cast(fun); } // These typedefs are used when testing void return type covariance. using UnqualifiedVoidFunType = typename std::conditional::type; using VoidFunType = GiveQualifiersToFun; using VoidAnyInvType = AnyInvocable; using VoidThisParamType = QualifiersForThis; template static VoidThisParamType ToVoidThisParam(T&& fun) { return static_cast(fun); } using CompatibleAnyInvocableFunType = absl::conditional_t::value, GiveQualifiersToFun, GiveQualifiersToFun>; using CompatibleAnyInvType = AnyInvocable; using IncompatibleInvocable = absl::conditional_t::value, GiveQualifiersToFun<_&, UnqualifiedFunType>(_::*), GiveQualifiersToFun<_&&, UnqualifiedFunType>(_::*)>; }; // Given a member-pointer type, this metafunction yields the target type of the // pointer, not including the class-type. It is used to verify that the function // call operator of AnyInvocable has the proper signature, corresponding to the // function type that the user provided. template struct MemberTypeOfImpl; template struct MemberTypeOfImpl { using type = T; }; template using MemberTypeOf = typename MemberTypeOfImpl::type; template struct IsMemberSwappableImpl : std::false_type { static constexpr bool kIsNothrow = false; }; template struct IsMemberSwappableImpl< T, absl::void_t().swap(std::declval()))>> : std::true_type { static constexpr bool kIsNothrow = noexcept(std::declval().swap(std::declval())); }; template using IsMemberSwappable = IsMemberSwappableImpl; template using IsNothrowMemberSwappable = std::integral_constant::kIsNothrow>; template class AnyInvTestBasic : public ::testing::Test {}; TYPED_TEST_SUITE_P(AnyInvTestBasic); TYPED_TEST_P(AnyInvTestBasic, DefaultConstruction) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun; EXPECT_FALSE(static_cast(fun)); EXPECT_TRUE(std::is_nothrow_default_constructible::value); } TYPED_TEST_P(AnyInvTestBasic, ConstructionNullptr) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun = nullptr; EXPECT_FALSE(static_cast(fun)); EXPECT_TRUE( (std::is_nothrow_constructible::value)); } TYPED_TEST_P(AnyInvTestBasic, ConstructionNullFunctionPtr) { using AnyInvType = typename TypeParam::AnyInvType; using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; UnqualifiedFunType* const null_fun_ptr = nullptr; AnyInvType fun = null_fun_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, ConstructionNullMemberFunctionPtr) { using AnyInvType = typename TypeParam::AnyInvType; using MemFunPtrType = typename TypeParam::MemFunPtrType; const MemFunPtrType null_mem_fun_ptr = nullptr; AnyInvType fun = null_mem_fun_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, ConstructionNullMemberObjectPtr) { using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; using MemObjPtrType = typename TypeParam::MemObjPtrType; const MemObjPtrType null_mem_obj_ptr = nullptr; UnaryAnyInvType fun = null_mem_obj_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, ConstructionMemberFunctionPtr) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun = &Int::MemberFunctionAdd; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestBasic, ConstructionMemberObjectPtr) { using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; UnaryAnyInvType fun = &Int::value; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(13, TypeParam::ToUnaryThisParam(fun)(13)); } TYPED_TEST_P(AnyInvTestBasic, ConstructionFunctionReferenceDecay) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun = add_function; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestBasic, ConstructionCompatibleAnyInvocableEmpty) { using AnyInvType = typename TypeParam::AnyInvType; using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; CompatibleAnyInvType other; AnyInvType fun = std::move(other); EXPECT_FALSE(static_cast(other)); // NOLINT EXPECT_EQ(other, nullptr); // NOLINT EXPECT_EQ(nullptr, other); // NOLINT EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, ConstructionCompatibleAnyInvocableNonempty) { using AnyInvType = typename TypeParam::AnyInvType; using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; CompatibleAnyInvType other = &add_function; AnyInvType fun = std::move(other); EXPECT_FALSE(static_cast(other)); // NOLINT EXPECT_EQ(other, nullptr); // NOLINT EXPECT_EQ(nullptr, other); // NOLINT EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestBasic, ConversionToBool) { using AnyInvType = typename TypeParam::AnyInvType; { AnyInvType fun; // This tests contextually-convertible-to-bool. EXPECT_FALSE(fun ? true : false); // NOLINT // Make sure that the conversion is not implicit. EXPECT_TRUE( (std::is_nothrow_constructible::value)); EXPECT_FALSE((std::is_convertible::value)); } { AnyInvType fun = &add_function; // This tests contextually-convertible-to-bool. EXPECT_TRUE(fun ? true : false); // NOLINT } } TYPED_TEST_P(AnyInvTestBasic, Invocation) { using AnyInvType = typename TypeParam::AnyInvType; using FunType = typename TypeParam::FunType; using AnyInvCallType = MemberTypeOf; // Make sure the function call operator of AnyInvocable always has the // type that was specified via the template argument. EXPECT_TRUE((std::is_same::value)); AnyInvType fun = &add_function; EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestBasic, InPlaceConstruction) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType fun(absl::in_place_type, 5); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestBasic, InPlaceConstructionInitializerList) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType fun(absl::in_place_type, {1, 2, 3, 4}, 5); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(39, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestBasic, InPlaceNullFunPtrConstruction) { using AnyInvType = typename TypeParam::AnyInvType; using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; AnyInvType fun(absl::in_place_type, nullptr); // In-place construction does not lead to empty. EXPECT_TRUE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, InPlaceNullFunPtrConstructionValueInit) { using AnyInvType = typename TypeParam::AnyInvType; using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; AnyInvType fun(absl::in_place_type); // In-place construction does not lead to empty. EXPECT_TRUE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, InPlaceNullMemFunPtrConstruction) { using AnyInvType = typename TypeParam::AnyInvType; using MemFunPtrType = typename TypeParam::MemFunPtrType; AnyInvType fun(absl::in_place_type, nullptr); // In-place construction does not lead to empty. EXPECT_TRUE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, InPlaceNullMemFunPtrConstructionValueInit) { using AnyInvType = typename TypeParam::AnyInvType; using MemFunPtrType = typename TypeParam::MemFunPtrType; AnyInvType fun(absl::in_place_type); // In-place construction does not lead to empty. EXPECT_TRUE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, InPlaceNullMemObjPtrConstruction) { using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; using MemObjPtrType = typename TypeParam::MemObjPtrType; UnaryAnyInvType fun(absl::in_place_type, nullptr); // In-place construction does not lead to empty. EXPECT_TRUE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, InPlaceNullMemObjPtrConstructionValueInit) { using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; using MemObjPtrType = typename TypeParam::MemObjPtrType; UnaryAnyInvType fun(absl::in_place_type); // In-place construction does not lead to empty. EXPECT_TRUE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, InPlaceVoidCovarianceConstruction) { using VoidAnyInvType = typename TypeParam::VoidAnyInvType; using AddType = typename TypeParam::AddType; VoidAnyInvType fun(absl::in_place_type, 5); EXPECT_TRUE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestBasic, MoveConstructionFromEmpty) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType source_fun; AnyInvType fun(std::move(source_fun)); EXPECT_FALSE(static_cast(fun)); EXPECT_TRUE(std::is_nothrow_move_constructible::value); } TYPED_TEST_P(AnyInvTestBasic, MoveConstructionFromNonEmpty) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType source_fun(absl::in_place_type, 5); AnyInvType fun(std::move(source_fun)); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); EXPECT_TRUE(std::is_nothrow_move_constructible::value); } TYPED_TEST_P(AnyInvTestBasic, ComparisonWithNullptrEmpty) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun; EXPECT_TRUE(fun == nullptr); EXPECT_TRUE(nullptr == fun); EXPECT_FALSE(fun != nullptr); EXPECT_FALSE(nullptr != fun); } TYPED_TEST_P(AnyInvTestBasic, ComparisonWithNullptrNonempty) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType fun(absl::in_place_type, 5); EXPECT_FALSE(fun == nullptr); EXPECT_FALSE(nullptr == fun); EXPECT_TRUE(fun != nullptr); EXPECT_TRUE(nullptr != fun); } TYPED_TEST_P(AnyInvTestBasic, ResultType) { using AnyInvType = typename TypeParam::AnyInvType; using ExpectedResultType = typename TypeParam::ResultType; EXPECT_TRUE((std::is_same::value)); } template class AnyInvTestCombinatoric : public ::testing::Test {}; TYPED_TEST_SUITE_P(AnyInvTestCombinatoric); TYPED_TEST_P(AnyInvTestCombinatoric, MoveAssignEmptyEmptyLhsRhs) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType source_fun; AnyInvType fun; fun = std::move(source_fun); EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, MoveAssignEmptyLhsNonemptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType source_fun(absl::in_place_type, 5); AnyInvType fun; fun = std::move(source_fun); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestCombinatoric, MoveAssignNonemptyEmptyLhsRhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType source_fun; AnyInvType fun(absl::in_place_type, 5); fun = std::move(source_fun); EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, MoveAssignNonemptyLhsNonemptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType source_fun(absl::in_place_type, 5); AnyInvType fun(absl::in_place_type, 20); fun = std::move(source_fun); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestCombinatoric, SelfMoveAssignEmpty) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType source_fun; source_fun = std::move(source_fun); // This space intentionally left blank. } TYPED_TEST_P(AnyInvTestCombinatoric, SelfMoveAssignNonempty) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType source_fun(absl::in_place_type, 5); source_fun = std::move(source_fun); // This space intentionally left blank. } TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullptrEmptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun; fun = nullptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullFunctionPtrEmptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; UnqualifiedFunType* const null_fun_ptr = nullptr; AnyInvType fun; fun = null_fun_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullMemberFunctionPtrEmptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; using MemFunPtrType = typename TypeParam::MemFunPtrType; const MemFunPtrType null_mem_fun_ptr = nullptr; AnyInvType fun; fun = null_mem_fun_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullMemberObjectPtrEmptyLhs) { using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; using MemObjPtrType = typename TypeParam::MemObjPtrType; const MemObjPtrType null_mem_obj_ptr = nullptr; UnaryAnyInvType fun; fun = null_mem_obj_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignMemberFunctionPtrEmptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun; fun = &Int::MemberFunctionAdd; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignMemberObjectPtrEmptyLhs) { using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; UnaryAnyInvType fun; fun = &Int::value; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(13, TypeParam::ToUnaryThisParam(fun)(13)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignFunctionReferenceDecayEmptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun; fun = add_function; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignCompatibleAnyInvocableEmptyLhsEmptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; CompatibleAnyInvType other; AnyInvType fun; fun = std::move(other); EXPECT_FALSE(static_cast(other)); // NOLINT EXPECT_EQ(other, nullptr); // NOLINT EXPECT_EQ(nullptr, other); // NOLINT EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignCompatibleAnyInvocableEmptyLhsNonemptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; CompatibleAnyInvType other = &add_function; AnyInvType fun; fun = std::move(other); EXPECT_FALSE(static_cast(other)); // NOLINT EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullptrNonemptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun = &mult_function; fun = nullptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullFunctionPtrNonemptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; using UnqualifiedFunType = typename TypeParam::UnqualifiedFunType; UnqualifiedFunType* const null_fun_ptr = nullptr; AnyInvType fun = &mult_function; fun = null_fun_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullMemberFunctionPtrNonemptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; using MemFunPtrType = typename TypeParam::MemFunPtrType; const MemFunPtrType null_mem_fun_ptr = nullptr; AnyInvType fun = &mult_function; fun = null_mem_fun_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignNullMemberObjectPtrNonemptyLhs) { using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; using MemObjPtrType = typename TypeParam::MemObjPtrType; const MemObjPtrType null_mem_obj_ptr = nullptr; UnaryAnyInvType fun = &square_function; fun = null_mem_obj_ptr; EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignMemberFunctionPtrNonemptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun = &mult_function; fun = &Int::MemberFunctionAdd; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignMemberObjectPtrNonemptyLhs) { using UnaryAnyInvType = typename TypeParam::UnaryAnyInvType; UnaryAnyInvType fun = &square_function; fun = &Int::value; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(13, TypeParam::ToUnaryThisParam(fun)(13)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignFunctionReferenceDecayNonemptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; AnyInvType fun = &mult_function; fun = add_function; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignCompatibleAnyInvocableNonemptyLhsEmptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; CompatibleAnyInvType other; AnyInvType fun = &mult_function; fun = std::move(other); EXPECT_FALSE(static_cast(other)); // NOLINT EXPECT_EQ(other, nullptr); // NOLINT EXPECT_EQ(nullptr, other); // NOLINT EXPECT_FALSE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestCombinatoric, AssignCompatibleAnyInvocableNonemptyLhsNonemptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using CompatibleAnyInvType = typename TypeParam::CompatibleAnyInvType; CompatibleAnyInvType other = &add_function; AnyInvType fun = &mult_function; fun = std::move(other); EXPECT_FALSE(static_cast(other)); // NOLINT EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(24, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestCombinatoric, SwapEmptyLhsEmptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; // Swap idiom { AnyInvType fun; AnyInvType other; using std::swap; swap(fun, other); EXPECT_FALSE(static_cast(fun)); EXPECT_FALSE(static_cast(other)); EXPECT_TRUE( absl::type_traits_internal::IsNothrowSwappable::value); } // Member swap { AnyInvType fun; AnyInvType other; fun.swap(other); EXPECT_FALSE(static_cast(fun)); EXPECT_FALSE(static_cast(other)); EXPECT_TRUE(IsNothrowMemberSwappable::value); } } TYPED_TEST_P(AnyInvTestCombinatoric, SwapEmptyLhsNonemptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; // Swap idiom { AnyInvType fun; AnyInvType other(absl::in_place_type, 5); using std::swap; swap(fun, other); EXPECT_TRUE(static_cast(fun)); EXPECT_FALSE(static_cast(other)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); EXPECT_TRUE( absl::type_traits_internal::IsNothrowSwappable::value); } // Member swap { AnyInvType fun; AnyInvType other(absl::in_place_type, 5); fun.swap(other); EXPECT_TRUE(static_cast(fun)); EXPECT_FALSE(static_cast(other)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); EXPECT_TRUE(IsNothrowMemberSwappable::value); } } TYPED_TEST_P(AnyInvTestCombinatoric, SwapNonemptyLhsEmptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; // Swap idiom { AnyInvType fun(absl::in_place_type, 5); AnyInvType other; using std::swap; swap(fun, other); EXPECT_FALSE(static_cast(fun)); EXPECT_TRUE(static_cast(other)); EXPECT_EQ(29, TypeParam::ToThisParam(other)(7, 8, 9).value); EXPECT_TRUE( absl::type_traits_internal::IsNothrowSwappable::value); } // Member swap { AnyInvType fun(absl::in_place_type, 5); AnyInvType other; fun.swap(other); EXPECT_FALSE(static_cast(fun)); EXPECT_TRUE(static_cast(other)); EXPECT_EQ(29, TypeParam::ToThisParam(other)(7, 8, 9).value); EXPECT_TRUE(IsNothrowMemberSwappable::value); } } TYPED_TEST_P(AnyInvTestCombinatoric, SwapNonemptyLhsNonemptyRhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; // Swap idiom { AnyInvType fun(absl::in_place_type, 5); AnyInvType other(absl::in_place_type, 6); using std::swap; swap(fun, other); EXPECT_TRUE(static_cast(fun)); EXPECT_TRUE(static_cast(other)); EXPECT_EQ(30, TypeParam::ToThisParam(fun)(7, 8, 9).value); EXPECT_EQ(29, TypeParam::ToThisParam(other)(7, 8, 9).value); EXPECT_TRUE( absl::type_traits_internal::IsNothrowSwappable::value); } // Member swap { AnyInvType fun(absl::in_place_type, 5); AnyInvType other(absl::in_place_type, 6); fun.swap(other); EXPECT_TRUE(static_cast(fun)); EXPECT_TRUE(static_cast(other)); EXPECT_EQ(30, TypeParam::ToThisParam(fun)(7, 8, 9).value); EXPECT_EQ(29, TypeParam::ToThisParam(other)(7, 8, 9).value); EXPECT_TRUE(IsNothrowMemberSwappable::value); } } template class AnyInvTestMovable : public ::testing::Test {}; TYPED_TEST_SUITE_P(AnyInvTestMovable); TYPED_TEST_P(AnyInvTestMovable, ConversionConstructionUserDefinedType) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType fun(AddType(5)); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestMovable, ConversionConstructionVoidCovariance) { using VoidAnyInvType = typename TypeParam::VoidAnyInvType; using AddType = typename TypeParam::AddType; VoidAnyInvType fun(AddType(5)); EXPECT_TRUE(static_cast(fun)); } TYPED_TEST_P(AnyInvTestMovable, ConversionAssignUserDefinedTypeEmptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType fun; fun = AddType(5); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestMovable, ConversionAssignUserDefinedTypeNonemptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType fun = &add_function; fun = AddType(5); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); } TYPED_TEST_P(AnyInvTestMovable, ConversionAssignVoidCovariance) { using VoidAnyInvType = typename TypeParam::VoidAnyInvType; using AddType = typename TypeParam::AddType; VoidAnyInvType fun; fun = AddType(5); EXPECT_TRUE(static_cast(fun)); } template class AnyInvTestNoexceptFalse : public ::testing::Test {}; TYPED_TEST_SUITE_P(AnyInvTestNoexceptFalse); TYPED_TEST_P(AnyInvTestNoexceptFalse, ConversionConstructionConstraints) { using AnyInvType = typename TypeParam::AnyInvType; EXPECT_TRUE((std::is_constructible< AnyInvType, typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value)); EXPECT_FALSE(( std::is_constructible::value)); } TYPED_TEST_P(AnyInvTestNoexceptFalse, ConversionAssignConstraints) { using AnyInvType = typename TypeParam::AnyInvType; EXPECT_TRUE((std::is_assignable< AnyInvType&, typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value)); EXPECT_FALSE( (std::is_assignable::value)); } template class AnyInvTestNoexceptTrue : public ::testing::Test {}; TYPED_TEST_SUITE_P(AnyInvTestNoexceptTrue); TYPED_TEST_P(AnyInvTestNoexceptTrue, ConversionConstructionConstraints) { #if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L GTEST_SKIP() << "Noexcept was not part of the type system before C++17."; #else using AnyInvType = typename TypeParam::AnyInvType; EXPECT_FALSE((std::is_constructible< AnyInvType, typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value)); EXPECT_FALSE(( std::is_constructible::value)); #endif } TYPED_TEST_P(AnyInvTestNoexceptTrue, ConversionAssignConstraints) { #if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L GTEST_SKIP() << "Noexcept was not part of the type system before C++17."; #else using AnyInvType = typename TypeParam::AnyInvType; EXPECT_FALSE((std::is_assignable< AnyInvType&, typename TypeParam::AnyInvocableFunTypeNotNoexcept*>::value)); EXPECT_FALSE( (std::is_assignable::value)); #endif } template class AnyInvTestNonRvalue : public ::testing::Test {}; TYPED_TEST_SUITE_P(AnyInvTestNonRvalue); TYPED_TEST_P(AnyInvTestNonRvalue, ConversionConstructionReferenceWrapper) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AddType add(4); AnyInvType fun = std::ref(add); add.state = 5; EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).value); } TYPED_TEST_P(AnyInvTestNonRvalue, NonMoveableResultType) { #if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L GTEST_SKIP() << "Copy/move elision was not standard before C++17"; #else // Define a result type that cannot be copy- or move-constructed. struct Result { int x; explicit Result(const int x_in) : x(x_in) {} Result(Result&&) = delete; }; static_assert(!std::is_move_constructible::value, ""); static_assert(!std::is_copy_constructible::value, ""); // Assumption check: it should nevertheless be possible to use functors that // return a Result struct according to the language rules. const auto return_17 = []() noexcept { return Result(17); }; EXPECT_EQ(17, return_17().x); // Just like plain functors, it should work fine to use an AnyInvocable that // returns the non-moveable type. using UnqualifiedFun = absl::conditional_t; using Fun = GiveQualifiersToFun; AnyInvocable any_inv(return_17); EXPECT_EQ(17, any_inv().x); #endif } TYPED_TEST_P(AnyInvTestNonRvalue, ConversionAssignReferenceWrapperEmptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AddType add(4); AnyInvType fun; fun = std::ref(add); add.state = 5; EXPECT_TRUE( (std::is_nothrow_assignable>::value)); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).value); } TYPED_TEST_P(AnyInvTestNonRvalue, ConversionAssignReferenceWrapperNonemptyLhs) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AddType add(4); AnyInvType fun = &mult_function; fun = std::ref(add); add.state = 5; EXPECT_TRUE( (std::is_nothrow_assignable>::value)); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(29, TypeParam::ToThisParam(fun)(7, 8, 9).value); EXPECT_TRUE(static_cast(fun)); EXPECT_EQ(38, TypeParam::ToThisParam(fun)(10, 11, 12).value); } template class AnyInvTestRvalue : public ::testing::Test {}; TYPED_TEST_SUITE_P(AnyInvTestRvalue); TYPED_TEST_P(AnyInvTestRvalue, ConversionConstructionReferenceWrapper) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; EXPECT_FALSE(( std::is_convertible, AnyInvType>::value)); } TYPED_TEST_P(AnyInvTestRvalue, NonMoveableResultType) { #if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L GTEST_SKIP() << "Copy/move elision was not standard before C++17"; #else // Define a result type that cannot be copy- or move-constructed. struct Result { int x; explicit Result(const int x_in) : x(x_in) {} Result(Result&&) = delete; }; static_assert(!std::is_move_constructible::value, ""); static_assert(!std::is_copy_constructible::value, ""); // Assumption check: it should nevertheless be possible to use functors that // return a Result struct according to the language rules. const auto return_17 = []() noexcept { return Result(17); }; EXPECT_EQ(17, return_17().x); // Just like plain functors, it should work fine to use an AnyInvocable that // returns the non-moveable type. using UnqualifiedFun = absl::conditional_t; using Fun = GiveQualifiersToFun; EXPECT_EQ(17, AnyInvocable(return_17)().x); #endif } TYPED_TEST_P(AnyInvTestRvalue, ConversionAssignReferenceWrapper) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; EXPECT_FALSE(( std::is_assignable>::value)); } TYPED_TEST_P(AnyInvTestRvalue, NonConstCrashesOnSecondCall) { using AnyInvType = typename TypeParam::AnyInvType; using AddType = typename TypeParam::AddType; AnyInvType fun(absl::in_place_type, 5); EXPECT_TRUE(static_cast(fun)); std::move(fun)(7, 8, 9); // Ensure we're still valid EXPECT_TRUE(static_cast(fun)); // NOLINT(bugprone-use-after-move) #if !defined(NDEBUG) EXPECT_DEATH_IF_SUPPORTED(std::move(fun)(7, 8, 9), ""); #endif } // Ensure that any qualifiers (in particular &&-qualifiers) do not affect // when the destructor is actually run. TYPED_TEST_P(AnyInvTestRvalue, QualifierIndependentObjectLifetime) { using AnyInvType = typename TypeParam::AnyInvType; auto refs = std::make_shared(); { AnyInvType fun([refs](auto&&...) noexcept { return 0; }); EXPECT_GT(refs.use_count(), 1); std::move(fun)(7, 8, 9); // Ensure destructor hasn't run even if rref-qualified EXPECT_GT(refs.use_count(), 1); } EXPECT_EQ(refs.use_count(), 1); } // NOTE: This test suite originally attempted to enumerate all possible // combinations of type properties but the build-time started getting too large. // Instead, it is now assumed that certain parameters are orthogonal and so // some combinations are elided. // A metafunction to form a TypeList of all cv and non-rvalue ref combinations, // coupled with all of the other explicitly specified parameters. template using NonRvalueQualifiedTestParams = ::testing::Types< // TestParams, // TestParams, // TestParams, // TestParams>; // A metafunction to form a TypeList of const and non-const rvalue ref // qualifiers, coupled with all of the other explicitly specified parameters. template using RvalueQualifiedTestParams = ::testing::Types< TestParams, // TestParams // >; // All qualifier combinations and a noexcept function type using TestParameterListNonRvalueQualifiersNothrowCall = NonRvalueQualifiedTestParams; using TestParameterListRvalueQualifiersNothrowCall = RvalueQualifiedTestParams; // All qualifier combinations and a non-noexcept function type using TestParameterListNonRvalueQualifiersCallMayThrow = NonRvalueQualifiedTestParams; using TestParameterListRvalueQualifiersCallMayThrow = RvalueQualifiedTestParams; // Lists of various cases that should lead to remote storage using TestParameterListRemoteMovable = ::testing::Types< // "Normal" aligned types that are large and have trivial destructors TestParams, // TestParams, // TestParams, // TestParams, // // Same as above but with non-trivial destructors TestParams, // TestParams, // TestParams, // TestParams // // Dynamic memory allocation for over-aligned data was introduced in C++17. // See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r4.html #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L // Types that must use remote storage because of a large alignment. , TestParams, // TestParams, // TestParams, // TestParams // #endif >; using TestParameterListRemoteNonMovable = ::testing::Types< // "Normal" aligned types that are large and have trivial destructors TestParams, // TestParams, // // Same as above but with non-trivial destructors TestParams, // TestParams // >; // Parameters that lead to local storage using TestParameterListLocal = ::testing::Types< // Types that meet the requirements and have trivial destructors TestParams, // TestParams, // // Same as above but with non-trivial destructors TestParams, // TestParams // >; // All of the tests that are run for every possible combination of types. REGISTER_TYPED_TEST_SUITE_P( AnyInvTestBasic, DefaultConstruction, ConstructionNullptr, ConstructionNullFunctionPtr, ConstructionNullMemberFunctionPtr, ConstructionNullMemberObjectPtr, ConstructionMemberFunctionPtr, ConstructionMemberObjectPtr, ConstructionFunctionReferenceDecay, ConstructionCompatibleAnyInvocableEmpty, ConstructionCompatibleAnyInvocableNonempty, InPlaceConstruction, ConversionToBool, Invocation, InPlaceConstructionInitializerList, InPlaceNullFunPtrConstruction, InPlaceNullFunPtrConstructionValueInit, InPlaceNullMemFunPtrConstruction, InPlaceNullMemFunPtrConstructionValueInit, InPlaceNullMemObjPtrConstruction, InPlaceNullMemObjPtrConstructionValueInit, InPlaceVoidCovarianceConstruction, MoveConstructionFromEmpty, MoveConstructionFromNonEmpty, ComparisonWithNullptrEmpty, ComparisonWithNullptrNonempty, ResultType); INSTANTIATE_TYPED_TEST_SUITE_P( NonRvalueCallMayThrow, AnyInvTestBasic, TestParameterListNonRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestBasic, TestParameterListRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestBasic, TestParameterListRemoteMovable); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteNonMovable, AnyInvTestBasic, TestParameterListRemoteNonMovable); INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestBasic, TestParameterListLocal); INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestBasic, TestParameterListNonRvalueQualifiersNothrowCall); INSTANTIATE_TYPED_TEST_SUITE_P(CallNothrowRvalue, AnyInvTestBasic, TestParameterListRvalueQualifiersNothrowCall); // Tests for functions that take two operands. REGISTER_TYPED_TEST_SUITE_P( AnyInvTestCombinatoric, MoveAssignEmptyEmptyLhsRhs, MoveAssignEmptyLhsNonemptyRhs, MoveAssignNonemptyEmptyLhsRhs, MoveAssignNonemptyLhsNonemptyRhs, SelfMoveAssignEmpty, SelfMoveAssignNonempty, AssignNullptrEmptyLhs, AssignNullFunctionPtrEmptyLhs, AssignNullMemberFunctionPtrEmptyLhs, AssignNullMemberObjectPtrEmptyLhs, AssignMemberFunctionPtrEmptyLhs, AssignMemberObjectPtrEmptyLhs, AssignFunctionReferenceDecayEmptyLhs, AssignCompatibleAnyInvocableEmptyLhsEmptyRhs, AssignCompatibleAnyInvocableEmptyLhsNonemptyRhs, AssignNullptrNonemptyLhs, AssignNullFunctionPtrNonemptyLhs, AssignNullMemberFunctionPtrNonemptyLhs, AssignNullMemberObjectPtrNonemptyLhs, AssignMemberFunctionPtrNonemptyLhs, AssignMemberObjectPtrNonemptyLhs, AssignFunctionReferenceDecayNonemptyLhs, AssignCompatibleAnyInvocableNonemptyLhsEmptyRhs, AssignCompatibleAnyInvocableNonemptyLhsNonemptyRhs, SwapEmptyLhsEmptyRhs, SwapEmptyLhsNonemptyRhs, SwapNonemptyLhsEmptyRhs, SwapNonemptyLhsNonemptyRhs); INSTANTIATE_TYPED_TEST_SUITE_P( NonRvalueCallMayThrow, AnyInvTestCombinatoric, TestParameterListNonRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestCombinatoric, TestParameterListRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestCombinatoric, TestParameterListRemoteMovable); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteNonMovable, AnyInvTestCombinatoric, TestParameterListRemoteNonMovable); INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestCombinatoric, TestParameterListLocal); INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestCombinatoric, TestParameterListNonRvalueQualifiersNothrowCall); INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallNothrow, AnyInvTestCombinatoric, TestParameterListRvalueQualifiersNothrowCall); REGISTER_TYPED_TEST_SUITE_P(AnyInvTestMovable, ConversionConstructionUserDefinedType, ConversionConstructionVoidCovariance, ConversionAssignUserDefinedTypeEmptyLhs, ConversionAssignUserDefinedTypeNonemptyLhs, ConversionAssignVoidCovariance); INSTANTIATE_TYPED_TEST_SUITE_P( NonRvalueCallMayThrow, AnyInvTestMovable, TestParameterListNonRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestMovable, TestParameterListRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestMovable, TestParameterListRemoteMovable); INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestMovable, TestParameterListLocal); INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestMovable, TestParameterListNonRvalueQualifiersNothrowCall); INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallNothrow, AnyInvTestMovable, TestParameterListRvalueQualifiersNothrowCall); REGISTER_TYPED_TEST_SUITE_P(AnyInvTestNoexceptFalse, ConversionConstructionConstraints, ConversionAssignConstraints); INSTANTIATE_TYPED_TEST_SUITE_P( NonRvalueCallMayThrow, AnyInvTestNoexceptFalse, TestParameterListNonRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestNoexceptFalse, TestParameterListRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestNoexceptFalse, TestParameterListRemoteMovable); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteNonMovable, AnyInvTestNoexceptFalse, TestParameterListRemoteNonMovable); INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestNoexceptFalse, TestParameterListLocal); REGISTER_TYPED_TEST_SUITE_P(AnyInvTestNoexceptTrue, ConversionConstructionConstraints, ConversionAssignConstraints); INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestNoexceptTrue, TestParameterListNonRvalueQualifiersNothrowCall); INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallNothrow, AnyInvTestNoexceptTrue, TestParameterListRvalueQualifiersNothrowCall); REGISTER_TYPED_TEST_SUITE_P(AnyInvTestNonRvalue, ConversionConstructionReferenceWrapper, NonMoveableResultType, ConversionAssignReferenceWrapperEmptyLhs, ConversionAssignReferenceWrapperNonemptyLhs); INSTANTIATE_TYPED_TEST_SUITE_P( NonRvalueCallMayThrow, AnyInvTestNonRvalue, TestParameterListNonRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteMovable, AnyInvTestNonRvalue, TestParameterListRemoteMovable); INSTANTIATE_TYPED_TEST_SUITE_P(RemoteNonMovable, AnyInvTestNonRvalue, TestParameterListRemoteNonMovable); INSTANTIATE_TYPED_TEST_SUITE_P(Local, AnyInvTestNonRvalue, TestParameterListLocal); INSTANTIATE_TYPED_TEST_SUITE_P(NonRvalueCallNothrow, AnyInvTestNonRvalue, TestParameterListNonRvalueQualifiersNothrowCall); REGISTER_TYPED_TEST_SUITE_P(AnyInvTestRvalue, ConversionConstructionReferenceWrapper, NonMoveableResultType, ConversionAssignReferenceWrapper, NonConstCrashesOnSecondCall, QualifierIndependentObjectLifetime); INSTANTIATE_TYPED_TEST_SUITE_P(RvalueCallMayThrow, AnyInvTestRvalue, TestParameterListRvalueQualifiersCallMayThrow); INSTANTIATE_TYPED_TEST_SUITE_P(CallNothrowRvalue, AnyInvTestRvalue, TestParameterListRvalueQualifiersNothrowCall); // Minimal SFINAE testing for platforms where we can't run the tests, but we can // build binaries for. static_assert( std::is_convertible>::value, ""); static_assert(!std::is_convertible>::value, ""); #undef ABSL_INTERNAL_NOEXCEPT_SPEC } // namespace