diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -71,3 +71,23 @@ `CMAKE_POSITION_INDEPENDENT_CODE=ON` instead. - When the header is included, it will no longer include transitively. + +- The functions ``std::atomic::fetch_(add|sub)`` and + ``std::atomic_fetch_(add|sub)`` no longer accept a function pointer. This + isn't allowed by the Standard. 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. This isn't + allowed by the Standard. 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 @@ -1846,19 +1846,28 @@ _Tp* operator=(_Tp* __d) _NOEXCEPT {__base::store(__d); return __d;} + template _LIBCPP_INLINE_VISIBILITY - _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) - volatile _NOEXCEPT + typename enable_if::value && is_object<_Up>::value, _Up*>::type + fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {return __cxx_atomic_fetch_add(&this->__a_, __op, __m);} + + template _LIBCPP_INLINE_VISIBILITY - _Tp* fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT + typename enable_if::value && is_object<_Up>::value, _Up*>::type + fetch_add(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {return __cxx_atomic_fetch_add(&this->__a_, __op, __m);} + + template _LIBCPP_INLINE_VISIBILITY - _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) - volatile _NOEXCEPT + typename enable_if::value && is_object<_Up>::value, _Up*>::type + fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT {return __cxx_atomic_fetch_sub(&this->__a_, __op, __m);} + + template _LIBCPP_INLINE_VISIBILITY - _Tp* fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT + typename enable_if::value && is_object<_Up>::value, _Up*>::type + fetch_sub(ptrdiff_t __op, memory_order __m = memory_order_seq_cst) _NOEXCEPT {return __cxx_atomic_fetch_sub(&this->__a_, __op, __m);} _LIBCPP_INLINE_VISIBILITY @@ -2195,11 +2204,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); @@ -2207,70 +2212,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 +_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 -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 -{ - 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); } @@ -2279,40 +2238,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); } @@ -2321,40 +2254,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/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.verify.cpp b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/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:* {{no matching member function for call to 'fetch_add'}} + std::atomic_fetch_add(&obj, 0); + } + { + std::atomic obj; + // expected-error@atomic:* {{no matching member function for call to 'fetch_add'}} + 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:* {{no matching member function for call to 'fetch_add'}} + std::atomic_fetch_add(&fun, 0); + } + { + std::atomic fun; + // expected-error@atomic:* {{no matching member function for call to 'fetch_add'}} + 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/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_add_explicit.verify.cpp b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_add_explicit.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/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:* {{no matching member function for call to 'fetch_add'}} + std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed); + } + { + std::atomic obj; + // expected-error@atomic:* {{no matching member function for call to 'fetch_add'}} + 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:* {{no matching member function for call to 'fetch_add'}} + std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed); + } + { + std::atomic fun; + // expected-error@atomic:* {{no matching member function for call to 'fetch_add'}} + 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/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.verify.cpp b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/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:* {{no matching member function for call to 'fetch_sub'}} + std::atomic_fetch_sub(&obj, 0); + } + { + std::atomic obj; + // expected-error@atomic:* {{no matching member function for call to 'fetch_sub'}} + 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:* {{no matching member function for call to 'fetch_sub'}} + std::atomic_fetch_sub(&fun, 0); + } + { + std::atomic fun; + // expected-error@atomic:* {{no matching member function for call to 'fetch_sub'}} + 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/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)); } } diff --git a/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.verify.cpp b/libcxx/test/std/atomics/atomics.types.operations/atomics.types.operations.req/atomic_fetch_sub_explicit.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/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:* {{no matching member function for call to 'fetch_sub'}} + std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed); + } + { + std::atomic obj; + // expected-error@atomic:* {{no matching member function for call to 'fetch_sub'}} + 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:* {{no matching member function for call to 'fetch_sub'}} + std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed); + } + { + std::atomic fun; + // expected-error@atomic:* {{no matching member function for call to 'fetch_sub'}} + 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); + } +}