242 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// <functional>10 11// INVOKE (f, t1, t2, ..., tN)12 13//------------------------------------------------------------------------------14// TESTING INVOKE(f, t1, t2, ..., tN)15// - Bullet 1 -- (t1.*f)(t2, ..., tN)16// - Bullet 2 -- (t1.get().*f)(t2, ..., tN) // t1 is a reference_wrapper17// - Bullet 3 -- ((*t1).*f)(t2, ..., tN)18//19// Overview:20// Bullets 1, 2 and 3 handle the case where 'f' is a pointer to member function.21// Bullet 1 only handles the cases where t1 is an object of type T or a22// type derived from 'T'. Bullet 2 handles the case where 't1' is a reference23// wrapper and bullet 3 handles all other cases.24//25// Concerns:26// 1) cv-qualified member function signatures are accepted.27// 2) reference qualified member function signatures are accepted.28// 3) member functions with varargs at the end are accepted.29// 4) The arguments are perfect forwarded to the member function call.30// 5) Classes that are publicly derived from 'T' are accepted as the call object31// 6) All types that dereference to T or a type derived from T can be used32// as the call object.33// 7) Pointers to T or a type derived from T can be used as the call object.34// 8) Reference return types are properly deduced.35// 9) reference_wrappers are properly handled and unwrapped.36//37//38// Plan:39// 1) Create a class that contains a set, 'S', of non-static functions.40// 'S' should include functions that cover every single combination41// of qualifiers and varargs for arities of 0, 1 and 2 (C-1,2,3).42// The argument types used in the functions should be non-copyable (C-4).43// The functions should return 'MethodID::setUncheckedCall()'.44//45// 2) Create a set of supported call object, 'Objs', of different types46// and behaviors. (C-5,6,7)47//48// 3) Attempt to call each function, 'f', in 'S' with each call object, 'c',49// in 'Objs'. After every attempted call to 'f' check that 'f' was50// actually called using 'MethodID::checkCalled(<return-value>)'51//52// 3b) If 'f' is reference qualified call 'f' with the properly qualified53// call object. Otherwise call 'f' with lvalue call objects.54//55// 3a) If 'f' is const, volatile, or cv qualified then call it with call56// objects that are equally or less cv-qualified.57 58#include <functional>59#include <cassert>60#include <type_traits>61#include <utility>62 63#include "test_macros.h"64#include "invoke_helpers.h"65 66//==============================================================================67// MemFun03 - C++03 compatible set of test member functions.68struct MemFun03 {69 typedef void*& R;70#define F(...) \71 R f(__VA_ARGS__) { return MethodID<R(MemFun03::*)(__VA_ARGS__)>::setUncheckedCall(); } \72 R f(__VA_ARGS__) const { return MethodID<R(MemFun03::*)(__VA_ARGS__) const>::setUncheckedCall(); } \73 R f(__VA_ARGS__) volatile { return MethodID<R(MemFun03::*)(__VA_ARGS__) volatile>::setUncheckedCall(); } \74 R f(__VA_ARGS__) const volatile { return MethodID<R(MemFun03::*)(__VA_ARGS__) const volatile>::setUncheckedCall(); }75#76 F()77 F(...)78 F(ArgType&)79 F(ArgType&, ...)80 F(ArgType&, ArgType&)81 F(ArgType&, ArgType&, ...)82 F(ArgType&, ArgType&, ArgType&)83 F(ArgType&, ArgType&, ArgType&, ...)84#undef F85public:86 MemFun03() {}87private:88 MemFun03(MemFun03 const&);89 MemFun03& operator=(MemFun03 const&);90};91 92 93//==============================================================================94// TestCase - A test case for a single member function.95// ClassType - The type of the class being tested.96// CallSig - The function signature of the method being tested.97// Arity - the arity of 'CallSig'98// CV - the cv qualifiers of 'CallSig' represented as a type tag.99// RValue - The method is RValue qualified.100// ArgRValue - Call the method with RValue arguments.101template <class ClassType, class CallSig, int Arity, class CV,102 bool RValue = false, bool ArgRValue = false>103struct TestCaseImp {104public:105 106 static void run() { TestCaseImp().doTest(); }107 108private:109 //==========================================================================110 // TEST DISPATCH111 void doTest() {112 // (Plan-2) Create test call objects.113 typedef ClassType T;114 typedef DerivedFromType<T> D;115 T obj;116 T* obj_ptr = &obj;117 D der;118 D* der_ptr = &der;119 DerefToType<T> dref;120 DerefPropType<T> dref2;121 std::reference_wrapper<T> rref(obj);122 std::reference_wrapper<D> drref(der);123 124 // (Plan-3) Dispatch based on the CV tags.125 CV tag;126 Bool<!RValue> NotRValue;127 runTestDispatch(tag, obj);128 runTestDispatch(tag, der);129 runTestDispatch(tag, dref2);130 runTestDispatchIf(NotRValue, tag, dref);131 runTestDispatchIf(NotRValue, tag, obj_ptr);132 runTestDispatchIf(NotRValue, tag, der_ptr);133 }134 135 template <class QT, class Tp>136 void runTestDispatchIf(Bool<true>, QT q, Tp& v) {137 runTestDispatch(q, v);138 }139 140 template <class QT, class Tp>141 void runTestDispatchIf(Bool<false>, QT, Tp&) {142 }143 144 template <class Tp>145 void runTestDispatch(Q_None, Tp& v) {146 runTest(v);147 }148 149 template <class Tp>150 void runTestDispatch(Q_Const, Tp& v) {151 runTest(v);152 runTest(makeConst(v));153 }154 155 template <class Tp>156 void runTestDispatch(Q_Volatile, Tp& v) {157 runTest(v);158 runTest(makeVolatile(v));159 160 }161 162 template <class Tp>163 void runTestDispatch(Q_CV, Tp& v) {164 runTest(v);165 runTest(makeConst(v));166 runTest(makeVolatile(v));167 runTest(makeCV(v));168 }169 170 template <class T>171 void runTest(const std::reference_wrapper<T>& obj) {172 typedef Caster<Q_None, RValue> SCast;173 typedef Caster<Q_None, ArgRValue> ACast;174 typedef CallSig (ClassType::*MemPtr);175 // Delegate test to logic in invoke_helpers.h176 BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;177 b.runTest( (MemPtr)&ClassType::f, obj);178 }179 180 template <class T>181 void runTest(T* obj) {182 typedef Caster<Q_None, RValue> SCast;183 typedef Caster<Q_None, ArgRValue> ACast;184 typedef CallSig (ClassType::*MemPtr);185 // Delegate test to logic in invoke_helpers.h186 BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;187 b.runTest( (MemPtr)&ClassType::f, obj);188 }189 190 template <class Obj>191 void runTest(Obj& obj) {192 typedef Caster<Q_None, RValue> SCast;193 typedef Caster<Q_None, ArgRValue> ACast;194 typedef CallSig (ClassType::*MemPtr);195 // Delegate test to logic in invoke_helpers.h196 BasicTest<MethodID<MemPtr>, Arity, SCast, ACast> b;197 b.runTest( (MemPtr)&ClassType::f, obj);198 }199};200 201template <class Sig, int Arity, class CV>202struct TestCase : public TestCaseImp<MemFun03, Sig, Arity, CV> {};203 204int main(int, char**) {205 typedef void*& R;206 typedef ArgType A;207 TestCase<R(), 0, Q_None>::run();208 TestCase<R() const, 0, Q_Const>::run();209 TestCase<R() volatile, 0, Q_Volatile>::run();210 TestCase<R() const volatile, 0, Q_CV>::run();211 TestCase<R(...), 0, Q_None>::run();212 TestCase<R(...) const, 0, Q_Const>::run();213 TestCase<R(...) volatile, 0, Q_Volatile>::run();214 TestCase<R(...) const volatile, 0, Q_CV>::run();215 TestCase<R(A&), 1, Q_None>::run();216 TestCase<R(A&) const, 1, Q_Const>::run();217 TestCase<R(A&) volatile, 1, Q_Volatile>::run();218 TestCase<R(A&) const volatile, 1, Q_CV>::run();219 TestCase<R(A&, ...), 1, Q_None>::run();220 TestCase<R(A&, ...) const, 1, Q_Const>::run();221 TestCase<R(A&, ...) volatile, 1, Q_Volatile>::run();222 TestCase<R(A&, ...) const volatile, 1, Q_CV>::run();223 TestCase<R(A&, A&), 2, Q_None>::run();224 TestCase<R(A&, A&) const, 2, Q_Const>::run();225 TestCase<R(A&, A&) volatile, 2, Q_Volatile>::run();226 TestCase<R(A&, A&) const volatile, 2, Q_CV>::run();227 TestCase<R(A&, A&, ...), 2, Q_None>::run();228 TestCase<R(A&, A&, ...) const, 2, Q_Const>::run();229 TestCase<R(A&, A&, ...) volatile, 2, Q_Volatile>::run();230 TestCase<R(A&, A&, ...) const volatile, 2, Q_CV>::run();231 TestCase<R(A&, A&, A&), 3, Q_None>::run();232 TestCase<R(A&, A&, A&) const, 3, Q_Const>::run();233 TestCase<R(A&, A&, A&) volatile, 3, Q_Volatile>::run();234 TestCase<R(A&, A&, A&) const volatile, 3, Q_CV>::run();235 TestCase<R(A&, A&, A&, ...), 3, Q_None>::run();236 TestCase<R(A&, A&, A&, ...) const, 3, Q_Const>::run();237 TestCase<R(A&, A&, A&, ...) volatile, 3, Q_Volatile>::run();238 TestCase<R(A&, A&, A&, ...) const volatile, 3, Q_CV>::run();239 240 return 0;241}242