1 | // |
2 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
3 | // See https://llvm.org/LICENSE.txt for license information. |
4 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
5 | // |
6 | //===----------------------------------------------------------------------===// |
7 | |
8 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
9 | // XFAIL: !has-64-bit-atomics |
10 | |
11 | // integral-type operator++(int) const noexcept; |
12 | // integral-type operator--(int) const noexcept; |
13 | // integral-type operator++() const noexcept; |
14 | // integral-type operator--() const noexcept; |
15 | |
16 | #include <atomic> |
17 | #include <cassert> |
18 | #include <concepts> |
19 | #include <type_traits> |
20 | #include <utility> |
21 | |
22 | #include "atomic_helpers.h" |
23 | #include "test_macros.h" |
24 | |
25 | template <typename T> |
26 | concept has_pre_increment_operator = requires { ++std::declval<T const>(); }; |
27 | |
28 | template <typename T> |
29 | concept has_post_increment_operator = requires { std::declval<T const>()++; }; |
30 | |
31 | template <typename T> |
32 | concept has_pre_decrement_operator = requires { --std::declval<T const>(); }; |
33 | |
34 | template <typename T> |
35 | concept has_post_decrement_operator = requires { std::declval<T const>()--; }; |
36 | |
37 | template <typename T> |
38 | constexpr bool does_not_have_increment_nor_decrement_operators() { |
39 | return !has_pre_increment_operator<T> && !has_pre_decrement_operator<T> && !has_post_increment_operator<T> && |
40 | !has_post_decrement_operator<T>; |
41 | } |
42 | |
43 | template <typename T> |
44 | struct TestDoesNotHaveIncrementDecrement { |
45 | void operator()() const { static_assert(does_not_have_increment_nor_decrement_operators<std::atomic_ref<T>>()); } |
46 | }; |
47 | |
48 | template <typename T> |
49 | struct TestIncrementDecrement { |
50 | void operator()() const { |
51 | if constexpr (std::is_integral_v<T>) { |
52 | T x(T(1)); |
53 | std::atomic_ref<T> const a(x); |
54 | |
55 | { |
56 | std::same_as<T> decltype(auto) y = ++a; |
57 | assert(y == T(2)); |
58 | assert(x == T(2)); |
59 | ASSERT_NOEXCEPT(++a); |
60 | } |
61 | |
62 | { |
63 | std::same_as<T> decltype(auto) y = --a; |
64 | assert(y == T(1)); |
65 | assert(x == T(1)); |
66 | ASSERT_NOEXCEPT(--a); |
67 | } |
68 | |
69 | { |
70 | std::same_as<T> decltype(auto) y = a++; |
71 | assert(y == T(1)); |
72 | assert(x == T(2)); |
73 | ASSERT_NOEXCEPT(a++); |
74 | } |
75 | |
76 | { |
77 | std::same_as<T> decltype(auto) y = a--; |
78 | assert(y == T(2)); |
79 | assert(x == T(1)); |
80 | ASSERT_NOEXCEPT(a--); |
81 | } |
82 | } else if constexpr (std::is_pointer_v<T>) { |
83 | using U = std::remove_pointer_t<T>; |
84 | U t[9] = {}; |
85 | T p{&t[1]}; |
86 | std::atomic_ref<T> const a(p); |
87 | |
88 | { |
89 | std::same_as<T> decltype(auto) y = ++a; |
90 | assert(y == &t[2]); |
91 | assert(p == &t[2]); |
92 | ASSERT_NOEXCEPT(++a); |
93 | } |
94 | |
95 | { |
96 | std::same_as<T> decltype(auto) y = --a; |
97 | assert(y == &t[1]); |
98 | assert(p == &t[1]); |
99 | ASSERT_NOEXCEPT(--a); |
100 | } |
101 | |
102 | { |
103 | std::same_as<T> decltype(auto) y = a++; |
104 | assert(y == &t[1]); |
105 | assert(p == &t[2]); |
106 | ASSERT_NOEXCEPT(a++); |
107 | } |
108 | |
109 | { |
110 | std::same_as<T> decltype(auto) y = a--; |
111 | assert(y == &t[2]); |
112 | assert(p == &t[1]); |
113 | ASSERT_NOEXCEPT(a--); |
114 | } |
115 | } else { |
116 | static_assert(std::is_void_v<T>); |
117 | } |
118 | } |
119 | }; |
120 | |
121 | int main(int, char**) { |
122 | TestEachIntegralType<TestIncrementDecrement>()(); |
123 | |
124 | TestEachFloatingPointType<TestDoesNotHaveIncrementDecrement>()(); |
125 | |
126 | TestEachPointerType<TestIncrementDecrement>()(); |
127 | |
128 | TestDoesNotHaveIncrementDecrement<bool>()(); |
129 | TestDoesNotHaveIncrementDecrement<UserAtomicType>()(); |
130 | TestDoesNotHaveIncrementDecrement<LargeUserAtomicType>()(); |
131 | |
132 | return 0; |
133 | } |
134 | |