103e29a29SEric Fiselier //===----------------------------------------------------------------------===//
203e29a29SEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
603e29a29SEric Fiselier //
703e29a29SEric Fiselier //===----------------------------------------------------------------------===//
803e29a29SEric Fiselier 
903e29a29SEric Fiselier // UNSUPPORTED: c++98, c++03, c++11, c++14
1003e29a29SEric Fiselier 
1103e29a29SEric Fiselier // <tuple>
1203e29a29SEric Fiselier 
1303e29a29SEric Fiselier // template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
1403e29a29SEric Fiselier 
1503e29a29SEric Fiselier // Test with different ref/ptr/cv qualified argument types.
1603e29a29SEric Fiselier 
1703e29a29SEric Fiselier #include <tuple>
1803e29a29SEric Fiselier #include <array>
1903e29a29SEric Fiselier #include <utility>
2003e29a29SEric Fiselier #include <cassert>
2103e29a29SEric Fiselier 
2203e29a29SEric Fiselier #include "test_macros.h"
2303e29a29SEric Fiselier #include "type_id.h"
2403e29a29SEric Fiselier 
2503e29a29SEric Fiselier // std::array is explicitly allowed to be initialized with A a = { init-list };.
2603e29a29SEric Fiselier // Disable the missing braces warning for this reason.
2703e29a29SEric Fiselier #include "disable_missing_braces_warning.h"
2803e29a29SEric Fiselier 
2903e29a29SEric Fiselier 
3003e29a29SEric Fiselier constexpr int constexpr_sum_fn() { return 0; }
3103e29a29SEric Fiselier 
3203e29a29SEric Fiselier template <class ...Ints>
3303e29a29SEric Fiselier constexpr int constexpr_sum_fn(int x1, Ints... rest) { return x1 + constexpr_sum_fn(rest...); }
3403e29a29SEric Fiselier 
3503e29a29SEric Fiselier struct ConstexprSumT {
3603e29a29SEric Fiselier   constexpr ConstexprSumT() = default;
3703e29a29SEric Fiselier   template <class ...Ints>
3803e29a29SEric Fiselier   constexpr int operator()(Ints... values) const {
3903e29a29SEric Fiselier       return constexpr_sum_fn(values...);
4003e29a29SEric Fiselier   }
4103e29a29SEric Fiselier };
4203e29a29SEric Fiselier 
4303e29a29SEric Fiselier 
4403e29a29SEric Fiselier void test_constexpr_evaluation()
4503e29a29SEric Fiselier {
4603e29a29SEric Fiselier     constexpr ConstexprSumT sum_obj{};
4703e29a29SEric Fiselier     {
4803e29a29SEric Fiselier         using Tup = std::tuple<>;
4903e29a29SEric Fiselier         using Fn = int(&)();
5003e29a29SEric Fiselier         constexpr Tup t;
5103e29a29SEric Fiselier         static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 0, "");
5203e29a29SEric Fiselier         static_assert(std::apply(sum_obj, t) == 0, "");
5303e29a29SEric Fiselier     }
5403e29a29SEric Fiselier     {
5503e29a29SEric Fiselier         using Tup = std::tuple<int>;
5603e29a29SEric Fiselier         using Fn = int(&)(int);
5703e29a29SEric Fiselier         constexpr Tup t(42);
5803e29a29SEric Fiselier         static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 42, "");
5903e29a29SEric Fiselier         static_assert(std::apply(sum_obj, t) == 42, "");
6003e29a29SEric Fiselier     }
6103e29a29SEric Fiselier     {
6203e29a29SEric Fiselier         using Tup = std::tuple<int, long>;
6303e29a29SEric Fiselier         using Fn = int(&)(int, int);
6403e29a29SEric Fiselier         constexpr Tup t(42, 101);
6503e29a29SEric Fiselier         static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, "");
6603e29a29SEric Fiselier         static_assert(std::apply(sum_obj, t) == 143, "");
6703e29a29SEric Fiselier     }
6803e29a29SEric Fiselier     {
6903e29a29SEric Fiselier         using Tup = std::pair<int, long>;
7003e29a29SEric Fiselier         using Fn = int(&)(int, int);
7103e29a29SEric Fiselier         constexpr Tup t(42, 101);
7203e29a29SEric Fiselier         static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 143, "");
7303e29a29SEric Fiselier         static_assert(std::apply(sum_obj, t) == 143, "");
7403e29a29SEric Fiselier     }
7503e29a29SEric Fiselier     {
7603e29a29SEric Fiselier         using Tup = std::tuple<int, long, int>;
7703e29a29SEric Fiselier         using Fn = int(&)(int, int, int);
7803e29a29SEric Fiselier         constexpr Tup t(42, 101, -1);
7903e29a29SEric Fiselier         static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, "");
8003e29a29SEric Fiselier         static_assert(std::apply(sum_obj, t) == 142, "");
8103e29a29SEric Fiselier     }
8203e29a29SEric Fiselier     {
8303e29a29SEric Fiselier         using Tup = std::array<int, 3>;
8403e29a29SEric Fiselier         using Fn = int(&)(int, int, int);
8503e29a29SEric Fiselier         constexpr Tup t = {42, 101, -1};
8603e29a29SEric Fiselier         static_assert(std::apply(static_cast<Fn>(constexpr_sum_fn), t) == 142, "");
8703e29a29SEric Fiselier         static_assert(std::apply(sum_obj, t) == 142, "");
8803e29a29SEric Fiselier     }
8903e29a29SEric Fiselier }
9003e29a29SEric Fiselier 
9103e29a29SEric Fiselier 
9203e29a29SEric Fiselier enum CallQuals {
9303e29a29SEric Fiselier   CQ_None,
9403e29a29SEric Fiselier   CQ_LValue,
9503e29a29SEric Fiselier   CQ_ConstLValue,
9603e29a29SEric Fiselier   CQ_RValue,
9703e29a29SEric Fiselier   CQ_ConstRValue
9803e29a29SEric Fiselier };
9903e29a29SEric Fiselier 
10003e29a29SEric Fiselier template <class Tuple>
10103e29a29SEric Fiselier struct CallInfo {
10203e29a29SEric Fiselier   CallQuals quals;
10303e29a29SEric Fiselier   TypeID const* arg_types;
10403e29a29SEric Fiselier   Tuple args;
10503e29a29SEric Fiselier 
10603e29a29SEric Fiselier   template <class ...Args>
10703e29a29SEric Fiselier   CallInfo(CallQuals q, Args&&... xargs)
10803e29a29SEric Fiselier       : quals(q), arg_types(&makeArgumentID<Args&&...>()), args(std::forward<Args>(xargs)...)
10903e29a29SEric Fiselier   {}
11003e29a29SEric Fiselier };
11103e29a29SEric Fiselier 
11203e29a29SEric Fiselier template <class ...Args>
11303e29a29SEric Fiselier inline CallInfo<decltype(std::forward_as_tuple(std::declval<Args>()...))>
11403e29a29SEric Fiselier makeCallInfo(CallQuals quals, Args&&... args) {
11503e29a29SEric Fiselier     return {quals, std::forward<Args>(args)...};
11603e29a29SEric Fiselier }
11703e29a29SEric Fiselier 
11803e29a29SEric Fiselier struct TrackedCallable {
11903e29a29SEric Fiselier 
12003e29a29SEric Fiselier   TrackedCallable() = default;
12103e29a29SEric Fiselier 
12203e29a29SEric Fiselier   template <class ...Args> auto operator()(Args&&... xargs) &
12303e29a29SEric Fiselier   { return makeCallInfo(CQ_LValue, std::forward<Args>(xargs)...); }
12403e29a29SEric Fiselier 
12503e29a29SEric Fiselier   template <class ...Args> auto operator()(Args&&... xargs) const&
12603e29a29SEric Fiselier   { return makeCallInfo(CQ_ConstLValue, std::forward<Args>(xargs)...); }
12703e29a29SEric Fiselier 
12803e29a29SEric Fiselier   template <class ...Args> auto operator()(Args&&... xargs) &&
12903e29a29SEric Fiselier   { return makeCallInfo(CQ_RValue, std::forward<Args>(xargs)...); }
13003e29a29SEric Fiselier 
13103e29a29SEric Fiselier   template <class ...Args> auto operator()(Args&&... xargs) const&&
13203e29a29SEric Fiselier   { return makeCallInfo(CQ_ConstRValue, std::forward<Args>(xargs)...); }
13303e29a29SEric Fiselier };
13403e29a29SEric Fiselier 
13503e29a29SEric Fiselier template <class ...ExpectArgs, class Tuple>
13603e29a29SEric Fiselier void check_apply_quals_and_types(Tuple&& t) {
13703e29a29SEric Fiselier     TypeID const* const expect_args = &makeArgumentID<ExpectArgs...>();
13803e29a29SEric Fiselier     TrackedCallable obj;
13903e29a29SEric Fiselier     TrackedCallable const& cobj = obj;
14003e29a29SEric Fiselier     {
14103e29a29SEric Fiselier         auto ret = std::apply(obj, std::forward<Tuple>(t));
14203e29a29SEric Fiselier         assert(ret.quals == CQ_LValue);
14303e29a29SEric Fiselier         assert(ret.arg_types == expect_args);
14403e29a29SEric Fiselier         assert(ret.args == t);
14503e29a29SEric Fiselier     }
14603e29a29SEric Fiselier     {
14703e29a29SEric Fiselier         auto ret = std::apply(cobj, std::forward<Tuple>(t));
14803e29a29SEric Fiselier         assert(ret.quals == CQ_ConstLValue);
14903e29a29SEric Fiselier         assert(ret.arg_types == expect_args);
15003e29a29SEric Fiselier         assert(ret.args == t);
15103e29a29SEric Fiselier     }
15203e29a29SEric Fiselier     {
15303e29a29SEric Fiselier         auto ret = std::apply(std::move(obj), std::forward<Tuple>(t));
15403e29a29SEric Fiselier         assert(ret.quals == CQ_RValue);
15503e29a29SEric Fiselier         assert(ret.arg_types == expect_args);
15603e29a29SEric Fiselier         assert(ret.args == t);
15703e29a29SEric Fiselier     }
15803e29a29SEric Fiselier     {
15903e29a29SEric Fiselier         auto ret = std::apply(std::move(cobj), std::forward<Tuple>(t));
16003e29a29SEric Fiselier         assert(ret.quals == CQ_ConstRValue);
16103e29a29SEric Fiselier         assert(ret.arg_types == expect_args);
16203e29a29SEric Fiselier         assert(ret.args == t);
16303e29a29SEric Fiselier     }
16403e29a29SEric Fiselier }
16503e29a29SEric Fiselier 
16603e29a29SEric Fiselier void test_call_quals_and_arg_types()
16703e29a29SEric Fiselier {
16803e29a29SEric Fiselier     using Tup = std::tuple<int, int const&, unsigned&&>;
16903e29a29SEric Fiselier     const int x = 42;
17003e29a29SEric Fiselier     unsigned y = 101;
17103e29a29SEric Fiselier     Tup t(-1, x, std::move(y));
17203e29a29SEric Fiselier     Tup const& ct = t;
17303e29a29SEric Fiselier     check_apply_quals_and_types<int&, int const&, unsigned&>(t);
17403e29a29SEric Fiselier     check_apply_quals_and_types<int const&, int const&, unsigned&>(ct);
17503e29a29SEric Fiselier     check_apply_quals_and_types<int&&, int const&, unsigned&&>(std::move(t));
17603e29a29SEric Fiselier     check_apply_quals_and_types<int const&&, int const&, unsigned&&>(std::move(ct));
17703e29a29SEric Fiselier }
17803e29a29SEric Fiselier 
17903e29a29SEric Fiselier 
18003e29a29SEric Fiselier struct NothrowMoveable {
18103e29a29SEric Fiselier   NothrowMoveable() noexcept = default;
18203e29a29SEric Fiselier   NothrowMoveable(NothrowMoveable const&) noexcept(false) {}
18303e29a29SEric Fiselier   NothrowMoveable(NothrowMoveable&&) noexcept {}
18403e29a29SEric Fiselier };
18503e29a29SEric Fiselier 
18603e29a29SEric Fiselier template <bool IsNoexcept>
18703e29a29SEric Fiselier struct TestNoexceptCallable {
18803e29a29SEric Fiselier   template <class ...Args>
18903e29a29SEric Fiselier   NothrowMoveable operator()(Args...) const noexcept(IsNoexcept) { return {}; }
19003e29a29SEric Fiselier };
19103e29a29SEric Fiselier 
19203e29a29SEric Fiselier void test_noexcept()
19303e29a29SEric Fiselier {
19403e29a29SEric Fiselier     TestNoexceptCallable<true> nec;
19503e29a29SEric Fiselier     TestNoexceptCallable<false> tc;
19603e29a29SEric Fiselier     {
19703e29a29SEric Fiselier         // test that the functions noexcept-ness is propagated
19803e29a29SEric Fiselier         using Tup = std::tuple<int, const char*, long>;
19903e29a29SEric Fiselier         Tup t;
2008a597d65SStephan T. Lavavej         LIBCPP_ASSERT_NOEXCEPT(std::apply(nec, t));
20103e29a29SEric Fiselier         ASSERT_NOT_NOEXCEPT(std::apply(tc, t));
20203e29a29SEric Fiselier     }
20303e29a29SEric Fiselier     {
20403e29a29SEric Fiselier         // test that the noexcept-ness of the argument conversions is checked.
20503e29a29SEric Fiselier         using Tup = std::tuple<NothrowMoveable, int>;
20603e29a29SEric Fiselier         Tup t;
20703e29a29SEric Fiselier         ASSERT_NOT_NOEXCEPT(std::apply(nec, t));
2088a597d65SStephan T. Lavavej         LIBCPP_ASSERT_NOEXCEPT(std::apply(nec, std::move(t)));
20903e29a29SEric Fiselier     }
21003e29a29SEric Fiselier }
21103e29a29SEric Fiselier 
21203e29a29SEric Fiselier namespace ReturnTypeTest {
21303e29a29SEric Fiselier     static int my_int = 42;
21403e29a29SEric Fiselier 
21503e29a29SEric Fiselier     template <int N> struct index {};
21603e29a29SEric Fiselier 
21703e29a29SEric Fiselier     void f(index<0>) {}
21803e29a29SEric Fiselier 
21903e29a29SEric Fiselier     int f(index<1>) { return 0; }
22003e29a29SEric Fiselier 
22103e29a29SEric Fiselier     int & f(index<2>) { return static_cast<int &>(my_int); }
22203e29a29SEric Fiselier     int const & f(index<3>) { return static_cast<int const &>(my_int); }
22303e29a29SEric Fiselier     int volatile & f(index<4>) { return static_cast<int volatile &>(my_int); }
22403e29a29SEric Fiselier     int const volatile & f(index<5>) { return static_cast<int const volatile &>(my_int); }
22503e29a29SEric Fiselier 
22603e29a29SEric Fiselier     int && f(index<6>) { return static_cast<int &&>(my_int); }
22703e29a29SEric Fiselier     int const && f(index<7>) { return static_cast<int const &&>(my_int); }
22803e29a29SEric Fiselier     int volatile && f(index<8>) { return static_cast<int volatile &&>(my_int); }
22903e29a29SEric Fiselier     int const volatile && f(index<9>) { return static_cast<int const volatile &&>(my_int); }
23003e29a29SEric Fiselier 
23103e29a29SEric Fiselier     int * f(index<10>) { return static_cast<int *>(&my_int); }
23203e29a29SEric Fiselier     int const * f(index<11>) { return static_cast<int const *>(&my_int); }
23303e29a29SEric Fiselier     int volatile * f(index<12>) { return static_cast<int volatile *>(&my_int); }
23403e29a29SEric Fiselier     int const volatile * f(index<13>) { return static_cast<int const volatile *>(&my_int); }
23503e29a29SEric Fiselier 
23603e29a29SEric Fiselier     template <int Func, class Expect>
23703e29a29SEric Fiselier     void test()
23803e29a29SEric Fiselier     {
23903e29a29SEric Fiselier         using RawInvokeResult = decltype(f(index<Func>{}));
24003e29a29SEric Fiselier         static_assert(std::is_same<RawInvokeResult, Expect>::value, "");
24103e29a29SEric Fiselier         using FnType = RawInvokeResult (*) (index<Func>);
24203e29a29SEric Fiselier         FnType fn = f;
24303e29a29SEric Fiselier         std::tuple<index<Func>> t; ((void)t);
24403e29a29SEric Fiselier         using InvokeResult = decltype(std::apply(fn, t));
24503e29a29SEric Fiselier         static_assert(std::is_same<InvokeResult, Expect>::value, "");
24603e29a29SEric Fiselier     }
24703e29a29SEric Fiselier } // end namespace ReturnTypeTest
24803e29a29SEric Fiselier 
24903e29a29SEric Fiselier void test_return_type()
25003e29a29SEric Fiselier {
25103e29a29SEric Fiselier     using ReturnTypeTest::test;
25203e29a29SEric Fiselier     test<0, void>();
25303e29a29SEric Fiselier     test<1, int>();
25403e29a29SEric Fiselier     test<2, int &>();
25503e29a29SEric Fiselier     test<3, int const &>();
25603e29a29SEric Fiselier     test<4, int volatile &>();
25703e29a29SEric Fiselier     test<5, int const volatile &>();
25803e29a29SEric Fiselier     test<6, int &&>();
25903e29a29SEric Fiselier     test<7, int const &&>();
26003e29a29SEric Fiselier     test<8, int volatile &&>();
26103e29a29SEric Fiselier     test<9, int const volatile &&>();
26203e29a29SEric Fiselier     test<10, int *>();
26303e29a29SEric Fiselier     test<11, int const *>();
26403e29a29SEric Fiselier     test<12, int volatile *>();
26503e29a29SEric Fiselier     test<13, int const volatile *>();
26603e29a29SEric Fiselier }
26703e29a29SEric Fiselier 
268*2df59c50SJF Bastien int main(int, char**) {
26903e29a29SEric Fiselier     test_constexpr_evaluation();
27003e29a29SEric Fiselier     test_call_quals_and_arg_types();
27103e29a29SEric Fiselier     test_return_type();
27203e29a29SEric Fiselier     test_noexcept();
273*2df59c50SJF Bastien 
274*2df59c50SJF Bastien   return 0;
27503e29a29SEric Fiselier }
276