142ba740aSDamien L-G // 242ba740aSDamien L-G // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 342ba740aSDamien L-G // See https://llvm.org/LICENSE.txt for license information. 442ba740aSDamien L-G // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 542ba740aSDamien L-G // 642ba740aSDamien L-G //===----------------------------------------------------------------------===// 742ba740aSDamien L-G 842ba740aSDamien L-G // UNSUPPORTED: c++03, c++11, c++14, c++17 942ba740aSDamien L-G // XFAIL: !has-64-bit-atomics 1042ba740aSDamien L-G 1142ba740aSDamien L-G // integral-type operator++(int) const noexcept; 1242ba740aSDamien L-G // integral-type operator--(int) const noexcept; 1342ba740aSDamien L-G // integral-type operator++() const noexcept; 1442ba740aSDamien L-G // integral-type operator--() const noexcept; 1542ba740aSDamien L-G 1642ba740aSDamien L-G #include <atomic> 1742ba740aSDamien L-G #include <cassert> 1842ba740aSDamien L-G #include <concepts> 1942ba740aSDamien L-G #include <type_traits> 2009e3a360SLouis Dionne #include <utility> 2142ba740aSDamien L-G 2242ba740aSDamien L-G #include "atomic_helpers.h" 2342ba740aSDamien L-G #include "test_macros.h" 2442ba740aSDamien L-G 2542ba740aSDamien L-G template <typename T> 2642ba740aSDamien L-G concept has_pre_increment_operator = requires { ++std::declval<T const>(); }; 2742ba740aSDamien L-G 2842ba740aSDamien L-G template <typename T> 2942ba740aSDamien L-G concept has_post_increment_operator = requires { std::declval<T const>()++; }; 3042ba740aSDamien L-G 3142ba740aSDamien L-G template <typename T> 3242ba740aSDamien L-G concept has_pre_decrement_operator = requires { --std::declval<T const>(); }; 3342ba740aSDamien L-G 3442ba740aSDamien L-G template <typename T> 3542ba740aSDamien L-G concept has_post_decrement_operator = requires { std::declval<T const>()--; }; 3642ba740aSDamien L-G 3742ba740aSDamien L-G template <typename T> 3842ba740aSDamien L-G constexpr bool does_not_have_increment_nor_decrement_operators() { 3942ba740aSDamien L-G return !has_pre_increment_operator<T> && !has_pre_decrement_operator<T> && !has_post_increment_operator<T> && 4042ba740aSDamien L-G !has_post_decrement_operator<T>; 4142ba740aSDamien L-G } 4242ba740aSDamien L-G 4342ba740aSDamien L-G template <typename T> 4442ba740aSDamien L-G struct TestDoesNotHaveIncrementDecrement { 45*19557a4cSDamien L-G void operator()() const { static_assert(does_not_have_increment_nor_decrement_operators<std::atomic_ref<T>>()); } 4642ba740aSDamien L-G }; 4742ba740aSDamien L-G 4842ba740aSDamien L-G template <typename T> 4942ba740aSDamien L-G struct TestIncrementDecrement { 5042ba740aSDamien L-G void operator()() const { 51*19557a4cSDamien L-G if constexpr (std::is_integral_v<T>) { 5242ba740aSDamien L-G T x(T(1)); 5342ba740aSDamien L-G std::atomic_ref<T> const a(x); 5442ba740aSDamien L-G 5542ba740aSDamien L-G { 5642ba740aSDamien L-G std::same_as<T> decltype(auto) y = ++a; 5742ba740aSDamien L-G assert(y == T(2)); 5842ba740aSDamien L-G assert(x == T(2)); 5942ba740aSDamien L-G ASSERT_NOEXCEPT(++a); 6042ba740aSDamien L-G } 6142ba740aSDamien L-G 6242ba740aSDamien L-G { 6342ba740aSDamien L-G std::same_as<T> decltype(auto) y = --a; 6442ba740aSDamien L-G assert(y == T(1)); 6542ba740aSDamien L-G assert(x == T(1)); 6642ba740aSDamien L-G ASSERT_NOEXCEPT(--a); 6742ba740aSDamien L-G } 6842ba740aSDamien L-G 6942ba740aSDamien L-G { 7042ba740aSDamien L-G std::same_as<T> decltype(auto) y = a++; 7142ba740aSDamien L-G assert(y == T(1)); 7242ba740aSDamien L-G assert(x == T(2)); 7342ba740aSDamien L-G ASSERT_NOEXCEPT(a++); 7442ba740aSDamien L-G } 7542ba740aSDamien L-G 7642ba740aSDamien L-G { 7742ba740aSDamien L-G std::same_as<T> decltype(auto) y = a--; 7842ba740aSDamien L-G assert(y == T(2)); 7942ba740aSDamien L-G assert(x == T(1)); 8042ba740aSDamien L-G ASSERT_NOEXCEPT(a--); 8142ba740aSDamien L-G } 82*19557a4cSDamien L-G } else if constexpr (std::is_pointer_v<T>) { 83*19557a4cSDamien L-G using U = std::remove_pointer_t<T>; 84*19557a4cSDamien L-G U t[9] = {}; 85*19557a4cSDamien L-G T p{&t[1]}; 86*19557a4cSDamien L-G std::atomic_ref<T> const a(p); 87*19557a4cSDamien L-G 88*19557a4cSDamien L-G { 89*19557a4cSDamien L-G std::same_as<T> decltype(auto) y = ++a; 90*19557a4cSDamien L-G assert(y == &t[2]); 91*19557a4cSDamien L-G assert(p == &t[2]); 92*19557a4cSDamien L-G ASSERT_NOEXCEPT(++a); 93*19557a4cSDamien L-G } 94*19557a4cSDamien L-G 95*19557a4cSDamien L-G { 96*19557a4cSDamien L-G std::same_as<T> decltype(auto) y = --a; 97*19557a4cSDamien L-G assert(y == &t[1]); 98*19557a4cSDamien L-G assert(p == &t[1]); 99*19557a4cSDamien L-G ASSERT_NOEXCEPT(--a); 100*19557a4cSDamien L-G } 101*19557a4cSDamien L-G 102*19557a4cSDamien L-G { 103*19557a4cSDamien L-G std::same_as<T> decltype(auto) y = a++; 104*19557a4cSDamien L-G assert(y == &t[1]); 105*19557a4cSDamien L-G assert(p == &t[2]); 106*19557a4cSDamien L-G ASSERT_NOEXCEPT(a++); 107*19557a4cSDamien L-G } 108*19557a4cSDamien L-G 109*19557a4cSDamien L-G { 110*19557a4cSDamien L-G std::same_as<T> decltype(auto) y = a--; 111*19557a4cSDamien L-G assert(y == &t[2]); 112*19557a4cSDamien L-G assert(p == &t[1]); 113*19557a4cSDamien L-G ASSERT_NOEXCEPT(a--); 114*19557a4cSDamien L-G } 115*19557a4cSDamien L-G } else { 116*19557a4cSDamien L-G static_assert(std::is_void_v<T>); 117*19557a4cSDamien L-G } 11842ba740aSDamien L-G } 11942ba740aSDamien L-G }; 12042ba740aSDamien L-G 12142ba740aSDamien L-G int main(int, char**) { 12242ba740aSDamien L-G TestEachIntegralType<TestIncrementDecrement>()(); 12342ba740aSDamien L-G 12442ba740aSDamien L-G TestEachFloatingPointType<TestDoesNotHaveIncrementDecrement>()(); 12542ba740aSDamien L-G 126*19557a4cSDamien L-G TestEachPointerType<TestIncrementDecrement>()(); 12742ba740aSDamien L-G 12842ba740aSDamien L-G TestDoesNotHaveIncrementDecrement<bool>()(); 12942ba740aSDamien L-G TestDoesNotHaveIncrementDecrement<UserAtomicType>()(); 13042ba740aSDamien L-G TestDoesNotHaveIncrementDecrement<LargeUserAtomicType>()(); 13142ba740aSDamien L-G 13242ba740aSDamien L-G return 0; 13342ba740aSDamien L-G } 134