//===----------------------------------------------------------------------===// // // 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 }