diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -57,3 +57,21 @@ - Building the libc++ shared or static library requires a C++ 20 capable compiler. Use ``-DLLVM_ENABLE_PROJECTS='clang;compiler-rt' -DLLVM_ENABLE_RUNTIMES='libcxx;libcxxabi'`` to build libc++ using a fresh build of Clang. + +- The functions ``std::atomic::fetch_(add|sub)`` and + ``std::atomic_fetch_(add|sub)`` no longer accept a function pointer. While + this is technically an API break, the invalid syntax isn't supported by + libstc++ and MSVC STL. See https://godbolt.org/z/49fvzz98d. + +- The call of the functions ``std::atomic_(add|sub)(std::atomic*, ...)`` + with the explicit template argument ``T`` are now ill-formed. While this is + technically an API break, the invalid syntax isn't supported by libstc++ and + MSVC STL. See https://godbolt.org/z/v9959re3v. + + Due to this change it's now possible to call these functions with the + explicit template argument ``T*``. This allows using the same syntax on the + major Standard library implementations. + See https://godbolt.org/z/oEfzPhTTb. + + Calls to these functions where the template argument was deduced by the + compiler are unaffected by this change. diff --git a/libcxx/include/atomic b/libcxx/include/atomic --- a/libcxx/include/atomic +++ b/libcxx/include/atomic @@ -1844,19 +1844,32 @@ {__base::store(__d); return __d;} _LIBCPP_INLINE_VISIBILITY - _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) - volatile _NOEXCEPT - {return __cxx_atomic_fetch_add(&this->__a_, __op, __m);} + _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + // __atomic_fetch_add accepts function pointers, guard against them. + static_assert(!is_function::type>::value, "Pointer to function isn't allowed"); + return __cxx_atomic_fetch_add(&this->__a_, __op, __m); + } + _LIBCPP_INLINE_VISIBILITY - _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT - {return __cxx_atomic_fetch_add(&this->__a_, __op, __m);} + _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + // __atomic_fetch_add accepts function pointers, guard against them. + static_assert(!is_function::type>::value, "Pointer to function isn't allowed"); + return __cxx_atomic_fetch_add(&this->__a_, __op, __m); + } + _LIBCPP_INLINE_VISIBILITY - _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) - volatile _NOEXCEPT - {return __cxx_atomic_fetch_sub(&this->__a_, __op, __m);} + _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT { + // __atomic_fetch_add accepts function pointers, guard against them. + static_assert(!is_function::type>::value, "Pointer to function isn't allowed"); + return __cxx_atomic_fetch_sub(&this->__a_, __op, __m); + } + _LIBCPP_INLINE_VISIBILITY - _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT - {return __cxx_atomic_fetch_sub(&this->__a_, __op, __m);} + _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT { + // __atomic_fetch_add accepts function pointers, guard against them. + static_assert(!is_function::type>::value, "Pointer to function isn't allowed"); + return __cxx_atomic_fetch_sub(&this->__a_, __op, __m); + } _LIBCPP_INLINE_VISIBILITY _Tp* operator++(int) volatile _NOEXCEPT {return fetch_add(1);} @@ -2192,11 +2205,7 @@ template _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_integral<_Tp>::value && !is_same<_Tp, bool>::value && !is_const<_Tp>::value, - _Tp ->::type +_Tp atomic_fetch_add(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT { return __o->fetch_add(__op); @@ -2204,70 +2213,24 @@ template _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_integral<_Tp>::value && !is_same<_Tp, bool>::value && !is_const<_Tp>::value, - _Tp ->::type +_Tp atomic_fetch_add(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT { return __o->fetch_add(__op); } -template -_LIBCPP_INLINE_VISIBILITY -_Tp* -atomic_fetch_add(volatile atomic<_Tp*>* __o, typename atomic<_Tp*>::difference_type __op) _NOEXCEPT -{ - return __o->fetch_add(__op); -} - -template -_LIBCPP_INLINE_VISIBILITY -_Tp* -atomic_fetch_add(atomic<_Tp*>* __o, typename atomic<_Tp*>::difference_type __op) _NOEXCEPT -{ - return __o->fetch_add(__op); -} - // atomic_fetch_add_explicit template _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_integral<_Tp>::value && !is_same<_Tp, bool>::value && !is_const<_Tp>::value, - _Tp ->::type -atomic_fetch_add_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT -{ - return __o->fetch_add(__op, __m); -} - -template -_LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_integral<_Tp>::value && !is_same<_Tp, bool>::value && !is_const<_Tp>::value, - _Tp ->::type -atomic_fetch_add_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT +_Tp atomic_fetch_add_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT { return __o->fetch_add(__op, __m); } template _LIBCPP_INLINE_VISIBILITY -_Tp* -atomic_fetch_add_explicit(volatile atomic<_Tp*>* __o, typename atomic<_Tp*>::difference_type __op, memory_order __m) _NOEXCEPT -{ - return __o->fetch_add(__op, __m); -} - -template -_LIBCPP_INLINE_VISIBILITY -_Tp* -atomic_fetch_add_explicit(atomic<_Tp*>* __o, typename atomic<_Tp*>::difference_type __op, memory_order __m) _NOEXCEPT +_Tp atomic_fetch_add_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT { return __o->fetch_add(__op, __m); } @@ -2276,40 +2239,14 @@ template _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_integral<_Tp>::value && !is_same<_Tp, bool>::value && !is_const<_Tp>::value, - _Tp ->::type -atomic_fetch_sub(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT -{ - return __o->fetch_sub(__op); -} - -template -_LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_integral<_Tp>::value && !is_same<_Tp, bool>::value && !is_const<_Tp>::value, - _Tp ->::type -atomic_fetch_sub(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT -{ - return __o->fetch_sub(__op); -} - -template -_LIBCPP_INLINE_VISIBILITY -_Tp* -atomic_fetch_sub(volatile atomic<_Tp*>* __o, typename atomic<_Tp*>::difference_type __op) _NOEXCEPT +_Tp atomic_fetch_sub(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT { return __o->fetch_sub(__op); } template _LIBCPP_INLINE_VISIBILITY -_Tp* -atomic_fetch_sub(atomic<_Tp*>* __o, typename atomic<_Tp*>::difference_type __op) _NOEXCEPT +_Tp atomic_fetch_sub(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op) _NOEXCEPT { return __o->fetch_sub(__op); } @@ -2318,40 +2255,14 @@ template _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_integral<_Tp>::value && !is_same<_Tp, bool>::value && !is_const<_Tp>::value, - _Tp ->::type -atomic_fetch_sub_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT -{ - return __o->fetch_sub(__op, __m); -} - -template -_LIBCPP_INLINE_VISIBILITY -typename enable_if -< - is_integral<_Tp>::value && !is_same<_Tp, bool>::value && !is_const<_Tp>::value, - _Tp ->::type -atomic_fetch_sub_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT -{ - return __o->fetch_sub(__op, __m); -} - -template -_LIBCPP_INLINE_VISIBILITY -_Tp* -atomic_fetch_sub_explicit(volatile atomic<_Tp*>* __o, typename atomic<_Tp*>::difference_type __op, memory_order __m) _NOEXCEPT +_Tp atomic_fetch_sub_explicit(volatile atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT { return __o->fetch_sub(__op, __m); } template _LIBCPP_INLINE_VISIBILITY -_Tp* -atomic_fetch_sub_explicit(atomic<_Tp*>* __o, typename atomic<_Tp*>::difference_type __op, memory_order __m) _NOEXCEPT +_Tp atomic_fetch_sub_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::difference_type __op, memory_order __m) _NOEXCEPT { return __o->fetch_sub(__op, __m); } diff --git a/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add.verify.cpp b/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add.verify.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-threads + +// + +// template +// T* atomic_fetch_add(volatile atomic* obj, ptrdiff_t op) +// template +// T* atomic_fetch_add(atomic* obj, ptrdiff_t op); + +#include + +void void_pointer() { + { + volatile std::atomic obj; + // expected-error@atomic:* {{incomplete type 'void' where a complete type is required}} + std::atomic_fetch_add(&obj, 0); + } + { + std::atomic obj; + // expected-error@atomic:* {{incomplete type 'void' where a complete type is required}} + std::atomic_fetch_add(&obj, 0); + } +} + +struct Incomplete; + +void pointer_to_incomplete_type() { + { + volatile std::atomic obj; + // expected-error@atomic:* {{incomplete type 'Incomplete' where a complete type is required}} + std::atomic_fetch_add(&obj, 0); + } + { + std::atomic obj; + // expected-error@atomic:* {{incomplete type 'Incomplete' where a complete type is required}} + std::atomic_fetch_add(&obj, 0); + } +} + +void function_pointer() { + { + volatile std::atomic fun; + // expected-error@atomic:* {{static_assert failed due to requirement '!is_function::value' "Pointer to function isn't allowed"}} + std::atomic_fetch_add(&fun, 0); + } + { + std::atomic fun; + // expected-error@atomic:* {{static_assert failed due to requirement '!is_function::value' "Pointer to function isn't allowed"}} + std::atomic_fetch_add(&fun, 0); + } +} + +struct S { + void fun(int); +}; + +void member_function_pointer() { + { + volatile std::atomic fun; + // expected-error@atomic:* {{no member named 'fetch_add' in}} + std::atomic_fetch_add(&fun, 0); + } + { + std::atomic fun; + // expected-error@atomic:* {{no member named 'fetch_add' in}} + std::atomic_fetch_add(&fun, 0); + } +} diff --git a/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add_explicit.verify.cpp b/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add_explicit.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add_explicit.verify.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-threads + +// + +// template +// T* +// atomic_fetch_add_explicit(volatile atomic* obj, ptrdiff_t op, +// memory_order m); +// template +// T* +// atomic_fetch_add_explicit(atomic* obj, ptrdiff_t op, memory_order m); + +#include + +void void_pointer() { + { + volatile std::atomic obj; + // expected-error@atomic:* {{incomplete type 'void' where a complete type is required}} + std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed); + } + { + std::atomic obj; + // expected-error@atomic:* {{incomplete type 'void' where a complete type is required}} + std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed); + } +} + +struct Incomplete; + +void pointer_to_incomplete_type() { + { + volatile std::atomic obj; + // expected-error@atomic:* {{incomplete type 'Incomplete' where a complete type is required}} + std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed); + } + { + std::atomic obj; + // expected-error@atomic:* {{incomplete type 'Incomplete' where a complete type is required}} + std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed); + } +} + +void function_pointer() { + { + volatile std::atomic fun; + // expected-error@atomic:* {{static_assert failed due to requirement '!is_function::value' "Pointer to function isn't allowed"}} + std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed); + } + { + std::atomic fun; + // expected-error@atomic:* {{static_assert failed due to requirement '!is_function::value' "Pointer to function isn't allowed"}} + std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed); + } +} + +struct S { + void fun(int); +}; + +void member_function_pointer() { + { + volatile std::atomic fun; + // expected-error@atomic:* {{no member named 'fetch_add' in}} + std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed); + } + { + std::atomic fun; + // expected-error@atomic:* {{no member named 'fetch_add' in}} + std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed); + } +} diff --git a/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub.verify.cpp b/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub.verify.cpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-threads + +// + +// template +// T* atomic_fetch_sub(volatile atomic* obj, ptrdiff_t op) +// template +// T* atomic_fetch_sub(atomic* obj, ptrdiff_t op); + +#include + +void void_pointer() { + { + volatile std::atomic obj; + // expected-error@atomic:* {{incomplete type 'void' where a complete type is required}} + std::atomic_fetch_sub(&obj, 0); + } + { + std::atomic obj; + // expected-error@atomic:* {{incomplete type 'void' where a complete type is required}} + std::atomic_fetch_sub(&obj, 0); + } +} + +struct Incomplete; + +void pointer_to_incomplete_type() { + { + volatile std::atomic obj; + // expected-error@atomic:* {{incomplete type 'Incomplete' where a complete type is required}} + std::atomic_fetch_sub(&obj, 0); + } + { + std::atomic obj; + // expected-error@atomic:* {{incomplete type 'Incomplete' where a complete type is required}} + std::atomic_fetch_sub(&obj, 0); + } +} + +void function_pointer() { + { + volatile std::atomic fun; + // expected-error@atomic:* {{static_assert failed due to requirement '!is_function::value' "Pointer to function isn't allowed"}} + std::atomic_fetch_sub(&fun, 0); + } + { + std::atomic fun; + // expected-error@atomic:* {{static_assert failed due to requirement '!is_function::value' "Pointer to function isn't allowed"}} + std::atomic_fetch_sub(&fun, 0); + } +} + +struct S { + void fun(int); +}; + +void member_function_pointer() { + { + volatile std::atomic fun; + // expected-error@atomic:* {{no member named 'fetch_sub' in}} + std::atomic_fetch_sub(&fun, 0); + } + { + std::atomic fun; + // expected-error@atomic:* {{no member named 'fetch_sub' in}} + std::atomic_fetch_sub(&fun, 0); + } +} diff --git a/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.verify.cpp b/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.verify.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-threads + +// + +// template +// T* +// atomic_fetch_sub_explicit(volatile atomic* obj, ptrdiff_t op, +// memory_order m); +// template +// T* +// atomic_fetch_sub_explicit(atomic* obj, ptrdiff_t op, memory_order m); + +#include + +void void_pointer() { + { + volatile std::atomic obj; + // expected-error@atomic:* {{incomplete type 'void' where a complete type is required}} + std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed); + } + { + std::atomic obj; + // expected-error@atomic:* {{incomplete type 'void' where a complete type is required}} + std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed); + } +} + +struct Incomplete; + +void pointer_to_incomplete_type() { + { + volatile std::atomic obj; + // expected-error@atomic:* {{incomplete type 'Incomplete' where a complete type is required}} + std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed); + } + { + std::atomic obj; + // expected-error@atomic:* {{incomplete type 'Incomplete' where a complete type is required}} + std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed); + } +} + +void function_pointer() { + { + volatile std::atomic fun; + // expected-error@atomic:* {{static_assert failed due to requirement '!is_function::value' "Pointer to function isn't allowed"}} + std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed); + } + { + std::atomic fun; + // expected-error@atomic:* {{static_assert failed due to requirement '!is_function::value' "Pointer to function isn't allowed"}} + std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed); + } +} + +struct S { + void fun(int); +}; + +void member_function_pointer() { + { + volatile std::atomic fun; + // expected-error@atomic:* {{no member named 'fetch_sub' in}} + std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed); + } + { + std::atomic fun; + // expected-error@atomic:* {{no member named 'fetch_sub' in}} + std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed); + } +} diff --git a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add.pass.cpp b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add.pass.cpp --- a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add.pass.cpp +++ b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add.pass.cpp @@ -20,11 +20,11 @@ // // template // T* -// atomic_fetch_add(volatile atomic* obj, ptrdiff_t op); +// atomic_fetch_add(volatile atomic* obj, typename atomic::difference_type) noexcept; // // template // T* -// atomic_fetch_add(atomic* obj, ptrdiff_t op); +// atomic_fetch_add(atomic* obj, typename atomic::difference_type) noexcept; #include #include @@ -41,12 +41,14 @@ A t(T(1)); assert(std::atomic_fetch_add(&t, T(2)) == T(1)); assert(t == T(3)); + ASSERT_NOEXCEPT(std::atomic_fetch_add(&t, 0)); } { typedef std::atomic A; volatile A t(T(1)); assert(std::atomic_fetch_add(&t, T(2)) == T(1)); assert(t == T(3)); + ASSERT_NOEXCEPT(std::atomic_fetch_add(&t, 0)); } } }; @@ -57,26 +59,22 @@ { typedef std::atomic A; typedef typename std::remove_pointer::type X; - A t(T(1 * sizeof(X))); - assert(std::atomic_fetch_add(&t, 2) == T(1*sizeof(X))); -#ifdef _LIBCPP_VERSION // libc++ is nonconforming - std::atomic_fetch_add(&t, 0); -#else + X a[3] = {0}; + A t(&a[0]); + assert(std::atomic_fetch_add(&t, 2) == &a[0]); std::atomic_fetch_add(&t, 0); -#endif // _LIBCPP_VERSION - assert(t == T(3*sizeof(X))); + assert(t == &a[2]); + ASSERT_NOEXCEPT(std::atomic_fetch_add(&t, 0)); } { typedef std::atomic A; typedef typename std::remove_pointer::type X; - volatile A t(T(1 * sizeof(X))); - assert(std::atomic_fetch_add(&t, 2) == T(1*sizeof(X))); -#ifdef _LIBCPP_VERSION // libc++ is nonconforming - std::atomic_fetch_add(&t, 0); -#else + X a[3] = {0}; + volatile A t(&a[0]); + assert(std::atomic_fetch_add(&t, 2) == &a[0]); std::atomic_fetch_add(&t, 0); -#endif // _LIBCPP_VERSION - assert(t == T(3*sizeof(X))); + assert(t == &a[2]); + ASSERT_NOEXCEPT(std::atomic_fetch_add(&t, 0)); } } diff --git a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add_explicit.pass.cpp b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add_explicit.pass.cpp --- a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add_explicit.pass.cpp +++ b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add_explicit.pass.cpp @@ -42,6 +42,7 @@ assert(std::atomic_fetch_add_explicit(&t, T(2), std::memory_order_seq_cst) == T(1)); assert(t == T(3)); + ASSERT_NOEXCEPT(std::atomic_fetch_add_explicit(&t, 0, std::memory_order_relaxed)); } { typedef std::atomic A; @@ -49,6 +50,7 @@ assert(std::atomic_fetch_add_explicit(&t, T(2), std::memory_order_seq_cst) == T(1)); assert(t == T(3)); + ASSERT_NOEXCEPT(std::atomic_fetch_add_explicit(&t, 0, std::memory_order_relaxed)); } } }; @@ -60,28 +62,22 @@ { typedef std::atomic A; typedef typename std::remove_pointer::type X; - A t(T(1 * sizeof(X))); - assert(std::atomic_fetch_add_explicit(&t, 2, - std::memory_order_seq_cst) == T(1*sizeof(X))); -#ifdef _LIBCPP_VERSION // libc++ is not conforming - std::atomic_fetch_add_explicit(&t, 0, std::memory_order_relaxed); -#else + X a[3] = {0}; + A t(&a[0]); + assert(std::atomic_fetch_add_explicit(&t, 2, std::memory_order_seq_cst) == &a[0]); std::atomic_fetch_add_explicit(&t, 0, std::memory_order_relaxed); -#endif // _LIBCPP_VERSION - assert(t == T(3*sizeof(X))); + assert(t == &a[2]); + ASSERT_NOEXCEPT(std::atomic_fetch_add_explicit(&t, 0, std::memory_order_relaxed)); } { typedef std::atomic A; typedef typename std::remove_pointer::type X; - volatile A t(T(1 * sizeof(X))); - assert(std::atomic_fetch_add_explicit(&t, 2, - std::memory_order_seq_cst) == T(1*sizeof(X))); -#ifdef _LIBCPP_VERSION // libc++ is not conforming - std::atomic_fetch_add_explicit(&t, 0, std::memory_order_relaxed); -#else + X a[3] = {0}; + volatile A t(&a[0]); + assert(std::atomic_fetch_add_explicit(&t, 2, std::memory_order_seq_cst) == &a[0]); std::atomic_fetch_add_explicit(&t, 0, std::memory_order_relaxed); -#endif // _LIBCPP_VERSION - assert(t == T(3*sizeof(X))); + assert(t == &a[2]); + ASSERT_NOEXCEPT(std::atomic_fetch_add_explicit(&t, 0, std::memory_order_relaxed)); } } diff --git a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub.pass.cpp b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub.pass.cpp --- a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub.pass.cpp +++ b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub.pass.cpp @@ -41,12 +41,14 @@ A t(T(3)); assert(std::atomic_fetch_sub(&t, T(2)) == T(3)); assert(t == T(1)); + ASSERT_NOEXCEPT(std::atomic_fetch_sub(&t, 0)); } { typedef std::atomic A; volatile A t(T(3)); assert(std::atomic_fetch_sub(&t, T(2)) == T(3)); assert(t == T(1)); + ASSERT_NOEXCEPT(std::atomic_fetch_sub(&t, 0)); } } }; @@ -57,26 +59,22 @@ { typedef std::atomic A; typedef typename std::remove_pointer::type X; - A t(T(3 * sizeof(X))); - assert(std::atomic_fetch_sub(&t, 2) == T(3*sizeof(X))); -#ifdef _LIBCPP_VERSION // libc++ is nonconforming - std::atomic_fetch_sub(&t, 0); -#else + X a[3] = {0}; + A t(&a[2]); + assert(std::atomic_fetch_sub(&t, 2) == &a[2]); std::atomic_fetch_sub(&t, 0); -#endif // _LIBCPP_VERSION - assert(t == T(1*sizeof(X))); + assert(t == &a[0]); + ASSERT_NOEXCEPT(std::atomic_fetch_sub(&t, 0)); } { typedef std::atomic A; typedef typename std::remove_pointer::type X; - volatile A t(T(3 * sizeof(X))); - assert(std::atomic_fetch_sub(&t, 2) == T(3*sizeof(X))); -#ifdef _LIBCPP_VERSION // libc++ is nonconforming - std::atomic_fetch_sub(&t, 0); -#else + X a[3] = {0}; + volatile A t(&a[2]); + assert(std::atomic_fetch_sub(&t, 2) == &a[2]); std::atomic_fetch_sub(&t, 0); -#endif // _LIBCPP_VERSION - assert(t == T(1*sizeof(X))); + assert(t == &a[0]); + ASSERT_NOEXCEPT(std::atomic_fetch_sub(&t, 0)); } } diff --git a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.pass.cpp b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.pass.cpp --- a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.pass.cpp +++ b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.pass.cpp @@ -43,6 +43,7 @@ assert(std::atomic_fetch_sub_explicit(&t, T(2), std::memory_order_seq_cst) == T(3)); assert(t == T(1)); + ASSERT_NOEXCEPT(std::atomic_fetch_sub_explicit(&t, 0, std::memory_order_relaxed)); } { typedef std::atomic A; @@ -50,6 +51,7 @@ assert(std::atomic_fetch_sub_explicit(&t, T(2), std::memory_order_seq_cst) == T(3)); assert(t == T(1)); + ASSERT_NOEXCEPT(std::atomic_fetch_sub_explicit(&t, 0, std::memory_order_relaxed)); } } }; @@ -60,28 +62,22 @@ { typedef std::atomic A; typedef typename std::remove_pointer::type X; - A t(T(3 * sizeof(X))); - assert(std::atomic_fetch_sub_explicit(&t, 2, - std::memory_order_seq_cst) == T(3*sizeof(X))); -#ifdef _LIBCPP_VERSION // libc++ is nonconforming - std::atomic_fetch_sub_explicit(&t, 0, std::memory_order_relaxed); -#else + X a[3] = {0}; + A t(&a[2]); + assert(std::atomic_fetch_sub_explicit(&t, 2, std::memory_order_seq_cst) == &a[2]); std::atomic_fetch_sub_explicit(&t, 0, std::memory_order_relaxed); -#endif // _LIBCPP_VERSION - assert(t == T(1*sizeof(X))); + assert(t == &a[0]); + ASSERT_NOEXCEPT(std::atomic_fetch_sub_explicit(&t, 0, std::memory_order_relaxed)); } { typedef std::atomic A; typedef typename std::remove_pointer::type X; - volatile A t(T(3 * sizeof(X))); - assert(std::atomic_fetch_sub_explicit(&t, 2, - std::memory_order_seq_cst) == T(3*sizeof(X))); -#ifdef _LIBCPP_VERSION // libc++ is nonconforming - std::atomic_fetch_sub_explicit(&t, 0, std::memory_order_relaxed); -#else + X a[3] = {0}; + volatile A t(&a[2]); + assert(std::atomic_fetch_sub_explicit(&t, 2, std::memory_order_seq_cst) == &a[2]); std::atomic_fetch_sub_explicit(&t, 0, std::memory_order_relaxed); -#endif // _LIBCPP_VERSION - assert(t == T(1*sizeof(X))); + assert(t == &a[0]); + ASSERT_NOEXCEPT(std::atomic_fetch_sub_explicit(&t, 0, std::memory_order_relaxed)); } }