diff options
author | Eric Fiselier <eric@efcs.ca> | 2015-07-28 01:25:36 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2015-07-28 01:25:36 +0000 |
commit | 522b1d14efe523b983eea899ab07524b27d14ff7 (patch) | |
tree | beb4aeeac0a770f6c15b4ceb6642d69f80c1ec19 /libcxx/test/std/utilities | |
parent | ae7df1ca4db5643faae83d7d69d386ab12ea75a2 (diff) | |
download | bcm5719-llvm-522b1d14efe523b983eea899ab07524b27d14ff7.tar.gz bcm5719-llvm-522b1d14efe523b983eea899ab07524b27d14ff7.zip |
Checking more __invoke tests.
Before I start trying to fix __invoke in C++03 it needs better test coverage.
This patch adds a large amount of tests for __invoke.
llvm-svn: 243366
Diffstat (limited to 'libcxx/test/std/utilities')
4 files changed, 1126 insertions, 0 deletions
diff --git a/libcxx/test/std/utilities/function.objects/func.require/bullet_1_and_2.pass.cpp b/libcxx/test/std/utilities/function.objects/func.require/bullet_1_and_2.pass.cpp new file mode 100644 index 00000000000..e579f207a33 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.require/bullet_1_and_2.pass.cpp @@ -0,0 +1,318 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <functional> + +// INVOKE (f, t1, t2, ..., tN) + +//------------------------------------------------------------------------------ +// TESTING INVOKE(f, t1, t2, ..., tN) +// - Bullet 1 -- (t1.*f)(t2, ..., tN) +// - Bullet 2 -- ((*t1).*f)(t2, ..., tN) +// +// Overview: +// Bullets 1 and 2 handle the case where 'f' is a pointer to member function. +// Bullet 1 only handles the cases where t1 is an object of type T or a +// type derived from 'T'. Bullet 2 handles all other cases. +// +// Concerns: +// 1) cv-qualified member function signatures are accepted. +// 2) reference qualified member function signatures are accepted. +// 3) member functions with varargs at the end are accepted. +// 4) The arguments are perfect forwarded to the member function call. +// 5) Classes that are publicly derived from 'T' are accepted as the call object +// 6) All types that dereference to T or a type derived from T can be used +// as the call object. +// 7) Pointers to T or a type derived from T can be used as the call object. +// 8) Reference return types are properly deduced. +// +// +// Plan: +// 1) Create a class that contains a set, 'S', of non-static functions. +// 'S' should include functions that cover every single combination +// of qualifiers and varargs for arities of 0, 1 and 2 (C-1,2,3). +// The argument types used in the functions should be non-copyable (C-4). +// The functions should return 'MethodID::setUncheckedCall()'. +// +// 2) Create a set of supported call object, 'Objs', of different types +// and behaviors. (C-5,6,7) +// +// 3) Attempt to call each function, 'f', in 'S' with each call object, 'c', +// in 'Objs'. After every attempted call to 'f' check that 'f' was +// actually called using 'MethodID::checkCalled(<return-value>)' +// +// 3b) If 'f' is reference qualified call 'f' with the properly qualified +// call object. Otherwise call 'f' with lvalue call objects. +// +// 3a) If 'f' is const, volatile, or cv qualified then call it with call +// objects that are equally or less cv-qualified. + +#include <functional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "invoke_helpers.h" + +//============================================================================== +// MemFun03 - C++03 compatible set of test member functions. +struct MemFun03 { + typedef void*& R; +#define F(...) \ + R f(__VA_ARGS__) { return MethodID<R(MemFun03::*)(__VA_ARGS__)>::setUncheckedCall(); } \ + R f(__VA_ARGS__) const { return MethodID<R(MemFun03::*)(__VA_ARGS__) const>::setUncheckedCall(); } \ + R f(__VA_ARGS__) volatile { return MethodID<R(MemFun03::*)(__VA_ARGS__) volatile>::setUncheckedCall(); } \ + R f(__VA_ARGS__) const volatile { return MethodID<R(MemFun03::*)(__VA_ARGS__) const volatile>::setUncheckedCall(); } +# + F() + F(...) + F(ArgType&) + F(ArgType&, ...) + F(ArgType&, ArgType&) + F(ArgType&, ArgType&, ...) + F(ArgType&, ArgType&, ArgType&) + F(ArgType&, ArgType&, ArgType&, ...) +#undef F +public: + MemFun03() {} +private: + MemFun03(MemFun03 const&); + MemFun03& operator=(MemFun03 const&); +}; + + +#if TEST_STD_VER >= 11 + +//============================================================================== +// MemFun11 - C++11 reference qualified test member functions. +struct MemFun11 { + typedef void*& R; + typedef MemFun11 C; +#define F(...) \ + R f(__VA_ARGS__) & { return MethodID<R(C::*)(__VA_ARGS__) &>::setUncheckedCall(); } \ + R f(__VA_ARGS__) const & { return MethodID<R(C::*)(__VA_ARGS__) const &>::setUncheckedCall(); } \ + R f(__VA_ARGS__) volatile & { return MethodID<R(C::*)(__VA_ARGS__) volatile &>::setUncheckedCall(); } \ + R f(__VA_ARGS__) const volatile & { return MethodID<R(C::*)(__VA_ARGS__) const volatile &>::setUncheckedCall(); } \ + R f(__VA_ARGS__) && { return MethodID<R(C::*)(__VA_ARGS__) &&>::setUncheckedCall(); } \ + R f(__VA_ARGS__) const && { return MethodID<R(C::*)(__VA_ARGS__) const &&>::setUncheckedCall(); } \ + R f(__VA_ARGS__) volatile && { return MethodID<R(C::*)(__VA_ARGS__) volatile &&>::setUncheckedCall(); } \ + R f(__VA_ARGS__) const volatile && { return MethodID<R(C::*)(__VA_ARGS__) const volatile &&>::setUncheckedCall(); } +# + F() + F(...) + F(ArgType&&) + F(ArgType&&, ...) + F(ArgType&&, ArgType&&) + F(ArgType&&, ArgType&&, ...) + F(ArgType&&, ArgType&&, ArgType&&) + F(ArgType&&, ArgType&&, ArgType&&, ...) +#undef F +public: + MemFun11() {} +private: + MemFun11(MemFun11 const&); + MemFun11& operator=(MemFun11 const&); +}; + +#endif // TEST_STD_VER >= 11 + + +//============================================================================== +// TestCase - A test case for a single member function. +// ClassType - The type of the class being tested. +// CallSig - The function signature of the method being tested. +// Arity - the arity of 'CallSig' +// CV - the cv qualifiers of 'CallSig' represented as a type tag. +// RValue - The method is RValue qualified. +// ArgRValue - Call the method with RValue arguments. +template <class ClassType, class CallSig, int Arity, class CV, + bool RValue = false, bool ArgRValue = false> +struct TestCaseImp { +public: + + static void run() { TestCaseImp().doTest(); } + +private: + //========================================================================== + // TEST DISPATCH + void doTest() { + // (Plan-2) Create test call objects. + typedef ClassType T; + typedef DerivedFromType<T> D; + T obj; + T* obj_ptr = &obj; + D der; + D* der_ptr = &der; + DerefToType<T> dref; + DerefPropType<T> dref2; + + // (Plan-3) Dispatch based on the CV tags. + CV tag; + Bool<!RValue> NotRValue; + runTestDispatch(tag, obj); + runTestDispatch(tag, der); + runTestDispatch(tag, dref2); + runTestDispatchIf(NotRValue, tag, dref); + runTestDispatchIf(NotRValue, tag, obj_ptr); + runTestDispatchIf(NotRValue, tag, der_ptr); + } + + template <class QT, class Tp> + void runTestDispatchIf(Bool<true>, QT q, Tp& v) { + runTestDispatch(q, v); + } + + template <class QT, class Tp> + void runTestDispatchIf(Bool<false>, QT, Tp&) { + } + + template <class Tp> + void runTestDispatch(Q_None, Tp& v) { + runTest(v); + } + + template <class Tp> + void runTestDispatch(Q_Const, Tp& v) { + Tp const& cv = v; + runTest(v); + runTest(cv); + } + + template <class Tp> + void runTestDispatch(Q_Volatile, Tp& v) { + Tp volatile& vv = v; + runTest(v); + runTest(vv); + } + + template <class Tp> + void runTestDispatch(Q_CV, Tp& v) { + Tp const& cv = v; + Tp volatile& vv = v; + Tp const volatile& cvv = v; + runTest(v); + runTest(cv); + runTest(vv); + runTest(cvv); + } + + template <class Obj> + void runTest(Obj& obj) { + typedef Caster<Q_None, RValue> SCast; + typedef Caster<Q_None, ArgRValue> ACast; + typedef CallSig (ClassType::*MemPtr); + // Delegate test to logic in invoke_helpers.h + BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b; + b.runTest( (MemPtr)&ClassType::f, obj); + } +}; + +template <class Sig, int Arity, class CV> +struct TestCase : public TestCaseImp<MemFun03, Sig, Arity, CV> {}; + +#if TEST_STD_VER >= 11 +template <class Sig, int Arity, class CV, bool RValue = false> +struct TestCase11 : public TestCaseImp<MemFun11, Sig, Arity, CV, RValue, true> {}; +#endif + +int main() { + typedef void*& R; + typedef ArgType A; + TestCase<R(), 0, Q_None>::run(); + TestCase<R() const, 0, Q_Const>::run(); + TestCase<R() volatile, 0, Q_Volatile>::run(); + TestCase<R() const volatile, 0, Q_CV>::run(); + TestCase<R(...), 0, Q_None>::run(); + TestCase<R(...) const, 0, Q_Const>::run(); + TestCase<R(...) volatile, 0, Q_Volatile>::run(); + TestCase<R(...) const volatile, 0, Q_CV>::run(); + TestCase<R(A&), 1, Q_None>::run(); + TestCase<R(A&) const, 1, Q_Const>::run(); + TestCase<R(A&) volatile, 1, Q_Volatile>::run(); + TestCase<R(A&) const volatile, 1, Q_CV>::run(); + TestCase<R(A&, ...), 1, Q_None>::run(); + TestCase<R(A&, ...) const, 1, Q_Const>::run(); + TestCase<R(A&, ...) volatile, 1, Q_Volatile>::run(); + TestCase<R(A&, ...) const volatile, 1, Q_CV>::run(); + TestCase<R(A&, A&), 2, Q_None>::run(); + TestCase<R(A&, A&) const, 2, Q_Const>::run(); + TestCase<R(A&, A&) volatile, 2, Q_Volatile>::run(); + TestCase<R(A&, A&) const volatile, 2, Q_CV>::run(); + TestCase<R(A&, A&, ...), 2, Q_None>::run(); + TestCase<R(A&, A&, ...) const, 2, Q_Const>::run(); + TestCase<R(A&, A&, ...) volatile, 2, Q_Volatile>::run(); + TestCase<R(A&, A&, ...) const volatile, 2, Q_CV>::run(); + TestCase<R(A&, A&, A&), 3, Q_None>::run(); + TestCase<R(A&, A&, A&) const, 3, Q_Const>::run(); + TestCase<R(A&, A&, A&) volatile, 3, Q_Volatile>::run(); + TestCase<R(A&, A&, A&) const volatile, 3, Q_CV>::run(); + TestCase<R(A&, A&, A&, ...), 3, Q_None>::run(); + TestCase<R(A&, A&, A&, ...) const, 3, Q_Const>::run(); + TestCase<R(A&, A&, A&, ...) volatile, 3, Q_Volatile>::run(); + TestCase<R(A&, A&, A&, ...) const volatile, 3, Q_CV>::run(); + +#if TEST_STD_VER >= 11 + TestCase11<R() &, 0, Q_None>::run(); + TestCase11<R() const &, 0, Q_Const>::run(); + TestCase11<R() volatile &, 0, Q_Volatile>::run(); + TestCase11<R() const volatile &, 0, Q_CV>::run(); + TestCase11<R(...) &, 0, Q_None>::run(); + TestCase11<R(...) const &, 0, Q_Const>::run(); + TestCase11<R(...) volatile &, 0, Q_Volatile>::run(); + TestCase11<R(...) const volatile &, 0, Q_CV>::run(); + TestCase11<R(A&&) &, 1, Q_None>::run(); + TestCase11<R(A&&) const &, 1, Q_Const>::run(); + TestCase11<R(A&&) volatile &, 1, Q_Volatile>::run(); + TestCase11<R(A&&) const volatile &, 1, Q_CV>::run(); + TestCase11<R(A&&, ...) &, 1, Q_None>::run(); + TestCase11<R(A&&, ...) const &, 1, Q_Const>::run(); + TestCase11<R(A&&, ...) volatile &, 1, Q_Volatile>::run(); + TestCase11<R(A&&, ...) const volatile &, 1, Q_CV>::run(); + TestCase11<R(A&&, A&&) &, 2, Q_None>::run(); + TestCase11<R(A&&, A&&) const &, 2, Q_Const>::run(); + TestCase11<R(A&&, A&&) volatile &, 2, Q_Volatile>::run(); + TestCase11<R(A&&, A&&) const volatile &, 2, Q_CV>::run(); + TestCase11<R(A&&, A&&, ...) &, 2, Q_None>::run(); + TestCase11<R(A&&, A&&, ...) const &, 2, Q_Const>::run(); + TestCase11<R(A&&, A&&, ...) volatile &, 2, Q_Volatile>::run(); + TestCase11<R(A&&, A&&, ...) const volatile &, 2, Q_CV>::run(); + TestCase11<R() &&, 0, Q_None, /* RValue */ true>::run(); + TestCase11<R() const &&, 0, Q_Const, /* RValue */ true>::run(); + TestCase11<R() volatile &&, 0, Q_Volatile, /* RValue */ true>::run(); + TestCase11<R() const volatile &&, 0, Q_CV, /* RValue */ true>::run(); + TestCase11<R(...) &&, 0, Q_None, /* RValue */ true>::run(); + TestCase11<R(...) const &&, 0, Q_Const, /* RValue */ true>::run(); + TestCase11<R(...) volatile &&, 0, Q_Volatile, /* RValue */ true>::run(); + TestCase11<R(...) const volatile &&, 0, Q_CV, /* RValue */ true>::run(); + TestCase11<R(A&&) &&, 1, Q_None, /* RValue */ true>::run(); + TestCase11<R(A&&) const &&, 1, Q_Const, /* RValue */ true>::run(); + TestCase11<R(A&&) volatile &&, 1, Q_Volatile, /* RValue */ true>::run(); + TestCase11<R(A&&) const volatile &&, 1, Q_CV, /* RValue */ true>::run(); + TestCase11<R(A&&, ...) &&, 1, Q_None, /* RValue */ true>::run(); + TestCase11<R(A&&, ...) const &&, 1, Q_Const, /* RValue */ true>::run(); + TestCase11<R(A&&, ...) volatile &&, 1, Q_Volatile, /* RValue */ true>::run(); + TestCase11<R(A&&, ...) const volatile &&, 1, Q_CV, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&) &&, 2, Q_None, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&) const &&, 2, Q_Const, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&) volatile &&, 2, Q_Volatile, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&) const volatile &&, 2, Q_CV, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, ...) &&, 2, Q_None, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, ...) const &&, 2, Q_Const, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, ...) volatile &&, 2, Q_Volatile, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, ...) const volatile &&, 2, Q_CV, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, A&&) &&, 3, Q_None, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, A&&) const &&, 3, Q_Const, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, A&&) volatile &&, 3, Q_Volatile, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, A&&) const volatile &&, 3, Q_CV, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, A&&, ...) &&, 3, Q_None, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, A&&, ...) const &&, 3, Q_Const, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, A&&, ...) volatile &&, 3, Q_Volatile, /* RValue */ true>::run(); + TestCase11<R(A&&, A&&, A&&, ...) const volatile &&, 3, Q_CV, /* RValue */ true>::run(); +#endif +}
\ No newline at end of file diff --git a/libcxx/test/std/utilities/function.objects/func.require/bullet_3_and_4.pass.cpp b/libcxx/test/std/utilities/function.objects/func.require/bullet_3_and_4.pass.cpp new file mode 100644 index 00000000000..b6fe190bd2a --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.require/bullet_3_and_4.pass.cpp @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <functional> + +// INVOKE (f, t1, t2, ..., tN) + +//------------------------------------------------------------------------------ +// TESTING INVOKE(f, t1, t2, ..., tN) +// - Bullet 3 -- t1.*f +// - Bullet 4 -- (*t1).*f +// +// Overview: +// Bullets 3 and 4 handle the case where 'f' is a pointer to member object. +// Bullet 3 only handles the cases where t1 is an object of type T or a +// type derived from 'T'. Bullet 4 handles all other cases. +// +// Concerns: +// 1) The return type is always an lvalue reference. +// 2) The return type is not less cv-qualified that the object that contains it. +// 3) The return type is not less cv-qualified than object type. +// 4) The call object is perfectly forwarded. +// 5) Classes that are publicly derived from 'T' are accepted as the call object +// 6) All types that dereference to T or a type derived from T can be used +// as the call object. +// 7) Pointers to T or a type derived from T can be used as the call object. + +#include <functional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "invoke_helpers.h" + +template <class Tp> +struct TestMemberObject { + TestMemberObject() : object() {} + Tp object; +private: + TestMemberObject(TestMemberObject const&); + TestMemberObject& operator=(TestMemberObject const&); +}; + +template <class ObjectType> +struct TestCase { + public: + + static void run() { TestCase().doTest(); } + +private: + typedef TestMemberObject<ObjectType> TestType; + + //========================================================================== + // TEST DISPATCH + void doTest() { + typedef DerivedFromType<TestType> Derived; + TestType obj; + TestType* obj_ptr = &obj; + Derived der; + Derived* der_ptr = &der; + DerefToType<TestType> dref; + DerefPropType<TestType> dref2; + + { + typedef ObjectType (TestType::*MemPtr); + typedef ObjectType E; + MemPtr M = &TestType::object; + runTestDispatch<E>(M, obj, &obj.object); + runTestDispatch<E>(M, der, &der.object); + runTestDispatch<E>(M, dref2, &dref2.object.object); + runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object); + runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object); + runTestPointerDispatch<E>(M, dref, &dref.object.object); + } + { + typedef ObjectType const (TestType::*CMemPtr); + typedef ObjectType const E; + CMemPtr M = &TestType::object; + runTestDispatch<E>(M, obj, &obj.object); + runTestDispatch<E>(M, der, &der.object); + runTestDispatch<E>(M, dref2, &dref2.object.object); + runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object); + runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object); + runTestPointerDispatch<E>(M, dref, &dref.object.object); + } + { + typedef ObjectType volatile (TestType::*VMemPtr); + typedef ObjectType volatile E; + VMemPtr M = &TestType::object; + runTestDispatch<E>(M, obj, &obj.object); + runTestDispatch<E>(M, der, &der.object); + runTestDispatch<E>(M, dref2, &dref2.object.object); + runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object); + runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object); + runTestPointerDispatch<E>(M, dref, &dref.object.object); + } + { + typedef ObjectType const volatile (TestType::*CVMemPtr); + typedef ObjectType const volatile E; + CVMemPtr M = &TestType::object; + runTestDispatch<E>(M, obj, &obj.object); + runTestDispatch<E>(M, der, &der.object); + runTestDispatch<E>(M, dref2, &dref2.object.object); + runTestPointerDispatch<E>(M, obj_ptr, &obj_ptr->object); + runTestPointerDispatch<E>(M, der_ptr, &der_ptr->object); + runTestPointerDispatch<E>(M, dref, &dref.object.object); + } + } + + template <class Expect, class Fn, class T> + void runTestDispatch(Fn M, T& obj, ObjectType* expect) { + runTest<Expect &> (M, C_<T&>(obj), expect); + runTest<Expect const&> (M, C_<T const&>(obj), expect); + runTest<Expect volatile&> (M, C_<T volatile&>(obj), expect); + runTest<Expect const volatile&>(M, C_<T const volatile&>(obj), expect); +#if TEST_STD_VER >= 11 + runTest<Expect&&> (M, C_<T&&>(obj), expect); + runTest<Expect const&&> (M, C_<T const&&>(obj), expect); + runTest<Expect volatile&&> (M, C_<T volatile&&>(obj), expect); + runTest<Expect const volatile&&>(M, C_<T const volatile&&>(obj), expect); +#endif + } + + template <class Expect, class Fn, class T> + void runTestPointerDispatch(Fn M, T& obj, ObjectType* expect) { + runTest<Expect&>(M, C_<T &>(obj), expect); + runTest<Expect&>(M, C_<T const&>(obj), expect); + runTest<Expect&>(M, C_<T volatile&>(obj), expect); + runTest<Expect&>(M, C_<T const volatile&>(obj), expect); +#if TEST_STD_VER >= 11 + runTest<Expect&>(M, C_<T&&>(obj), expect); + runTest<Expect&>(M, C_<T const&&>(obj), expect); + runTest<Expect&>(M, C_<T volatile&&>(obj), expect); + runTest<Expect&>(M, C_<T const volatile&&>(obj), expect); +#endif + } + + template <class Expect, class Fn, class T> +#if TEST_STD_VER >= 11 + void runTest(Fn M, T&& obj, ObjectType* expect) { +#else + void runTest(Fn M, T& obj, ObjectType* expect ) { +#endif + static_assert((std::is_same< + decltype(std::__invoke(M, std::forward<T>(obj))), Expect + >::value), ""); + Expect e = std::__invoke(M, std::forward<T>(obj)); + assert(&e == expect); + } +}; + +int main() { + TestCase<ArgType>::run(); + TestCase<ArgType const>::run(); + TestCase<ArgType volatile>::run(); + TestCase<ArgType const volatile>::run(); + TestCase<ArgType*>::run(); +}
\ No newline at end of file diff --git a/libcxx/test/std/utilities/function.objects/func.require/bullet_5.pass.cpp b/libcxx/test/std/utilities/function.objects/func.require/bullet_5.pass.cpp new file mode 100644 index 00000000000..3f3c96a9b9b --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.require/bullet_5.pass.cpp @@ -0,0 +1,327 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <functional> + +// INVOKE (f, t1, t2, ..., tN) + +//------------------------------------------------------------------------------ +// TESTING INVOKE(f, t1, t2, ..., tN) +// - Bullet 5 -- f(t2, ..., tN) +// +// Overview: +// Bullet 5 handles the cases where the first argument is not a member +// function. +// +// Concerns: +// 1) Different types of callable objects are supported. Including +// 1a) Free Function pointers and references. +// 1b) Classes which provide a call operator +// 1c) lambdas +// 2) The callable objects are perfect forwarded. +// 3) The arguments are perfect forwarded. +// 4) Signatures which include varargs are supported. +// 5) In C++03 3 extra arguments should be allowed. +// +// Plan: +// 1) Define a set of free functions, 'SF', and class types with call +// operators, 'SC', that address concerns 4 and 5. The free functions should +// return 'FunctionID::setUncheckedCall()' and the call operators should +// return 'MethodID::setUncheckedCall()'. +// +// 2) For each function 'f' in 'SF' and 'SC' attempt to call 'f' +// using the correct number of arguments and cv-ref qualifiers. Check that +// 'f' has been called using 'FunctionID::checkCall()' if 'f' is a free +// function and 'MethodID::checkCall()' otherwise. + + + +#include <functional> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" +#include "invoke_helpers.h" + + +//============================================================================== +// freeFunction03 - A C++03 free function. +void*& freeFunction03() { + return FunctionPtrID<void*&(), freeFunction03>::setUncheckedCall(); +} + +void*& freeFunction03(...) { + return FunctionPtrID<void*&(...), freeFunction03>::setUncheckedCall(); +} + +template <class A0> +void*& freeFunction03(A0&) { + return FunctionPtrID<void*&(A0&), freeFunction03>::setUncheckedCall(); +} + + +template <class A0> +void*& freeFunction03(A0&, ...) { + return FunctionPtrID<void*&(A0&, ...), freeFunction03>::setUncheckedCall(); +} + +template <class A0, class A1> +void*& freeFunction03(A0&, A1&) { + return FunctionPtrID<void*&(A0&, A1&), freeFunction03>::setUncheckedCall(); +} + + +template <class A0, class A1> +void*& freeFunction03(A0&, A1&, ...) { + return FunctionPtrID<void*&(A0&, A1&, ...), freeFunction03>::setUncheckedCall(); +} + +template <class A0, class A1, class A2> +void*& freeFunction03(A0&, A1&, A2&) { + return FunctionPtrID<void*&(A0&, A1&, A2&), freeFunction03>::setUncheckedCall(); +} + +template <class A0, class A1, class A2> +void*& freeFunction03(A0&, A1&, A2&, ...) { + return FunctionPtrID<void*&(A0&, A1&, A2&, ...), freeFunction03>::setUncheckedCall(); +} + +//============================================================================== +// Functor03 - C++03 compatible functor object +struct Functor03 { + typedef void*& R; + typedef Functor03 C; +#define F(Args, ...) \ + __VA_ARGS__ R operator() Args { return MethodID<R(C::*) Args>::setUncheckedCall(); } \ + __VA_ARGS__ R operator() Args const { return MethodID<R(C::*) Args const>::setUncheckedCall(); } \ + __VA_ARGS__ R operator() Args volatile { return MethodID<R(C::*) Args volatile>::setUncheckedCall(); } \ + __VA_ARGS__ R operator() Args const volatile { return MethodID<R(C::*) Args const volatile>::setUncheckedCall(); } +# + F(()) + F((A0&), template <class A0>) + F((A0&, A1&), template <class A0, class A1>) + F((A0&, A1&, A2&), template <class A0, class A1, class A2>) +#undef F +public: + Functor03() {} +private: + Functor03(Functor03 const&); + Functor03& operator=(Functor03 const&); +}; + + +#if TEST_STD_VER >= 11 + +//============================================================================== +// freeFunction11 - A C++11 free function. +template <class ...Args> +void*& freeFunction11(Args&&...) { + return FunctionPtrID<void*&(Args&&...), freeFunction11>::setUncheckedCall(); +} + +template <class ...Args> +void*& freeFunction11(Args&&...,...) { + return FunctionPtrID<void*&(Args&&...,...), freeFunction11>::setUncheckedCall(); +} + +//============================================================================== +// Functor11 - C++11 reference qualified test member functions. +struct Functor11 { + typedef void*& R; + typedef Functor11 C; + +#define F(CV) \ + template <class ...Args> \ + R operator()(Args&&...) CV { return MethodID<R(C::*)(Args&&...) CV>::setUncheckedCall(); } +# + F(&) + F(const &) + F(volatile &) + F(const volatile &) + F(&&) + F(const &&) + F(volatile &&) + F(const volatile &&) +#undef F +public: + Functor11() {} +private: + Functor11(Functor11 const&); + Functor11& operator=(Functor11 const&); +}; + +#endif // TEST_STD_VER >= 11 + + +//============================================================================== +// TestCaseFunctorImp - A test case for an operator() class method. +// ClassType - The type of the call object. +// CallSig - The function signature of the call operator being tested. +// Arity - the arity of 'CallSig' +// ObjCaster - Transformation function applied to call object. +// ArgCaster - Transformation function applied to the extra arguments. +template <class ClassType, class CallSig, int Arity, + class ObjCaster, class ArgCaster = LValueCaster> +struct TestCaseFunctorImp { +public: + static void run() { + typedef MethodID<CallSig ClassType::*> MID; + BasicTest<MID, Arity, ObjCaster, ArgCaster> t; + typedef ClassType T; + typedef DerivedFromType<T> D; + T obj; + D der; + t.runTest(obj); + t.runTest(der); + } +}; + +//============================================================================== +// TestCaseFreeFunction - A test case for a free function. +// CallSig - The function signature of the free function being tested. +// FnPtr - The function being tested. +// Arity - the arity of 'CallSig' +// ArgCaster - Transformation function to be applied to the extra arguments. +template <class CallSig, CallSig* FnPtr, int Arity, class ArgCaster> +struct TestCaseFreeFunction { +public: + static void run() { + typedef FunctionPtrID<CallSig, FnPtr> FID; + BasicTest<FID, Arity, LValueCaster, ArgCaster> t; + + DerefToType<CallSig*> deref_to(FnPtr); + DerefToType<CallSig&> deref_to_ref(*FnPtr); + + t.runTest(FnPtr); + t.runTest(*FnPtr); + t.runTest(deref_to); + t.runTest(deref_to_ref); + } +}; + +//============================================================================== +// runTest Helpers +//============================================================================== +#if TEST_STD_VER >= 11 +template <class Sig, int Arity, class ArgCaster> +void runFunctionTestCase11() { + TestCaseFreeFunction<Sig, freeFunction11, Arity, ArgCaster>(); +} +#endif + +template <class Sig, int Arity, class ArgCaster> +void runFunctionTestCase() { + TestCaseFreeFunction<Sig, freeFunction03, Arity, ArgCaster>(); +#if TEST_STD_VER >= 11 + runFunctionTestCase11<Sig, Arity, ArgCaster>(); +#endif +} + +template <class Sig, int Arity, class ObjCaster, class ArgCaster> +void runFunctorTestCase() { + TestCaseFunctorImp<Functor03, Sig, Arity, ObjCaster, ArgCaster>::run(); +} + +template <class Sig, int Arity, class ObjCaster> +void runFunctorTestCase() { + TestCaseFunctorImp<Functor03, Sig, Arity, ObjCaster>::run(); +} + +#if TEST_STD_VER >= 11 +// runTestCase - Run a test case for C++11 class functor types +template <class Sig, int Arity, class ObjCaster, class ArgCaster = LValueCaster> +void runFunctorTestCase11() { + TestCaseFunctorImp<Functor11, Sig, Arity, ObjCaster, ArgCaster>::run(); +} +#endif + +// runTestCase - Run a test case for both function and functor types. +template <class Sig, int Arity, class ArgCaster> +void runTestCase() { + runFunctionTestCase<Sig, Arity, ArgCaster>(); + runFunctorTestCase <Sig, Arity, LValueCaster, ArgCaster>(); +}; + +int main() { + typedef void*& R; + typedef ArgType A; + typedef A const CA; + + runTestCase< R(), 0, LValueCaster >(); + runTestCase< R(A&), 1, LValueCaster >(); + runTestCase< R(A&, A&), 2, LValueCaster >(); + runTestCase< R(A&, A&, A&), 3, LValueCaster >(); + runTestCase< R(CA&), 1, ConstCaster >(); + runTestCase< R(CA&, CA&), 2, ConstCaster >(); + runTestCase< R(CA&, CA&, CA&), 3, ConstCaster >(); + + runFunctionTestCase<R(...), 0, LValueCaster >(); + runFunctionTestCase<R(A&, ...), 1, LValueCaster >(); + runFunctionTestCase<R(A&, A&, ...), 2, LValueCaster >(); + runFunctionTestCase<R(A&, A&, A&, ...), 3, LValueCaster >(); + +#if TEST_STD_VER >= 11 + runFunctionTestCase11<R(A&&), 1, MoveCaster >(); + runFunctionTestCase11<R(A&&, ...), 1, MoveCaster >(); +#endif + + runFunctorTestCase<R(), 0, LValueCaster >(); + runFunctorTestCase<R() const, 0, ConstCaster >(); + runFunctorTestCase<R() volatile, 0, VolatileCaster >(); + runFunctorTestCase<R() const volatile, 0, CVCaster >(); + runFunctorTestCase<R(A&), 1, LValueCaster >(); + runFunctorTestCase<R(A&) const, 1, ConstCaster >(); + runFunctorTestCase<R(A&) volatile, 1, VolatileCaster >(); + runFunctorTestCase<R(A&) const volatile, 1, CVCaster >(); + runFunctorTestCase<R(A&, A&), 2, LValueCaster >(); + runFunctorTestCase<R(A&, A&) const, 2, ConstCaster >(); + runFunctorTestCase<R(A&, A&) volatile, 2, VolatileCaster >(); + runFunctorTestCase<R(A&, A&) const volatile, 2, CVCaster >(); + runFunctorTestCase<R(A&, A&, A&), 3, LValueCaster >(); + runFunctorTestCase<R(A&, A&, A&) const, 3, ConstCaster >(); + runFunctorTestCase<R(A&, A&, A&) volatile, 3, VolatileCaster >(); + runFunctorTestCase<R(A&, A&, A&) const volatile, 3, CVCaster >(); + { + typedef ConstCaster CC; + runFunctorTestCase<R(CA&), 1, LValueCaster, CC>(); + runFunctorTestCase<R(CA&) const, 1, ConstCaster, CC>(); + runFunctorTestCase<R(CA&) volatile, 1, VolatileCaster, CC>(); + runFunctorTestCase<R(CA&) const volatile, 1, CVCaster, CC>(); + runFunctorTestCase<R(CA&, CA&), 2, LValueCaster, CC>(); + runFunctorTestCase<R(CA&, CA&) const, 2, ConstCaster, CC>(); + runFunctorTestCase<R(CA&, CA&) volatile, 2, VolatileCaster, CC>(); + runFunctorTestCase<R(CA&, CA&) const volatile, 2, CVCaster, CC>(); + runFunctorTestCase<R(CA&, CA&, CA&), 3, LValueCaster, CC>(); + runFunctorTestCase<R(CA&, CA&, CA&) const, 3, ConstCaster, CC>(); + runFunctorTestCase<R(CA&, CA&, CA&) volatile, 3, VolatileCaster, CC>(); + runFunctorTestCase<R(CA&, CA&, CA&) const volatile, 3, CVCaster, CC>(); + } + +#if TEST_STD_VER >= 11 + runFunctorTestCase11<R() &, 0, LValueCaster >(); + runFunctorTestCase11<R() const &, 0, ConstCaster >(); + runFunctorTestCase11<R() volatile &, 0, VolatileCaster >(); + runFunctorTestCase11<R() const volatile &, 0, CVCaster >(); + runFunctorTestCase11<R() &&, 0, MoveCaster >(); + runFunctorTestCase11<R() const &&, 0, MoveConstCaster >(); + runFunctorTestCase11<R() volatile &&, 0, MoveVolatileCaster >(); + runFunctorTestCase11<R() const volatile &&, 0, MoveCVCaster >(); + { + typedef MoveCaster MC; + runFunctorTestCase11<R(A&&) &, 1, LValueCaster, MC>(); + runFunctorTestCase11<R(A&&) const &, 1, ConstCaster, MC>(); + runFunctorTestCase11<R(A&&) volatile &, 1, VolatileCaster, MC>(); + runFunctorTestCase11<R(A&&) const volatile &, 1, CVCaster, MC>(); + runFunctorTestCase11<R(A&&) &&, 1, MoveCaster, MC>(); + runFunctorTestCase11<R(A&&) const &&, 1, MoveConstCaster, MC>(); + runFunctorTestCase11<R(A&&) volatile &&, 1, MoveVolatileCaster, MC>(); + runFunctorTestCase11<R(A&&) const volatile &&, 1, MoveCVCaster, MC>(); + } +#endif +} diff --git a/libcxx/test/std/utilities/function.objects/func.require/invoke_helpers.h b/libcxx/test/std/utilities/function.objects/func.require/invoke_helpers.h new file mode 100644 index 00000000000..0583b624da3 --- /dev/null +++ b/libcxx/test/std/utilities/function.objects/func.require/invoke_helpers.h @@ -0,0 +1,317 @@ +#ifndef INVOKE_HELPERS_H +#define INVOKE_HELPERS_H + +#include <type_traits> +#include <cassert> +#include <functional> + +#include "test_macros.h" + +template <int I> +struct Int : public std::integral_constant<int, I> {}; + +template <bool P> +struct Bool : public std::integral_constant<bool, P> {}; + +struct Q_None { + template <class T> + struct apply { typedef T type; }; +}; + +struct Q_Const { + template <class T> + struct apply { typedef T const type; }; +}; + +struct Q_Volatile { + template <class T> + struct apply { typedef T volatile type; }; +}; + +struct Q_CV { + template <class T> + struct apply { typedef T const volatile type; }; +}; + +// Caster - A functor object that performs cv-qualifier and value category +// conversions. +// QualTag - A metafunction type that applies cv-qualifiers to its argument. +// RValue - True if the resulting object should be an RValue reference. +// False otherwise. +template <class QualTag, bool RValue = false> +struct Caster { + template <class T> + struct apply { + typedef typename std::remove_reference<T>::type RawType; + typedef typename QualTag::template apply<RawType>::type CVType; +#if TEST_STD_VER >= 11 + typedef typename std::conditional<RValue, + CVType&&, CVType& + >::type type; +#else + typedef CVType& type; +#endif + }; + + template <class T> + typename apply<T>::type + operator()(T& obj) const { + typedef typename apply<T>::type OutType; + return static_cast<OutType>(obj); + } +}; + +typedef Caster<Q_None> LValueCaster; +typedef Caster<Q_Const> ConstCaster; +typedef Caster<Q_Volatile> VolatileCaster; +typedef Caster<Q_CV> CVCaster; +typedef Caster<Q_None, true> MoveCaster; +typedef Caster<Q_Const, true> MoveConstCaster; +typedef Caster<Q_Volatile, true> MoveVolatileCaster; +typedef Caster<Q_CV, true> MoveCVCaster; + +// A shorter name for 'static_cast' +template <class QualType, class Tp> +QualType C_(Tp& v) { return static_cast<QualType>(v); }; + +//============================================================================== +// ArgType - A non-copyable type intended to be used as a dummy argument type +// to test functions. +struct ArgType { + int value; + explicit ArgType(int val = 0) : value(val) {} +private: + ArgType(ArgType const&); + ArgType& operator=(ArgType const&); +}; + +//============================================================================== +// DerivedFromBase - A type that derives from it's template argument 'Base' +template <class Base> +struct DerivedFromType : public Base { + DerivedFromType() : Base() {} + template <class Tp> + explicit DerivedFromType(Tp const& t) : Base(t) {} +}; + +//============================================================================== +// DerefToType - A type that dereferences to it's template argument 'To'. +// The cv-ref qualifiers of the 'DerefToType' object do not propagate +// to the resulting 'To' object. +template <class To> +struct DerefToType { + To object; + + DerefToType() {} + + template <class Up> + explicit DerefToType(Up const& val) : object(val) {} + + To& operator*() const volatile { return const_cast<To&>(object); } +}; + +//============================================================================== +// DerefPropToType - A type that dereferences to it's template argument 'To'. +// The cv-ref qualifiers of the 'DerefPropToType' object propagate +// to the resulting 'To' object. +template <class To> +struct DerefPropType { + To object; + + DerefPropType() {} + + template <class Up> + explicit DerefPropType(Up const& val) : object(val) {} + +#if TEST_STD_VER < 11 + To& operator*() { return object; } + To const& operator*() const { return object; } + To volatile& operator*() volatile { return object; } + To const volatile& operator*() const volatile { return object; } +#else + To& operator*() & { return object; } + To const& operator*() const & { return object; } + To volatile& operator*() volatile & { return object; } + To const volatile& operator*() const volatile & { return object; } + To&& operator*() && { return static_cast<To &&>(object); } + To const&& operator*() const && { return static_cast<To const&&>(object); } + To volatile&& operator*() volatile && { return static_cast<To volatile&&>(object); } + To const volatile&& operator*() const volatile && { return static_cast<To const volatile&&>(object); } +#endif +}; + +//============================================================================== +// MethodID - A type that uniquely identifies a member function for a class. +// This type is used to communicate between the member functions being tested +// and the tests invoking them. +// - Test methods should call 'setUncheckedCall()' whenever they are invoked. +// - Tests consume the unchecked call using checkCall(<return-value>)` to assert +// that the method has been called and that the return value of `__invoke` +// matches what the method actually returned. +template <class T> +struct MethodID { + typedef void* IDType; + + static int dummy; // A dummy memory location. + static void* id; // The "ID" is the value of this pointer. + static bool unchecked_call; // Has a call happened that has not been checked. + + static void*& setUncheckedCall() { + assert(unchecked_call == false); + unchecked_call = true; + return id; + } + + static bool checkCalled(void*& return_value) { + bool old = unchecked_call; + unchecked_call = false; + return old && id == return_value && &id == &return_value; + } +}; + +template <class T> int MethodID<T>::dummy = 0; +template <class T> void* MethodID<T>::id = (void*)&MethodID<T>::dummy; +template <class T> bool MethodID<T>::unchecked_call = false; + + +//============================================================================== +// FunctionPtrID - Like MethodID but for free function pointers. +template <class T, T*> +struct FunctionPtrID { + static int dummy; // A dummy memory location. + static void* id; // The "ID" is the value of this pointer. + static bool unchecked_call; // Has a call happened that has not been checked. + + static void*& setUncheckedCall() { + assert(unchecked_call == false); + unchecked_call = true; + return id; + } + + static bool checkCalled(void*& return_value) { + bool old = unchecked_call; + unchecked_call = false; + return old && id == return_value && &id == &return_value; + } +}; + +template <class T, T* Ptr> int FunctionPtrID<T, Ptr>::dummy = 0; +template <class T, T* Ptr> void* FunctionPtrID<T, Ptr>::id = (void*)&FunctionPtrID<T, Ptr>::dummy; +template <class T, T* Ptr> bool FunctionPtrID<T, Ptr>::unchecked_call = false; + +//============================================================================== +// BasicTest - The basic test structure for everything except +// member object pointers. +// ID - The "Function Identifier" type used either MethodID or FunctionPtrID. +// Arity - The Arity of the call signature. +// ObjectCaster - The object transformation functor type. +// ArgCaster - The extra argument transformation functor type. +template <class ID, int Arity, class ObjectCaster = LValueCaster, + class ArgCaster = LValueCaster> +struct BasicTest { + template <class ObjectT> + void runTest(ObjectT& object) { + Int<Arity> A; + runTestImp(A, object); + } + + template <class MethodPtr, class ObjectT> + void runTest(MethodPtr ptr, ObjectT& object) { + Int<Arity> A; + runTestImp(A, ptr, object); + } + +private: + typedef void*& CallRet; + ObjectCaster object_cast; + ArgCaster arg_cast; + ArgType a0, a1, a2; + + //========================================================================== + // BULLET 1 AND 2 TEST METHODS + //========================================================================== + template <class MethodPtr, class ObjectT> + void runTestImp(Int<0>, MethodPtr ptr, ObjectT& object) { + static_assert((std::is_same< + decltype(std::__invoke(ptr, object_cast(object))) + , CallRet>::value), ""); + assert(ID::unchecked_call == false); + CallRet ret = std::__invoke(ptr, object_cast(object)); + assert(ID::checkCalled(ret)); + } + + template <class MethodPtr, class ObjectT> + void runTestImp(Int<1>, MethodPtr ptr, ObjectT& object) { + static_assert((std::is_same< + decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0))) + , CallRet>::value), ""); + assert(ID::unchecked_call == false); + CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0)); + assert(ID::checkCalled(ret)); + } + + template <class MethodPtr, class ObjectT> + void runTestImp(Int<2>, MethodPtr ptr, ObjectT& object) { + static_assert((std::is_same< + decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1))) + , CallRet>::value), ""); + assert(ID::unchecked_call == false); + CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1)); + assert(ID::checkCalled(ret)); + } + + template <class MethodPtr, class ObjectT> + void runTestImp(Int<3>, MethodPtr ptr, ObjectT& object) { + static_assert((std::is_same< + decltype(std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2))) + , CallRet>::value), ""); + assert(ID::unchecked_call == false); + CallRet ret = std::__invoke(ptr, object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)); + assert(ID::checkCalled(ret)); + } + + //========================================================================== + // BULLET 5 TEST METHODS + //========================================================================== + template <class ObjectT> + void runTestImp(Int<0>, ObjectT& object) { + static_assert((std::is_same< + decltype(std::__invoke(object_cast(object))) + , CallRet>::value), ""); + assert(ID::unchecked_call == false); + CallRet ret = std::__invoke(object_cast(object)); + assert(ID::checkCalled(ret)); + } + + template <class ObjectT> + void runTestImp(Int<1>, ObjectT& object) { + static_assert((std::is_same< + decltype(std::__invoke(object_cast(object), arg_cast(a0))) + , CallRet>::value), ""); + assert(ID::unchecked_call == false); + CallRet ret = std::__invoke(object_cast(object), arg_cast(a0)); + assert(ID::checkCalled(ret)); + } + + template <class ObjectT> + void runTestImp(Int<2>, ObjectT& object) { + static_assert((std::is_same< + decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1))) + , CallRet>::value), ""); + assert(ID::unchecked_call == false); + CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1)); + assert(ID::checkCalled(ret)); + } + + template <class ObjectT> + void runTestImp(Int<3>, ObjectT& object) { + static_assert((std::is_same< + decltype(std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2))) + , CallRet>::value), ""); + assert(ID::unchecked_call == false); + CallRet ret = std::__invoke(object_cast(object), arg_cast(a0), arg_cast(a1), arg_cast(a2)); + assert(ID::checkCalled(ret)); + } +}; + +#endif // INVOKE_HELPERS_H |