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