brintos

brintos / llvm-project-archived public Read only

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