134 lines · cpp
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-exception5//6//===----------------------------------------------------------------------===//7 8// UNSUPPORTED: c++03, c++11, c++14, c++179// XFAIL: !has-64-bit-atomics10 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