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