brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.9 KiB · 1bf833b Raw
463 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// template <class F> unspecified not_fn(F&& f);12 13#include <functional>14#include <type_traits>15#include <string>16#include <cassert>17 18#include "test_macros.h"19#include "type_id.h"20#include "callable_types.h"21 22///////////////////////////////////////////////////////////////////////////////23//                        BOOL TEST TYPES24///////////////////////////////////////////////////////////////////////////////25 26struct EvilBool {27  static int bang_called;28 29  EvilBool(EvilBool const&) = default;30  EvilBool(EvilBool&&) = default;31 32  friend EvilBool operator!(EvilBool const& other) {33    ++bang_called;34    return EvilBool{!other.value};35  }36 37private:38  friend struct MoveOnlyCallable<EvilBool>;39  friend struct CopyCallable<EvilBool>;40  friend struct NoExceptCallable<EvilBool>;41 42  constexpr explicit EvilBool(bool x) : value(x) {}43  EvilBool& operator=(EvilBool const& other) = default;44 45public:46  bool value;47};48 49int EvilBool::bang_called = 0;50 51struct ExplicitBool {52  ExplicitBool(ExplicitBool const&) = default;53  ExplicitBool(ExplicitBool&&) = default;54 55  constexpr explicit operator bool() const { return value; }56 57private:58  friend struct MoveOnlyCallable<ExplicitBool>;59  friend struct CopyCallable<ExplicitBool>;60 61  constexpr explicit ExplicitBool(bool x) : value(x) {}62  constexpr ExplicitBool& operator=(bool x) {63      value = x;64      return *this;65  }66 67  bool value;68};69 70 71struct NoExceptEvilBool {72  NoExceptEvilBool(NoExceptEvilBool const&) = default;73  NoExceptEvilBool(NoExceptEvilBool&&) = default;74  NoExceptEvilBool& operator=(NoExceptEvilBool const& other) = default;75 76  constexpr explicit NoExceptEvilBool(bool x) : value(x) {}77 78  friend NoExceptEvilBool operator!(NoExceptEvilBool const& other) noexcept {79    return NoExceptEvilBool{!other.value};80  }81 82  bool value;83};84 85 86 87TEST_CONSTEXPR_CXX2088bool constructor_tests()89{90    {91        using T = MoveOnlyCallable<bool>;92        T value(true);93        using RetT = decltype(std::not_fn(std::move(value)));94        static_assert(std::is_move_constructible<RetT>::value, "");95        static_assert(!std::is_copy_constructible<RetT>::value, "");96        static_assert(!std::is_move_assignable<RetT>::value, "");97        static_assert(!std::is_copy_assignable<RetT>::value, "");98        auto ret = std::not_fn(std::move(value));99        // test it was moved from100        assert(value.value == false);101        // test that ret() negates the original value 'true'102        assert(ret() == false);103        assert(ret(0, 0.0, "blah") == false);104        // Move ret and test that it was moved from and that ret2 got the105        // original value.106        auto ret2 = std::move(ret);107        assert(ret() == true);108        assert(ret2() == false);109        assert(ret2(42) == false);110    }111    {112        using T = CopyCallable<bool>;113        T value(false);114        using RetT = decltype(std::not_fn(value));115        static_assert(std::is_move_constructible<RetT>::value, "");116        static_assert(std::is_copy_constructible<RetT>::value, "");117        static_assert(!std::is_move_assignable<RetT>::value, "");118        static_assert(!std::is_copy_assignable<RetT>::value, "");119        auto ret = std::not_fn(value);120        // test that value is unchanged (copied not moved)121        assert(value.value == false);122        // test 'ret' has the original value123        assert(ret() == true);124        assert(ret(42, 100) == true);125        // move from 'ret' and check that 'ret2' has the original value.126        auto ret2 = std::move(ret);127        assert(ret() == false);128        assert(ret2() == true);129        assert(ret2("abc") == true);130        // initialize not_fn with rvalue131        auto ret3 = std::not_fn(std::move(value));132        assert(ret(0) == false);133        assert(ret3(0) == true);134    }135    {136        using T = CopyAssignableWrapper;137        T value(true);138        T value2(false);139        using RetT = decltype(std::not_fn(value));140        static_assert(std::is_move_constructible<RetT>::value, "");141        static_assert(std::is_copy_constructible<RetT>::value, "");142        auto ret = std::not_fn(value);143        assert(ret() == false);144        auto ret2 = std::not_fn(value2);145        assert(ret2() == true);146    }147    {148        using T = MoveAssignableWrapper;149        T value(true);150        T value2(false);151        using RetT = decltype(std::not_fn(std::move(value)));152        static_assert(std::is_move_constructible<RetT>::value, "");153        static_assert(!std::is_copy_constructible<RetT>::value, "");154        static_assert(!std::is_copy_assignable<RetT>::value, "");155        auto ret = std::not_fn(std::move(value));156        assert(ret() == false);157        auto ret2 = std::not_fn(std::move(value2));158        assert(ret2() == true);159    }160    return true;161}162 163void return_type_tests()164{165    using std::is_same;166    {167        using T = CopyCallable<bool>;168        auto ret = std::not_fn(T{false});169        static_assert(is_same<decltype(ret()), bool>::value, "");170        static_assert(is_same<decltype(ret("abc")), bool>::value, "");171        assert(ret() == true);172    }173    {174        using T = CopyCallable<ExplicitBool>;175        auto ret = std::not_fn(T{true});176        static_assert(is_same<decltype(ret()), bool>::value, "");177        static_assert(is_same<decltype(ret(std::string("abc"))), bool>::value, "");178        assert(ret() == false);179    }180    {181        using T = CopyCallable<EvilBool>;182        auto ret = std::not_fn(T{false});183        static_assert(is_same<decltype(ret()), EvilBool>::value, "");184        EvilBool::bang_called = 0;185        auto value_ret = ret();186        assert(EvilBool::bang_called == 1);187        assert(value_ret.value == true);188        ret();189        assert(EvilBool::bang_called == 2);190    }191}192 193// Other tests only test using objects with call operators. Test various194// other callable types here.195TEST_CONSTEXPR_CXX20196bool other_callable_types_test()197{198    { // test with function pointer199        auto ret = std::not_fn(returns_true);200        assert(ret() == false);201    }202    { // test with lambda203        auto returns_value = [](bool value) { return value; };204        auto ret = std::not_fn(returns_value);205        assert(ret(true) == false);206        assert(ret(false) == true);207    }208    { // test with pointer to member function209        MemFunCallable mt(true);210        const MemFunCallable mf(false);211        auto ret = std::not_fn(&MemFunCallable::return_value);212        assert(ret(mt) == false);213        assert(ret(mf) == true);214        assert(ret(&mt) == false);215        assert(ret(&mf) == true);216    }217    { // test with pointer to member function218        MemFunCallable mt(true);219        MemFunCallable mf(false);220        auto ret = std::not_fn(&MemFunCallable::return_value_nc);221        assert(ret(mt) == false);222        assert(ret(mf) == true);223        assert(ret(&mt) == false);224        assert(ret(&mf) == true);225    }226    { // test with pointer to member data227        MemFunCallable mt(true);228        const MemFunCallable mf(false);229        auto ret = std::not_fn(&MemFunCallable::value);230        assert(ret(mt) == false);231        assert(ret(mf) == true);232        assert(ret(&mt) == false);233        assert(ret(&mf) == true);234    }235    return true;236}237 238void throws_in_constructor_test()239{240#ifndef TEST_HAS_NO_EXCEPTIONS241    struct ThrowsOnCopy {242      ThrowsOnCopy(ThrowsOnCopy const&) {243        throw 42;244      }245      ThrowsOnCopy() = default;246      bool operator()() const {247        assert(false);248#ifdef TEST_COMPILER_MSVC249        __assume(0);250#else251        __builtin_unreachable();252#endif253      }254    };255    {256        ThrowsOnCopy cp;257        try {258            (void)std::not_fn(cp);259            assert(false);260        } catch (int const& value) {261            assert(value == 42);262        }263    }264#endif265}266 267TEST_CONSTEXPR_CXX20268bool call_operator_sfinae_test() {269    { // wrong number of arguments270        using T = decltype(std::not_fn(returns_true));271        static_assert(std::is_invocable<T>::value, ""); // callable only with no args272        static_assert(!std::is_invocable<T, bool>::value, "");273    }274    { // violates const correctness (member function pointer)275        using T = decltype(std::not_fn(&MemFunCallable::return_value_nc));276        static_assert(std::is_invocable<T, MemFunCallable&>::value, "");277        static_assert(!std::is_invocable<T, const MemFunCallable&>::value, "");278    }279    { // violates const correctness (call object)280        using Obj = CopyCallable<bool>;281        using NCT = decltype(std::not_fn(Obj{true}));282        using CT = const NCT;283        static_assert(std::is_invocable<NCT>::value, "");284        static_assert(!std::is_invocable<CT>::value, "");285    }286    { // returns bad type with no operator!287        auto fn = [](auto x) { return x; };288        using T = decltype(std::not_fn(fn));289        static_assert(std::is_invocable<T, bool>::value, "");290        static_assert(!std::is_invocable<T, std::string>::value, "");291    }292    return true;293}294 295TEST_CONSTEXPR_CXX20296bool call_operator_forwarding_test()297{298    using Fn = ForwardingCallObject;299    Fn::State st;300    auto obj = std::not_fn(Fn{st});301    const auto& c_obj = obj;302    { // test zero args303        obj();304        assert(st.check_call<>(CT_NonConst | CT_LValue));305        std::move(obj)();306        assert(st.check_call<>(CT_NonConst | CT_RValue));307        c_obj();308        assert(st.check_call<>(CT_Const | CT_LValue));309        std::move(c_obj)();310        assert(st.check_call<>(CT_Const | CT_RValue));311    }312    { // test value categories313        int x = 42;314        const int cx = 42;315        obj(x);316        assert(st.check_call<int&>(CT_NonConst | CT_LValue));317        obj(cx);318        assert(st.check_call<const int&>(CT_NonConst | CT_LValue));319        obj(std::move(x));320        assert(st.check_call<int&&>(CT_NonConst | CT_LValue));321        obj(std::move(cx));322        assert(st.check_call<const int&&>(CT_NonConst | CT_LValue));323        obj(42);324        assert(st.check_call<int&&>(CT_NonConst | CT_LValue));325    }326    { // test value categories - rvalue327        int x = 42;328        const int cx = 42;329        std::move(obj)(x);330        assert(st.check_call<int&>(CT_NonConst | CT_RValue));331        std::move(obj)(cx);332        assert(st.check_call<const int&>(CT_NonConst | CT_RValue));333        std::move(obj)(std::move(x));334        assert(st.check_call<int&&>(CT_NonConst | CT_RValue));335        std::move(obj)(std::move(cx));336        assert(st.check_call<const int&&>(CT_NonConst | CT_RValue));337        std::move(obj)(42);338        assert(st.check_call<int&&>(CT_NonConst | CT_RValue));339    }340    { // test value categories - const call341        int x = 42;342        const int cx = 42;343        c_obj(x);344        assert(st.check_call<int&>(CT_Const | CT_LValue));345        c_obj(cx);346        assert(st.check_call<const int&>(CT_Const | CT_LValue));347        c_obj(std::move(x));348        assert(st.check_call<int&&>(CT_Const | CT_LValue));349        c_obj(std::move(cx));350        assert(st.check_call<const int&&>(CT_Const | CT_LValue));351        c_obj(42);352        assert(st.check_call<int&&>(CT_Const | CT_LValue));353    }354    { // test value categories - const call rvalue355        int x = 42;356        const int cx = 42;357        std::move(c_obj)(x);358        assert(st.check_call<int&>(CT_Const | CT_RValue));359        std::move(c_obj)(cx);360        assert(st.check_call<const int&>(CT_Const | CT_RValue));361        std::move(c_obj)(std::move(x));362        assert(st.check_call<int&&>(CT_Const | CT_RValue));363        std::move(c_obj)(std::move(cx));364        assert(st.check_call<const int&&>(CT_Const | CT_RValue));365        std::move(c_obj)(42);366        assert(st.check_call<int&&>(CT_Const | CT_RValue));367    }368    { // test multi arg369        using String = const char *;370        const double y = 3.14;371        String s = "abc";372        obj(42, std::move(y), s, String{"foo"});373        assert((st.check_call<int&&, const double&&, String&, String&&>(CT_NonConst | CT_LValue)));374        std::move(obj)(42, std::move(y), s, String{"foo"});375        assert((st.check_call<int&&, const double&&, String&, String&&>(CT_NonConst | CT_RValue)));376        c_obj(42, std::move(y), s, String{"foo"});377        assert((st.check_call<int&&, const double&&, String&, String&&>(CT_Const  | CT_LValue)));378        std::move(c_obj)(42, std::move(y), s, String{"foo"});379        assert((st.check_call<int&&, const double&&, String&, String&&>(CT_Const  | CT_RValue)));380    }381    return true;382}383 384TEST_CONSTEXPR_CXX20385bool call_operator_noexcept_test()386{387    {388        using T = ConstCallable<bool>;389        T value(true);390        auto ret = std::not_fn(value);391        static_assert(!noexcept(ret()), "call should not be noexcept");392        auto const& cret = ret;393        static_assert(!noexcept(cret()), "call should not be noexcept");394    }395    {396        using T = NoExceptCallable<bool>;397        T value(true);398        auto ret = std::not_fn(value);399        LIBCPP_STATIC_ASSERT(noexcept(!std::__invoke(value)), "");400#if TEST_STD_VER > 14401        static_assert(noexcept(!std::invoke(value)), "");402#endif403        static_assert(noexcept(ret()), "call should be noexcept");404        auto const& cret = ret;405        static_assert(noexcept(cret()), "call should be noexcept");406    }407    {408        using T = NoExceptCallable<NoExceptEvilBool>;409        T value(true);410        auto ret = std::not_fn(value);411        static_assert(noexcept(ret()), "call should not be noexcept");412        auto const& cret = ret;413        static_assert(noexcept(cret()), "call should not be noexcept");414    }415    {416        using T = NoExceptCallable<EvilBool>;417        T value(true);418        auto ret = std::not_fn(value);419        static_assert(!noexcept(ret()), "call should not be noexcept");420        auto const& cret = ret;421        static_assert(!noexcept(cret()), "call should not be noexcept");422    }423    return true;424}425 426TEST_CONSTEXPR_CXX20427bool test_lwg2767() {428    // See https://cplusplus.github.io/LWG/lwg-defects.html#2767429    struct Abstract { virtual void f() const = 0; };430    struct Derived : public Abstract { void f() const {} };431    struct F { constexpr bool operator()(Abstract&&) { return false; } };432    {433        Derived d;434        Abstract &a = d;435        bool b = std::not_fn(F{})(std::move(a));436        assert(b);437    }438    return true;439}440 441int main(int, char**)442{443    constructor_tests();444    return_type_tests();445    other_callable_types_test();446    throws_in_constructor_test();447    call_operator_sfinae_test(); // somewhat of an extension448    call_operator_forwarding_test();449    call_operator_noexcept_test();450    test_lwg2767();451 452#if TEST_STD_VER >= 20453    static_assert(constructor_tests());454    static_assert(other_callable_types_test());455    static_assert(call_operator_sfinae_test()); // somewhat of an extension456    static_assert(call_operator_forwarding_test());457    static_assert(call_operator_noexcept_test());458    static_assert(test_lwg2767());459#endif460 461    return 0;462}463