Home | History | Annotate | Download | only in func.not_fn
      1 //===----------------------------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 // UNSUPPORTED: c++98, c++03, c++11, c++14
     11 
     12 // template <class F> unspecified not_fn(F&& f);
     13 
     14 #include <functional>
     15 #include <type_traits>
     16 #include <string>
     17 #include <cassert>
     18 
     19 #include "test_macros.h"
     20 #include "type_id.h"
     21 
     22 
     23 ///////////////////////////////////////////////////////////////////////////////
     24 //                       CALLABLE TEST TYPES
     25 ///////////////////////////////////////////////////////////////////////////////
     26 
     27 bool returns_true() { return true; }
     28 
     29 template <class Ret = bool>
     30 struct MoveOnlyCallable {
     31   MoveOnlyCallable(MoveOnlyCallable const&) = delete;
     32   MoveOnlyCallable(MoveOnlyCallable&& other)
     33       : value(other.value)
     34   { other.value = !other.value; }
     35 
     36   template <class ...Args>
     37   Ret operator()(Args&&...) { return Ret{value}; }
     38 
     39   explicit MoveOnlyCallable(bool x) : value(x) {}
     40   Ret value;
     41 };
     42 
     43 template <class Ret = bool>
     44 struct CopyCallable {
     45   CopyCallable(CopyCallable const& other)
     46       : value(other.value) {}
     47 
     48   CopyCallable(CopyCallable&& other)
     49       : value(other.value) { other.value = !other.value; }
     50 
     51   template <class ...Args>
     52   Ret operator()(Args&&...) { return Ret{value}; }
     53 
     54   explicit CopyCallable(bool x) : value(x)  {}
     55   Ret value;
     56 };
     57 
     58 
     59 template <class Ret = bool>
     60 struct ConstCallable {
     61   ConstCallable(ConstCallable const& other)
     62       : value(other.value) {}
     63 
     64   ConstCallable(ConstCallable&& other)
     65       : value(other.value) { other.value = !other.value; }
     66 
     67   template <class ...Args>
     68   Ret operator()(Args&&...) const { return Ret{value}; }
     69 
     70   explicit ConstCallable(bool x) : value(x)  {}
     71   Ret value;
     72 };
     73 
     74 
     75 
     76 template <class Ret = bool>
     77 struct NoExceptCallable {
     78   NoExceptCallable(NoExceptCallable const& other)
     79       : value(other.value) {}
     80 
     81   template <class ...Args>
     82   Ret operator()(Args&&...) noexcept { return Ret{value}; }
     83 
     84   template <class ...Args>
     85   Ret operator()(Args&&...) const noexcept { return Ret{value}; }
     86 
     87   explicit NoExceptCallable(bool x) : value(x)  {}
     88   Ret value;
     89 };
     90 
     91 struct CopyAssignableWrapper {
     92   CopyAssignableWrapper(CopyAssignableWrapper const&) = default;
     93   CopyAssignableWrapper(CopyAssignableWrapper&&) = default;
     94   CopyAssignableWrapper& operator=(CopyAssignableWrapper const&) = default;
     95   CopyAssignableWrapper& operator=(CopyAssignableWrapper &&) = default;
     96 
     97   template <class ...Args>
     98   bool operator()(Args&&...) { return value; }
     99 
    100   explicit CopyAssignableWrapper(bool x) : value(x) {}
    101   bool value;
    102 };
    103 
    104 
    105 struct MoveAssignableWrapper {
    106   MoveAssignableWrapper(MoveAssignableWrapper const&) = delete;
    107   MoveAssignableWrapper(MoveAssignableWrapper&&) = default;
    108   MoveAssignableWrapper& operator=(MoveAssignableWrapper const&) = delete;
    109   MoveAssignableWrapper& operator=(MoveAssignableWrapper &&) = default;
    110 
    111   template <class ...Args>
    112   bool operator()(Args&&...) { return value; }
    113 
    114   explicit MoveAssignableWrapper(bool x) : value(x) {}
    115   bool value;
    116 };
    117 
    118 struct MemFunCallable {
    119   explicit MemFunCallable(bool x) : value(x) {}
    120 
    121   bool return_value() const { return value; }
    122   bool return_value_nc() { return value; }
    123   bool value;
    124 };
    125 
    126 enum CallType : unsigned {
    127   CT_None,
    128   CT_NonConst = 1,
    129   CT_Const = 2,
    130   CT_LValue = 4,
    131   CT_RValue = 8
    132 };
    133 
    134 inline constexpr CallType operator|(CallType LHS, CallType RHS) {
    135     return static_cast<CallType>(static_cast<unsigned>(LHS) | static_cast<unsigned>(RHS));
    136 }
    137 
    138 struct ForwardingCallObject {
    139 
    140   template <class ...Args>
    141   bool operator()(Args&&...) & {
    142       set_call<Args&&...>(CT_NonConst | CT_LValue);
    143       return true;
    144   }
    145 
    146   template <class ...Args>
    147   bool operator()(Args&&...) const & {
    148       set_call<Args&&...>(CT_Const | CT_LValue);
    149       return true;
    150   }
    151 
    152   // Don't allow the call operator to be invoked as an rvalue.
    153   template <class ...Args>
    154   bool operator()(Args&&...) && {
    155       set_call<Args&&...>(CT_NonConst | CT_RValue);
    156       return true;
    157   }
    158 
    159   template <class ...Args>
    160   bool operator()(Args&&...) const && {
    161       set_call<Args&&...>(CT_Const | CT_RValue);
    162       return true;
    163   }
    164 
    165   template <class ...Args>
    166   static void set_call(CallType type) {
    167       assert(last_call_type == CT_None);
    168       assert(last_call_args == nullptr);
    169       last_call_type = type;
    170       last_call_args = &makeArgumentID<Args...>();
    171   }
    172 
    173   template <class ...Args>
    174   static bool check_call(CallType type) {
    175       bool result =
    176            last_call_type == type
    177         && last_call_args
    178         && *last_call_args == makeArgumentID<Args...>();
    179       last_call_type = CT_None;
    180       last_call_args = nullptr;
    181       return result;
    182   }
    183 
    184   static CallType      last_call_type;
    185   static TypeID const* last_call_args;
    186 };
    187 
    188 CallType ForwardingCallObject::last_call_type = CT_None;
    189 TypeID const* ForwardingCallObject::last_call_args = nullptr;
    190 
    191 
    192 
    193 ///////////////////////////////////////////////////////////////////////////////
    194 //                        BOOL TEST TYPES
    195 ///////////////////////////////////////////////////////////////////////////////
    196 
    197 struct EvilBool {
    198   static int bang_called;
    199 
    200   EvilBool(EvilBool const&) = default;
    201   EvilBool(EvilBool&&) = default;
    202 
    203   friend EvilBool operator!(EvilBool const& other) {
    204     ++bang_called;
    205     return EvilBool{!other.value};
    206   }
    207 
    208 private:
    209   friend struct MoveOnlyCallable<EvilBool>;
    210   friend struct CopyCallable<EvilBool>;
    211   friend struct NoExceptCallable<EvilBool>;
    212 
    213   explicit EvilBool(bool x) : value(x) {}
    214   EvilBool& operator=(EvilBool const& other) = default;
    215 
    216 public:
    217   bool value;
    218 };
    219 
    220 int EvilBool::bang_called = 0;
    221 
    222 struct ExplicitBool {
    223   ExplicitBool(ExplicitBool const&) = default;
    224   ExplicitBool(ExplicitBool&&) = default;
    225 
    226   explicit operator bool() const { return value; }
    227 
    228 private:
    229   friend struct MoveOnlyCallable<ExplicitBool>;
    230   friend struct CopyCallable<ExplicitBool>;
    231 
    232   explicit ExplicitBool(bool x) : value(x) {}
    233   ExplicitBool& operator=(bool x) {
    234       value = x;
    235       return *this;
    236   }
    237 
    238   bool value;
    239 };
    240 
    241 
    242 struct NoExceptEvilBool {
    243   NoExceptEvilBool(NoExceptEvilBool const&) = default;
    244   NoExceptEvilBool(NoExceptEvilBool&&) = default;
    245   NoExceptEvilBool& operator=(NoExceptEvilBool const& other) = default;
    246 
    247   explicit NoExceptEvilBool(bool x) : value(x) {}
    248 
    249   friend NoExceptEvilBool operator!(NoExceptEvilBool const& other) noexcept {
    250     return NoExceptEvilBool{!other.value};
    251   }
    252 
    253   bool value;
    254 };
    255 
    256 
    257 
    258 void constructor_tests()
    259 {
    260     {
    261         using T = MoveOnlyCallable<bool>;
    262         T value(true);
    263         using RetT = decltype(std::not_fn(std::move(value)));
    264         static_assert(std::is_move_constructible<RetT>::value, "");
    265         static_assert(!std::is_copy_constructible<RetT>::value, "");
    266         static_assert(!std::is_move_assignable<RetT>::value, "");
    267         static_assert(!std::is_copy_assignable<RetT>::value, "");
    268         auto ret = std::not_fn(std::move(value));
    269         // test it was moved from
    270         assert(value.value == false);
    271         // test that ret() negates the original value 'true'
    272         assert(ret() == false);
    273         assert(ret(0, 0.0, "blah") == false);
    274         // Move ret and test that it was moved from and that ret2 got the
    275         // original value.
    276         auto ret2 = std::move(ret);
    277         assert(ret() == true);
    278         assert(ret2() == false);
    279         assert(ret2(42) == false);
    280     }
    281     {
    282         using T = CopyCallable<bool>;
    283         T value(false);
    284         using RetT = decltype(std::not_fn(value));
    285         static_assert(std::is_move_constructible<RetT>::value, "");
    286         static_assert(std::is_copy_constructible<RetT>::value, "");
    287         static_assert(!std::is_move_assignable<RetT>::value, "");
    288         static_assert(!std::is_copy_assignable<RetT>::value, "");
    289         auto ret = std::not_fn(value);
    290         // test that value is unchanged (copied not moved)
    291         assert(value.value == false);
    292         // test 'ret' has the original value
    293         assert(ret() == true);
    294         assert(ret(42, 100) == true);
    295         // move from 'ret' and check that 'ret2' has the original value.
    296         auto ret2 = std::move(ret);
    297         assert(ret() == false);
    298         assert(ret2() == true);
    299         assert(ret2("abc") == true);
    300     }
    301     {
    302         using T = CopyAssignableWrapper;
    303         T value(true);
    304         T value2(false);
    305         using RetT = decltype(std::not_fn(value));
    306         static_assert(std::is_move_constructible<RetT>::value, "");
    307         static_assert(std::is_copy_constructible<RetT>::value, "");
    308         LIBCPP_STATIC_ASSERT(std::is_move_assignable<RetT>::value, "");
    309         LIBCPP_STATIC_ASSERT(std::is_copy_assignable<RetT>::value, "");
    310         auto ret = std::not_fn(value);
    311         assert(ret() == false);
    312         auto ret2 = std::not_fn(value2);
    313         assert(ret2() == true);
    314 #if defined(_LIBCPP_VERSION)
    315         ret = ret2;
    316         assert(ret() == true);
    317         assert(ret2() == true);
    318 #endif // _LIBCPP_VERSION
    319     }
    320     {
    321         using T = MoveAssignableWrapper;
    322         T value(true);
    323         T value2(false);
    324         using RetT = decltype(std::not_fn(std::move(value)));
    325         static_assert(std::is_move_constructible<RetT>::value, "");
    326         static_assert(!std::is_copy_constructible<RetT>::value, "");
    327         LIBCPP_STATIC_ASSERT(std::is_move_assignable<RetT>::value, "");
    328         static_assert(!std::is_copy_assignable<RetT>::value, "");
    329         auto ret = std::not_fn(std::move(value));
    330         assert(ret() == false);
    331         auto ret2 = std::not_fn(std::move(value2));
    332         assert(ret2() == true);
    333 #if defined(_LIBCPP_VERSION)
    334         ret = std::move(ret2);
    335         assert(ret() == true);
    336 #endif // _LIBCPP_VERSION
    337     }
    338 }
    339 
    340 void return_type_tests()
    341 {
    342     using std::is_same;
    343     {
    344         using T = CopyCallable<bool>;
    345         auto ret = std::not_fn(T{false});
    346         static_assert(is_same<decltype(ret()), bool>::value, "");
    347         static_assert(is_same<decltype(ret("abc")), bool>::value, "");
    348         assert(ret() == true);
    349     }
    350     {
    351         using T = CopyCallable<ExplicitBool>;
    352         auto ret = std::not_fn(T{true});
    353         static_assert(is_same<decltype(ret()), bool>::value, "");
    354         static_assert(is_same<decltype(ret(std::string("abc"))), bool>::value, "");
    355         assert(ret() == false);
    356     }
    357     {
    358         using T = CopyCallable<EvilBool>;
    359         auto ret = std::not_fn(T{false});
    360         static_assert(is_same<decltype(ret()), EvilBool>::value, "");
    361         EvilBool::bang_called = 0;
    362         auto value_ret = ret();
    363         assert(EvilBool::bang_called == 1);
    364         assert(value_ret.value == true);
    365         ret();
    366         assert(EvilBool::bang_called == 2);
    367     }
    368 }
    369 
    370 // Other tests only test using objects with call operators. Test various
    371 // other callable types here.
    372 void other_callable_types_test()
    373 {
    374     { // test with function pointer
    375         auto ret = std::not_fn(returns_true);
    376         assert(ret() == false);
    377     }
    378     { // test with lambda
    379         auto returns_value = [](bool value) { return value; };
    380         auto ret = std::not_fn(returns_value);
    381         assert(ret(true) == false);
    382         assert(ret(false) == true);
    383     }
    384     { // test with pointer to member function
    385         MemFunCallable mt(true);
    386         const MemFunCallable mf(false);
    387         auto ret = std::not_fn(&MemFunCallable::return_value);
    388         assert(ret(mt) == false);
    389         assert(ret(mf) == true);
    390         assert(ret(&mt) == false);
    391         assert(ret(&mf) == true);
    392     }
    393     { // test with pointer to member function
    394         MemFunCallable mt(true);
    395         MemFunCallable mf(false);
    396         auto ret = std::not_fn(&MemFunCallable::return_value_nc);
    397         assert(ret(mt) == false);
    398         assert(ret(mf) == true);
    399         assert(ret(&mt) == false);
    400         assert(ret(&mf) == true);
    401     }
    402     { // test with pointer to member data
    403         MemFunCallable mt(true);
    404         const MemFunCallable mf(false);
    405         auto ret = std::not_fn(&MemFunCallable::value);
    406         assert(ret(mt) == false);
    407         assert(ret(mf) == true);
    408         assert(ret(&mt) == false);
    409         assert(ret(&mf) == true);
    410     }
    411 }
    412 
    413 void throws_in_constructor_test()
    414 {
    415 #ifndef TEST_HAS_NO_EXCEPTIONS
    416     struct ThrowsOnCopy {
    417       ThrowsOnCopy(ThrowsOnCopy const&) {
    418         throw 42;
    419       }
    420       ThrowsOnCopy() = default;
    421       bool operator()() const {
    422         assert(false);
    423 #if defined(TEST_COMPILER_C1XX)
    424         __assume(0);
    425 #else
    426         __builtin_unreachable();
    427 #endif
    428       }
    429     };
    430     {
    431         ThrowsOnCopy cp;
    432         try {
    433             (void)std::not_fn(cp);
    434             assert(false);
    435         } catch (int const& value) {
    436             assert(value == 42);
    437         }
    438     }
    439 #endif
    440 }
    441 
    442 void call_operator_sfinae_test() {
    443     { // wrong number of arguments
    444         using T = decltype(std::not_fn(returns_true));
    445         static_assert(std::is_invocable<T>::value, ""); // callable only with no args
    446         static_assert(!std::is_invocable<T, bool>::value, "");
    447     }
    448     { // violates const correctness (member function pointer)
    449         using T = decltype(std::not_fn(&MemFunCallable::return_value_nc));
    450         static_assert(std::is_invocable<T, MemFunCallable&>::value, "");
    451         static_assert(!std::is_invocable<T, const MemFunCallable&>::value, "");
    452     }
    453     { // violates const correctness (call object)
    454         using Obj = CopyCallable<bool>;
    455         using NCT = decltype(std::not_fn(Obj{true}));
    456         using CT = const NCT;
    457         static_assert(std::is_invocable<NCT>::value, "");
    458         static_assert(!std::is_invocable<CT>::value, "");
    459     }
    460     { // returns bad type with no operator!
    461         auto fn = [](auto x) { return x; };
    462         using T = decltype(std::not_fn(fn));
    463         static_assert(std::is_invocable<T, bool>::value, "");
    464         static_assert(!std::is_invocable<T, std::string>::value, "");
    465     }
    466 }
    467 
    468 void call_operator_forwarding_test()
    469 {
    470     using Fn = ForwardingCallObject;
    471     auto obj = std::not_fn(Fn{});
    472     const auto& c_obj = obj;
    473     { // test zero args
    474         obj();
    475         assert(Fn::check_call<>(CT_NonConst | CT_LValue));
    476         std::move(obj)();
    477         assert(Fn::check_call<>(CT_NonConst | CT_RValue));
    478         c_obj();
    479         assert(Fn::check_call<>(CT_Const | CT_LValue));
    480         std::move(c_obj)();
    481         assert(Fn::check_call<>(CT_Const | CT_RValue));
    482     }
    483     { // test value categories
    484         int x = 42;
    485         const int cx = 42;
    486         obj(x);
    487         assert(Fn::check_call<int&>(CT_NonConst | CT_LValue));
    488         obj(cx);
    489         assert(Fn::check_call<const int&>(CT_NonConst | CT_LValue));
    490         obj(std::move(x));
    491         assert(Fn::check_call<int&&>(CT_NonConst | CT_LValue));
    492         obj(std::move(cx));
    493         assert(Fn::check_call<const int&&>(CT_NonConst | CT_LValue));
    494         obj(42);
    495         assert(Fn::check_call<int&&>(CT_NonConst | CT_LValue));
    496     }
    497     { // test value categories - rvalue
    498         int x = 42;
    499         const int cx = 42;
    500         std::move(obj)(x);
    501         assert(Fn::check_call<int&>(CT_NonConst | CT_RValue));
    502         std::move(obj)(cx);
    503         assert(Fn::check_call<const int&>(CT_NonConst | CT_RValue));
    504         std::move(obj)(std::move(x));
    505         assert(Fn::check_call<int&&>(CT_NonConst | CT_RValue));
    506         std::move(obj)(std::move(cx));
    507         assert(Fn::check_call<const int&&>(CT_NonConst | CT_RValue));
    508         std::move(obj)(42);
    509         assert(Fn::check_call<int&&>(CT_NonConst | CT_RValue));
    510     }
    511     { // test value categories - const call
    512         int x = 42;
    513         const int cx = 42;
    514         c_obj(x);
    515         assert(Fn::check_call<int&>(CT_Const | CT_LValue));
    516         c_obj(cx);
    517         assert(Fn::check_call<const int&>(CT_Const | CT_LValue));
    518         c_obj(std::move(x));
    519         assert(Fn::check_call<int&&>(CT_Const | CT_LValue));
    520         c_obj(std::move(cx));
    521         assert(Fn::check_call<const int&&>(CT_Const | CT_LValue));
    522         c_obj(42);
    523         assert(Fn::check_call<int&&>(CT_Const | CT_LValue));
    524     }
    525     { // test value categories - const call rvalue
    526         int x = 42;
    527         const int cx = 42;
    528         std::move(c_obj)(x);
    529         assert(Fn::check_call<int&>(CT_Const | CT_RValue));
    530         std::move(c_obj)(cx);
    531         assert(Fn::check_call<const int&>(CT_Const | CT_RValue));
    532         std::move(c_obj)(std::move(x));
    533         assert(Fn::check_call<int&&>(CT_Const | CT_RValue));
    534         std::move(c_obj)(std::move(cx));
    535         assert(Fn::check_call<const int&&>(CT_Const | CT_RValue));
    536         std::move(c_obj)(42);
    537         assert(Fn::check_call<int&&>(CT_Const | CT_RValue));
    538     }
    539     { // test multi arg
    540         const double y = 3.14;
    541         std::string s = "abc";
    542         obj(42, std::move(y), s, std::string{"foo"});
    543         Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_NonConst | CT_LValue);
    544         std::move(obj)(42, std::move(y), s, std::string{"foo"});
    545         Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_NonConst | CT_RValue);
    546         c_obj(42, std::move(y), s, std::string{"foo"});
    547         Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_Const  | CT_LValue);
    548         std::move(c_obj)(42, std::move(y), s, std::string{"foo"});
    549         Fn::check_call<int&&, const double&&, std::string&, std::string&&>(CT_Const  | CT_RValue);
    550     }
    551 }
    552 
    553 void call_operator_noexcept_test()
    554 {
    555     {
    556         using T = ConstCallable<bool>;
    557         T value(true);
    558         auto ret = std::not_fn(value);
    559         static_assert(!noexcept(ret()), "call should not be noexcept");
    560         auto const& cret = ret;
    561         static_assert(!noexcept(cret()), "call should not be noexcept");
    562     }
    563     {
    564         using T = NoExceptCallable<bool>;
    565         T value(true);
    566         auto ret = std::not_fn(value);
    567         LIBCPP_STATIC_ASSERT(noexcept(!_VSTD::__invoke(value)), "");
    568 #if TEST_STD_VER > 14
    569         static_assert(noexcept(!std::invoke(value)), "");
    570 #endif
    571         static_assert(noexcept(ret()), "call should be noexcept");
    572         auto const& cret = ret;
    573         static_assert(noexcept(cret()), "call should be noexcept");
    574     }
    575     {
    576         using T = NoExceptCallable<NoExceptEvilBool>;
    577         T value(true);
    578         auto ret = std::not_fn(value);
    579         static_assert(noexcept(ret()), "call should not be noexcept");
    580         auto const& cret = ret;
    581         static_assert(noexcept(cret()), "call should not be noexcept");
    582     }
    583     {
    584         using T = NoExceptCallable<EvilBool>;
    585         T value(true);
    586         auto ret = std::not_fn(value);
    587         static_assert(!noexcept(ret()), "call should not be noexcept");
    588         auto const& cret = ret;
    589         static_assert(!noexcept(cret()), "call should not be noexcept");
    590     }
    591 }
    592 
    593 void test_lwg2767() {
    594     // See https://cplusplus.github.io/LWG/lwg-defects.html#2767
    595     struct Abstract { virtual void f() const = 0; };
    596     struct Derived : public Abstract { void f() const {} };
    597     struct F { bool operator()(Abstract&&) { return false; } };
    598     {
    599         Derived d;
    600         Abstract &a = d;
    601         bool b = std::not_fn(F{})(std::move(a));
    602         assert(b);
    603     }
    604 }
    605 
    606 int main()
    607 {
    608     constructor_tests();
    609     return_type_tests();
    610     other_callable_types_test();
    611     throws_in_constructor_test();
    612     call_operator_sfinae_test(); // somewhat of an extension
    613     call_operator_forwarding_test();
    614     call_operator_noexcept_test();
    615     test_lwg2767();
    616 }
    617