mirror of
https://github.com/llvm-mirror/libcxx.git
synced 2025-10-23 01:18:52 +08:00

The primary purpose of this patch is to add the 'is_callable' traits. Since 'is_nothrow_callable' required making 'INVOKE' conditionally noexcept I also took this oppertunity to implement a constexpr version of INVOKE. This fixes 'std::experimental::apply' which required constexpr 'INVOKE support'. This patch will be followed up with some cleanup. Primarly removing most of "__member_function_traits" since it's no longer used by INVOKE (in C++11 at least). git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@266836 91177308-0d34-0410-b5e6-96231b3b80d8
370 lines
16 KiB
C++
370 lines
16 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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.get().*f)(t2, ..., tN) // t1 is a reference_wrapper
|
|
// - Bullet 3 -- ((*t1).*f)(t2, ..., tN)
|
|
//
|
|
// Overview:
|
|
// Bullets 1, 2 and 3 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 the case where 't1' is a reference
|
|
// wrapper and bullet 3 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.
|
|
// 9) reference_wrappers are properly handled and unwrapped.
|
|
//
|
|
//
|
|
// 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;
|
|
std::reference_wrapper<T> rref(obj);
|
|
std::reference_wrapper<D> drref(der);
|
|
|
|
// (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);
|
|
#if TEST_STD_VER >= 11
|
|
runTestDispatchIf(NotRValue, tag, rref);
|
|
runTestDispatchIf(NotRValue, tag, drref);
|
|
#endif
|
|
}
|
|
|
|
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) {
|
|
runTest(v);
|
|
runTest(makeConst(v));
|
|
}
|
|
|
|
template <class Tp>
|
|
void runTestDispatch(Q_Volatile, Tp& v) {
|
|
runTest(v);
|
|
runTest(makeVolatile(v));
|
|
|
|
}
|
|
|
|
template <class Tp>
|
|
void runTestDispatch(Q_CV, Tp& v) {
|
|
runTest(v);
|
|
runTest(makeConst(v));
|
|
runTest(makeVolatile(v));
|
|
runTest(makeCV(v));
|
|
}
|
|
|
|
template <class T>
|
|
void runTest(const std::reference_wrapper<T>& 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 T>
|
|
void runTest(T* 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 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
|
|
|
|
template <class Tp>
|
|
struct DerivedFromRefWrap : public std::reference_wrapper<Tp> {
|
|
DerivedFromRefWrap(Tp& tp) : std::reference_wrapper<Tp>(tp) {}
|
|
};
|
|
|
|
#if TEST_STD_VER >= 11
|
|
void test_derived_from_ref_wrap() {
|
|
int x = 42;
|
|
std::reference_wrapper<int> r(x);
|
|
std::reference_wrapper<std::reference_wrapper<int>> r2(r);
|
|
DerivedFromRefWrap<int> d(x);
|
|
auto get_fn = &std::reference_wrapper<int>::get;
|
|
auto& ret = std::__invoke(get_fn, r);
|
|
auto& cret = std::__invoke_constexpr(get_fn, r);
|
|
assert(&ret == &x);
|
|
assert(&cret == &x);
|
|
auto& ret2 = std::__invoke(get_fn, d);
|
|
auto& cret2 = std::__invoke_constexpr(get_fn, d);
|
|
assert(&ret2 == &x);
|
|
auto& ret3 = std::__invoke(get_fn, r2);
|
|
assert(&ret3 == &x);
|
|
}
|
|
#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();
|
|
|
|
test_derived_from_ref_wrap();
|
|
#endif
|
|
} |