1*03e29a29SEric Fiselier //===----------------------------------------------------------------------===// 2*03e29a29SEric Fiselier // 3*03e29a29SEric Fiselier // The LLVM Compiler Infrastructure 4*03e29a29SEric Fiselier // 5*03e29a29SEric Fiselier // This file is dual licensed under the MIT and the University of Illinois Open 6*03e29a29SEric Fiselier // Source Licenses. See LICENSE.TXT for details. 7*03e29a29SEric Fiselier // 8*03e29a29SEric Fiselier //===----------------------------------------------------------------------===// 9*03e29a29SEric Fiselier 10*03e29a29SEric Fiselier // UNSUPPORTED: c++98, c++03, c++11, c++14 11*03e29a29SEric Fiselier 12*03e29a29SEric Fiselier // <tuple> 13*03e29a29SEric Fiselier 14*03e29a29SEric Fiselier // template <class F, class T> constexpr decltype(auto) apply(F &&, T &&) 15*03e29a29SEric Fiselier 16*03e29a29SEric Fiselier // Test with different ref/ptr/cv qualified argument types. 17*03e29a29SEric Fiselier 18*03e29a29SEric Fiselier #include <tuple> 19*03e29a29SEric Fiselier #include <array> 20*03e29a29SEric Fiselier #include <utility> 21*03e29a29SEric Fiselier #include <cassert> 22*03e29a29SEric Fiselier 23*03e29a29SEric Fiselier #include "test_macros.h" 24*03e29a29SEric Fiselier #include "type_id.h" 25*03e29a29SEric Fiselier 26*03e29a29SEric Fiselier // std::array is explicitly allowed to be initialized with A a = { init-list };. 27*03e29a29SEric Fiselier // Disable the missing braces warning for this reason. 28*03e29a29SEric Fiselier #include "disable_missing_braces_warning.h" 29*03e29a29SEric Fiselier 30*03e29a29SEric Fiselier 31*03e29a29SEric Fiselier constexpr int constexpr_sum_fn() { return 0; } 32*03e29a29SEric Fiselier 33*03e29a29SEric Fiselier template <class ...Ints> 34*03e29a29SEric Fiselier constexpr int constexpr_sum_fn(int x1, Ints... rest) { return x1 + constexpr_sum_fn(rest...); } 35*03e29a29SEric Fiselier 36*03e29a29SEric Fiselier struct ConstexprSumT { 37*03e29a29SEric Fiselier constexpr ConstexprSumT() = default; 38*03e29a29SEric Fiselier template <class ...Ints> 39*03e29a29SEric Fiselier constexpr int operator()(Ints... values) const { 40*03e29a29SEric Fiselier return constexpr_sum_fn(values...); 41*03e29a29SEric Fiselier } 42*03e29a29SEric Fiselier }; 43*03e29a29SEric Fiselier 44*03e29a29SEric Fiselier 45*03e29a29SEric Fiselier void test_constexpr_evaluation() 46*03e29a29SEric Fiselier { 47*03e29a29SEric Fiselier constexpr ConstexprSumT sum_obj{}; 48*03e29a29SEric Fiselier { 49*03e29a29SEric Fiselier using Tup = std::tuple<>; 50*03e29a29SEric Fiselier using Fn = int(&)(); 51*03e29a29SEric Fiselier constexpr Tup t; 52*03e29a29SEric Fiselier static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 0, ""); 53*03e29a29SEric Fiselier static_assert(std::apply(sum_obj, t) == 0, ""); 54*03e29a29SEric Fiselier } 55*03e29a29SEric Fiselier { 56*03e29a29SEric Fiselier using Tup = std::tuple<int>; 57*03e29a29SEric Fiselier using Fn = int(&)(int); 58*03e29a29SEric Fiselier constexpr Tup t(42); 59*03e29a29SEric Fiselier static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 42, ""); 60*03e29a29SEric Fiselier static_assert(std::apply(sum_obj, t) == 42, ""); 61*03e29a29SEric Fiselier } 62*03e29a29SEric Fiselier { 63*03e29a29SEric Fiselier using Tup = std::tuple<int, long>; 64*03e29a29SEric Fiselier using Fn = int(&)(int, int); 65*03e29a29SEric Fiselier constexpr Tup t(42, 101); 66*03e29a29SEric Fiselier static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, ""); 67*03e29a29SEric Fiselier static_assert(std::apply(sum_obj, t) == 143, ""); 68*03e29a29SEric Fiselier } 69*03e29a29SEric Fiselier { 70*03e29a29SEric Fiselier using Tup = std::pair<int, long>; 71*03e29a29SEric Fiselier using Fn = int(&)(int, int); 72*03e29a29SEric Fiselier constexpr Tup t(42, 101); 73*03e29a29SEric Fiselier static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, ""); 74*03e29a29SEric Fiselier static_assert(std::apply(sum_obj, t) == 143, ""); 75*03e29a29SEric Fiselier } 76*03e29a29SEric Fiselier { 77*03e29a29SEric Fiselier using Tup = std::tuple<int, long, int>; 78*03e29a29SEric Fiselier using Fn = int(&)(int, int, int); 79*03e29a29SEric Fiselier constexpr Tup t(42, 101, -1); 80*03e29a29SEric Fiselier static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, ""); 81*03e29a29SEric Fiselier static_assert(std::apply(sum_obj, t) == 142, ""); 82*03e29a29SEric Fiselier } 83*03e29a29SEric Fiselier { 84*03e29a29SEric Fiselier using Tup = std::array<int, 3>; 85*03e29a29SEric Fiselier using Fn = int(&)(int, int, int); 86*03e29a29SEric Fiselier constexpr Tup t = {42, 101, -1}; 87*03e29a29SEric Fiselier static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, ""); 88*03e29a29SEric Fiselier static_assert(std::apply(sum_obj, t) == 142, ""); 89*03e29a29SEric Fiselier } 90*03e29a29SEric Fiselier } 91*03e29a29SEric Fiselier 92*03e29a29SEric Fiselier 93*03e29a29SEric Fiselier enum CallQuals { 94*03e29a29SEric Fiselier CQ_None, 95*03e29a29SEric Fiselier CQ_LValue, 96*03e29a29SEric Fiselier CQ_ConstLValue, 97*03e29a29SEric Fiselier CQ_RValue, 98*03e29a29SEric Fiselier CQ_ConstRValue 99*03e29a29SEric Fiselier }; 100*03e29a29SEric Fiselier 101*03e29a29SEric Fiselier template <class Tuple> 102*03e29a29SEric Fiselier struct CallInfo { 103*03e29a29SEric Fiselier CallQuals quals; 104*03e29a29SEric Fiselier TypeID const* arg_types; 105*03e29a29SEric Fiselier Tuple args; 106*03e29a29SEric Fiselier 107*03e29a29SEric Fiselier template <class ...Args> 108*03e29a29SEric Fiselier CallInfo(CallQuals q, Args&&... xargs) 109*03e29a29SEric Fiselier : quals(q), arg_types(&makeArgumentID<Args&&...>()), args(std::forward<Args>(xargs)...) 110*03e29a29SEric Fiselier {} 111*03e29a29SEric Fiselier }; 112*03e29a29SEric Fiselier 113*03e29a29SEric Fiselier template <class ...Args> 114*03e29a29SEric Fiselier inline CallInfo<decltype(std::forward_as_tuple(std::declval<Args>()...))> 115*03e29a29SEric Fiselier makeCallInfo(CallQuals quals, Args&&... args) { 116*03e29a29SEric Fiselier return {quals, std::forward<Args>(args)...}; 117*03e29a29SEric Fiselier } 118*03e29a29SEric Fiselier 119*03e29a29SEric Fiselier struct TrackedCallable { 120*03e29a29SEric Fiselier 121*03e29a29SEric Fiselier TrackedCallable() = default; 122*03e29a29SEric Fiselier 123*03e29a29SEric Fiselier template <class ...Args> auto operator()(Args&&... xargs) & 124*03e29a29SEric Fiselier { return makeCallInfo(CQ_LValue, std::forward<Args>(xargs)...); } 125*03e29a29SEric Fiselier 126*03e29a29SEric Fiselier template <class ...Args> auto operator()(Args&&... xargs) const& 127*03e29a29SEric Fiselier { return makeCallInfo(CQ_ConstLValue, std::forward<Args>(xargs)...); } 128*03e29a29SEric Fiselier 129*03e29a29SEric Fiselier template <class ...Args> auto operator()(Args&&... xargs) && 130*03e29a29SEric Fiselier { return makeCallInfo(CQ_RValue, std::forward<Args>(xargs)...); } 131*03e29a29SEric Fiselier 132*03e29a29SEric Fiselier template <class ...Args> auto operator()(Args&&... xargs) const&& 133*03e29a29SEric Fiselier { return makeCallInfo(CQ_ConstRValue, std::forward<Args>(xargs)...); } 134*03e29a29SEric Fiselier }; 135*03e29a29SEric Fiselier 136*03e29a29SEric Fiselier template <class ...ExpectArgs, class Tuple> 137*03e29a29SEric Fiselier void check_apply_quals_and_types(Tuple&& t) { 138*03e29a29SEric Fiselier TypeID const* const expect_args = &makeArgumentID<ExpectArgs...>(); 139*03e29a29SEric Fiselier TrackedCallable obj; 140*03e29a29SEric Fiselier TrackedCallable const& cobj = obj; 141*03e29a29SEric Fiselier { 142*03e29a29SEric Fiselier auto ret = std::apply(obj, std::forward<Tuple>(t)); 143*03e29a29SEric Fiselier assert(ret.quals == CQ_LValue); 144*03e29a29SEric Fiselier assert(ret.arg_types == expect_args); 145*03e29a29SEric Fiselier assert(ret.args == t); 146*03e29a29SEric Fiselier } 147*03e29a29SEric Fiselier { 148*03e29a29SEric Fiselier auto ret = std::apply(cobj, std::forward<Tuple>(t)); 149*03e29a29SEric Fiselier assert(ret.quals == CQ_ConstLValue); 150*03e29a29SEric Fiselier assert(ret.arg_types == expect_args); 151*03e29a29SEric Fiselier assert(ret.args == t); 152*03e29a29SEric Fiselier } 153*03e29a29SEric Fiselier { 154*03e29a29SEric Fiselier auto ret = std::apply(std::move(obj), std::forward<Tuple>(t)); 155*03e29a29SEric Fiselier assert(ret.quals == CQ_RValue); 156*03e29a29SEric Fiselier assert(ret.arg_types == expect_args); 157*03e29a29SEric Fiselier assert(ret.args == t); 158*03e29a29SEric Fiselier } 159*03e29a29SEric Fiselier { 160*03e29a29SEric Fiselier auto ret = std::apply(std::move(cobj), std::forward<Tuple>(t)); 161*03e29a29SEric Fiselier assert(ret.quals == CQ_ConstRValue); 162*03e29a29SEric Fiselier assert(ret.arg_types == expect_args); 163*03e29a29SEric Fiselier assert(ret.args == t); 164*03e29a29SEric Fiselier } 165*03e29a29SEric Fiselier } 166*03e29a29SEric Fiselier 167*03e29a29SEric Fiselier void test_call_quals_and_arg_types() 168*03e29a29SEric Fiselier { 169*03e29a29SEric Fiselier TrackedCallable obj; 170*03e29a29SEric Fiselier using Tup = std::tuple<int, int const&, unsigned&&>; 171*03e29a29SEric Fiselier const int x = 42; 172*03e29a29SEric Fiselier unsigned y = 101; 173*03e29a29SEric Fiselier Tup t(-1, x, std::move(y)); 174*03e29a29SEric Fiselier Tup const& ct = t; 175*03e29a29SEric Fiselier check_apply_quals_and_types<int&, int const&, unsigned&>(t); 176*03e29a29SEric Fiselier check_apply_quals_and_types<int const&, int const&, unsigned&>(ct); 177*03e29a29SEric Fiselier check_apply_quals_and_types<int&&, int const&, unsigned&&>(std::move(t)); 178*03e29a29SEric Fiselier check_apply_quals_and_types<int const&&, int const&, unsigned&&>(std::move(ct)); 179*03e29a29SEric Fiselier } 180*03e29a29SEric Fiselier 181*03e29a29SEric Fiselier 182*03e29a29SEric Fiselier struct NothrowMoveable { 183*03e29a29SEric Fiselier NothrowMoveable() noexcept = default; 184*03e29a29SEric Fiselier NothrowMoveable(NothrowMoveable const&) noexcept(false) {} 185*03e29a29SEric Fiselier NothrowMoveable(NothrowMoveable&&) noexcept {} 186*03e29a29SEric Fiselier }; 187*03e29a29SEric Fiselier 188*03e29a29SEric Fiselier template <bool IsNoexcept> 189*03e29a29SEric Fiselier struct TestNoexceptCallable { 190*03e29a29SEric Fiselier template <class ...Args> 191*03e29a29SEric Fiselier NothrowMoveable operator()(Args...) const noexcept(IsNoexcept) { return {}; } 192*03e29a29SEric Fiselier }; 193*03e29a29SEric Fiselier 194*03e29a29SEric Fiselier void test_noexcept() 195*03e29a29SEric Fiselier { 196*03e29a29SEric Fiselier TestNoexceptCallable<true> nec; 197*03e29a29SEric Fiselier TestNoexceptCallable<false> tc; 198*03e29a29SEric Fiselier { 199*03e29a29SEric Fiselier // test that the functions noexcept-ness is propagated 200*03e29a29SEric Fiselier using Tup = std::tuple<int, const char*, long>; 201*03e29a29SEric Fiselier Tup t; 202*03e29a29SEric Fiselier ASSERT_NOEXCEPT(std::apply(nec, t)); 203*03e29a29SEric Fiselier ASSERT_NOT_NOEXCEPT(std::apply(tc, t)); 204*03e29a29SEric Fiselier } 205*03e29a29SEric Fiselier { 206*03e29a29SEric Fiselier // test that the noexcept-ness of the argument conversions is checked. 207*03e29a29SEric Fiselier using Tup = std::tuple<NothrowMoveable, int>; 208*03e29a29SEric Fiselier Tup t; 209*03e29a29SEric Fiselier ASSERT_NOT_NOEXCEPT(std::apply(nec, t)); 210*03e29a29SEric Fiselier ASSERT_NOEXCEPT(std::apply(nec, std::move(t))); 211*03e29a29SEric Fiselier } 212*03e29a29SEric Fiselier } 213*03e29a29SEric Fiselier 214*03e29a29SEric Fiselier namespace ReturnTypeTest { 215*03e29a29SEric Fiselier static int my_int = 42; 216*03e29a29SEric Fiselier 217*03e29a29SEric Fiselier template <int N> struct index {}; 218*03e29a29SEric Fiselier 219*03e29a29SEric Fiselier void f(index<0>) {} 220*03e29a29SEric Fiselier 221*03e29a29SEric Fiselier int f(index<1>) { return 0; } 222*03e29a29SEric Fiselier 223*03e29a29SEric Fiselier int & f(index<2>) { return static_cast<int &>(my_int); } 224*03e29a29SEric Fiselier int const & f(index<3>) { return static_cast<int const &>(my_int); } 225*03e29a29SEric Fiselier int volatile & f(index<4>) { return static_cast<int volatile &>(my_int); } 226*03e29a29SEric Fiselier int const volatile & f(index<5>) { return static_cast<int const volatile &>(my_int); } 227*03e29a29SEric Fiselier 228*03e29a29SEric Fiselier int && f(index<6>) { return static_cast<int &&>(my_int); } 229*03e29a29SEric Fiselier int const && f(index<7>) { return static_cast<int const &&>(my_int); } 230*03e29a29SEric Fiselier int volatile && f(index<8>) { return static_cast<int volatile &&>(my_int); } 231*03e29a29SEric Fiselier int const volatile && f(index<9>) { return static_cast<int const volatile &&>(my_int); } 232*03e29a29SEric Fiselier 233*03e29a29SEric Fiselier int * f(index<10>) { return static_cast<int *>(&my_int); } 234*03e29a29SEric Fiselier int const * f(index<11>) { return static_cast<int const *>(&my_int); } 235*03e29a29SEric Fiselier int volatile * f(index<12>) { return static_cast<int volatile *>(&my_int); } 236*03e29a29SEric Fiselier int const volatile * f(index<13>) { return static_cast<int const volatile *>(&my_int); } 237*03e29a29SEric Fiselier 238*03e29a29SEric Fiselier template <int Func, class Expect> 239*03e29a29SEric Fiselier void test() 240*03e29a29SEric Fiselier { 241*03e29a29SEric Fiselier using RawInvokeResult = decltype(f(index<Func>{})); 242*03e29a29SEric Fiselier static_assert(std::is_same<RawInvokeResult, Expect>::value, ""); 243*03e29a29SEric Fiselier using FnType = RawInvokeResult (*) (index<Func>); 244*03e29a29SEric Fiselier FnType fn = f; 245*03e29a29SEric Fiselier std::tuple<index<Func>> t; ((void)t); 246*03e29a29SEric Fiselier using InvokeResult = decltype(std::apply(fn, t)); 247*03e29a29SEric Fiselier static_assert(std::is_same<InvokeResult, Expect>::value, ""); 248*03e29a29SEric Fiselier } 249*03e29a29SEric Fiselier } // end namespace ReturnTypeTest 250*03e29a29SEric Fiselier 251*03e29a29SEric Fiselier void test_return_type() 252*03e29a29SEric Fiselier { 253*03e29a29SEric Fiselier using ReturnTypeTest::test; 254*03e29a29SEric Fiselier test<0, void>(); 255*03e29a29SEric Fiselier test<1, int>(); 256*03e29a29SEric Fiselier test<2, int &>(); 257*03e29a29SEric Fiselier test<3, int const &>(); 258*03e29a29SEric Fiselier test<4, int volatile &>(); 259*03e29a29SEric Fiselier test<5, int const volatile &>(); 260*03e29a29SEric Fiselier test<6, int &&>(); 261*03e29a29SEric Fiselier test<7, int const &&>(); 262*03e29a29SEric Fiselier test<8, int volatile &&>(); 263*03e29a29SEric Fiselier test<9, int const volatile &&>(); 264*03e29a29SEric Fiselier test<10, int *>(); 265*03e29a29SEric Fiselier test<11, int const *>(); 266*03e29a29SEric Fiselier test<12, int volatile *>(); 267*03e29a29SEric Fiselier test<13, int const volatile *>(); 268*03e29a29SEric Fiselier } 269*03e29a29SEric Fiselier 270*03e29a29SEric Fiselier int main() { 271*03e29a29SEric Fiselier test_constexpr_evaluation(); 272*03e29a29SEric Fiselier test_call_quals_and_arg_types(); 273*03e29a29SEric Fiselier test_return_type(); 274*03e29a29SEric Fiselier test_noexcept(); 275*03e29a29SEric Fiselier } 276