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
25template <typename T>
26concept has_pre_increment_operator = requires { ++std::declval<T const>(); };
27
28template <typename T>
29concept has_post_increment_operator = requires { std::declval<T const>()++; };
30
31template <typename T>
32concept has_pre_decrement_operator = requires { --std::declval<T const>(); };
33
34template <typename T>
35concept has_post_decrement_operator = requires { std::declval<T const>()--; };
36
37template <typename T>
38constexpr 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
43template <typename T>
44struct TestDoesNotHaveIncrementDecrement {
45 void operator()() const { static_assert(does_not_have_increment_nor_decrement_operators<std::atomic_ref<T>>()); }
46};
47
48template <typename T>
49struct 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
121int 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

source code of libcxx/test/std/atomics/atomics.ref/increment_decrement.pass.cpp