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 | #include "callable_types.h" |
21 | |
22 | /////////////////////////////////////////////////////////////////////////////// |
23 | // BOOL TEST TYPES |
24 | /////////////////////////////////////////////////////////////////////////////// |
25 | |
26 | struct 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 | |
37 | private: |
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 | |
45 | public: |
46 | bool value; |
47 | }; |
48 | |
49 | int EvilBool::bang_called = 0; |
50 | |
51 | struct ExplicitBool { |
52 | ExplicitBool(ExplicitBool const&) = default; |
53 | ExplicitBool(ExplicitBool&&) = default; |
54 | |
55 | constexpr explicit operator bool() const { return value; } |
56 | |
57 | private: |
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 | |
71 | struct 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 | |
87 | TEST_CONSTEXPR_CXX20 |
88 | bool 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 from |
100 | 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 the |
105 | // 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 value |
123 | 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 rvalue |
131 | 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 | |
163 | void 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 various |
194 | // other callable types here. |
195 | TEST_CONSTEXPR_CXX20 |
196 | bool other_callable_types_test() |
197 | { |
198 | { // test with function pointer |
199 | auto ret = std::not_fn(returns_true); |
200 | assert(ret() == false); |
201 | } |
202 | { // test with lambda |
203 | auto returns_value = [](bool value) { return value; }; |
204 | auto ret = std::not_fn(fn&: returns_value); |
205 | assert(ret(true) == false); |
206 | assert(ret(false) == true); |
207 | } |
208 | { // test with pointer to member function |
209 | 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 function |
218 | 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 data |
227 | 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 | |
238 | void throws_in_constructor_test() |
239 | { |
240 | #ifndef TEST_HAS_NO_EXCEPTIONS |
241 | struct ThrowsOnCopy { |
242 | ThrowsOnCopy(ThrowsOnCopy const&) { |
243 | throw 42; |
244 | } |
245 | ThrowsOnCopy() = default; |
246 | bool operator()() const { |
247 | assert(false); |
248 | #ifdef TEST_COMPILER_MSVC |
249 | __assume(0); |
250 | #else |
251 | __builtin_unreachable(); |
252 | #endif |
253 | } |
254 | }; |
255 | { |
256 | ThrowsOnCopy cp; |
257 | try { |
258 | (void)std::not_fn(fn&: cp); |
259 | assert(false); |
260 | } catch (int const& value) { |
261 | assert(value == 42); |
262 | } |
263 | } |
264 | #endif |
265 | } |
266 | |
267 | TEST_CONSTEXPR_CXX20 |
268 | bool call_operator_sfinae_test() { |
269 | { // wrong number of arguments |
270 | using T = decltype(std::not_fn(returns_true)); |
271 | static_assert(std::is_invocable<T>::value, "" ); // callable only with no args |
272 | 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&: 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 | |
295 | TEST_CONSTEXPR_CXX20 |
296 | bool 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 args |
303 | 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 categories |
313 | 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 - rvalue |
327 | 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 call |
341 | 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 rvalue |
355 | 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 arg |
369 | 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 | |
384 | TEST_CONSTEXPR_CXX20 |
385 | bool 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 > 14 |
401 | static_assert(noexcept(!std::invoke(value)), "" ); |
402 | #endif |
403 | 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 | |
426 | TEST_CONSTEXPR_CXX20 |
427 | bool test_lwg2767() { |
428 | // See https://cplusplus.github.io/LWG/lwg-defects.html#2767 |
429 | 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(fn: F{})(std::move(a)); |
436 | assert(b); |
437 | } |
438 | return true; |
439 | } |
440 | |
441 | int 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 extension |
448 | call_operator_forwarding_test(); |
449 | call_operator_noexcept_test(); |
450 | test_lwg2767(); |
451 | |
452 | #if TEST_STD_VER >= 20 |
453 | static_assert(constructor_tests()); |
454 | static_assert(other_callable_types_test()); |
455 | static_assert(call_operator_sfinae_test()); // somewhat of an extension |
456 | static_assert(call_operator_forwarding_test()); |
457 | static_assert(call_operator_noexcept_test()); |
458 | static_assert(test_lwg2767()); |
459 | #endif |
460 | |
461 | return 0; |
462 | } |
463 | |