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