This implements the significant changes from P0558R1 for C++17, adding nested typedefs and making it ill-formed to do arithmetic on std::atomic<T*> if !is_object<T>::value.
We currently support such arithmetic for std::atomic<void*>, and even have a test checking it, so I've only made it ill-formed for C++17 mode. I'd like to deprecate that extension for GCC 8 and make it ill-formed in all modes at some point. PR 69769 points out that we also allow that arithmetic for pointers to functions, which is just crazy. The unimplemented parts of the paper are changing the non-member functions to use the new std::atomic<T>::value_type and std::atomic<T>::difference_type types for the parameters, so they are non-deduced contexts. That would be too big a change to make now, so we can revisit that for GCC 8 too. PR libstdc++/69769 * include/bits/atomic_base.h (__atomic_base): Add new typedefs for C++17. * include/std/atomic (atomic<bool>, atomic<T>, atomic<T*>): Likewise. (atomic<T*>::operator++, atomic<T*>::operator--) (atomic<T*>::operator+=, atomic<T*>::operator-=) (atomic<T*>::fetch_add, atomic<T*>::fetch_sub): Add static assertion to enforce C++17 requirement on pointer arithmetic. * testsuite/29_atomics/atomic/60695.cc: Adjust dg-error lineno. * testsuite/29_atomics/atomic/69769.cc: New test. * testsuite/29_atomics/atomic/operators/pointer_partial_void.cc: Disable test for C++17. * testsuite/29_atomics/atomic/requirements/typedefs.cc: New test. * testsuite/29_atomics/atomic_integral/requirements/typedefs.cc: New test. Tested powerpc64le-linux, with all -std=gnu++?? options. I plan to commit this tomorrow.
commit 8b28c80f1c250d87d8a30a99a2f190f2e17a8981 Author: Jonathan Wakely <jwak...@redhat.com> Date: Wed Apr 19 16:30:18 2017 +0100 Implement C++17 changes to std::atomic (P0558R1 partial) PR libstdc++/69769 * include/bits/atomic_base.h (__atomic_base): Add new typedefs for C++17. * include/std/atomic (atomic<bool>, atomic<T>, atomic<T*>): Likewise. (atomic<T*>::operator++, atomic<T*>::operator--) (atomic<T*>::operator+=, atomic<T*>::operator-=) (atomic<T*>::fetch_add, atomic<T*>::fetch_sub): Add static assertion to enforce C++17 requirement on pointer arithmetic. * testsuite/29_atomics/atomic/60695.cc: Adjust dg-error lineno. * testsuite/29_atomics/atomic/69769.cc: New test. * testsuite/29_atomics/atomic/operators/pointer_partial_void.cc: Disable test for C++17. * testsuite/29_atomics/atomic/requirements/typedefs.cc: New test. * testsuite/29_atomics/atomic_integral/requirements/typedefs.cc: New test. diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index e79ff67..93f85c3 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -237,6 +237,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _ITp> struct __atomic_base { +#if __cplusplus > 201402L + using value_type = _ITp; + using difference_type = value_type; +#endif + private: typedef _ITp __int_type; diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic index 5b252a4..47d3004 100644 --- a/libstdc++-v3/include/std/atomic +++ b/libstdc++-v3/include/std/atomic @@ -62,6 +62,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<> struct atomic<bool> { +#if __cplusplus > 201402L + using value_type = bool; +#endif + private: __atomic_base<bool> _M_base; @@ -173,6 +177,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> struct atomic { +#if __cplusplus > 201402L + using value_type = _Tp; +#endif + private: // Align 1/2/4/8/16-byte types to at least their size. static constexpr int _S_min_alignment @@ -351,6 +359,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> struct atomic<_Tp*> { +#if __cplusplus > 201402L + using value_type = _Tp*; + using difference_type = ptrdiff_t; +#endif + typedef _Tp* __pointer_type; typedef __atomic_base<_Tp*> __base_type; __base_type _M_b; @@ -379,51 +392,111 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __pointer_type operator++(int) noexcept - { return _M_b++; } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b++; + } __pointer_type operator++(int) volatile noexcept - { return _M_b++; } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b++; + } __pointer_type operator--(int) noexcept - { return _M_b--; } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b--; + } __pointer_type operator--(int) volatile noexcept - { return _M_b--; } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b--; + } __pointer_type operator++() noexcept - { return ++_M_b; } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return ++_M_b; + } __pointer_type operator++() volatile noexcept - { return ++_M_b; } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return ++_M_b; + } __pointer_type operator--() noexcept - { return --_M_b; } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return --_M_b; + } __pointer_type operator--() volatile noexcept - { return --_M_b; } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return --_M_b; + } __pointer_type operator+=(ptrdiff_t __d) noexcept - { return _M_b.operator+=(__d); } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b.operator+=(__d); + } __pointer_type operator+=(ptrdiff_t __d) volatile noexcept - { return _M_b.operator+=(__d); } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b.operator+=(__d); + } __pointer_type operator-=(ptrdiff_t __d) noexcept - { return _M_b.operator-=(__d); } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b.operator-=(__d); + } __pointer_type operator-=(ptrdiff_t __d) volatile noexcept - { return _M_b.operator-=(__d); } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b.operator-=(__d); + } bool is_lock_free() const noexcept @@ -522,22 +595,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __pointer_type fetch_add(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) noexcept - { return _M_b.fetch_add(__d, __m); } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b.fetch_add(__d, __m); + } __pointer_type fetch_add(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile noexcept - { return _M_b.fetch_add(__d, __m); } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b.fetch_add(__d, __m); + } __pointer_type fetch_sub(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) noexcept - { return _M_b.fetch_sub(__d, __m); } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b.fetch_sub(__d, __m); + } __pointer_type fetch_sub(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile noexcept - { return _M_b.fetch_sub(__d, __m); } + { +#if __cplusplus > 201402L + static_assert( is_object<_Tp>::value, "pointer to object type" ); +#endif + return _M_b.fetch_sub(__d, __m); + } }; diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc b/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc index b24daae..fd94338 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic/60695.cc @@ -27,4 +27,4 @@ struct X { char stuff[0]; // GNU extension, type has zero size }; -std::atomic<X> a; // { dg-error "not supported" "" { target *-*-* } 190 } +std::atomic<X> a; // { dg-error "not supported" "" { target *-*-* } 198 } diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/69769.cc b/libstdc++-v3/testsuite/29_atomics/atomic/69769.cc new file mode 100644 index 0000000..9724ea3 --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/69769.cc @@ -0,0 +1,79 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++1z } } + +#include <atomic> + +void +test01() +{ + std::atomic<void*> p; + p.fetch_add(1); // { dg-error "from here" } + p.fetch_sub(1); // { dg-error "from here" } + p += 1; // { dg-error "from here" } + p -= 1; // { dg-error "from here" } + ++p; // { dg-error "from here" } + p++; // { dg-error "from here" } + --p; // { dg-error "from here" } + p--; // { dg-error "from here" } +} + +void +test02() +{ + std::atomic<void(*)()> p; + p.fetch_add(1); // { dg-error "from here" } + p.fetch_sub(1); // { dg-error "from here" } + p += 1; // { dg-error "from here" } + p -= 1; // { dg-error "from here" } + ++p; // { dg-error "from here" } + p++; // { dg-error "from here" } + --p; // { dg-error "from here" } + p--; // { dg-error "from here" } +} + +void +test03() +{ + volatile std::atomic<void*> p; + p.fetch_add(1); // { dg-error "from here" } + p.fetch_sub(1); // { dg-error "from here" } + p += 1; // { dg-error "from here" } + p -= 1; // { dg-error "from here" } + ++p; // { dg-error "from here" } + p++; // { dg-error "from here" } + --p; // { dg-error "from here" } + p--; // { dg-error "from here" } +} + +void +test04() +{ + volatile std::atomic<void(*)()> p; + p.fetch_add(1); // { dg-error "from here" } + p.fetch_sub(1); // { dg-error "from here" } + p += 1; // { dg-error "from here" } + p -= 1; // { dg-error "from here" } + ++p; // { dg-error "from here" } + p++; // { dg-error "from here" } + --p; // { dg-error "from here" } + p--; // { dg-error "from here" } +} + +// { dg-prune-output "static assertion failed" } diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc index 1fb4c9c..a0c84bb 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc @@ -1,4 +1,4 @@ -// { dg-do run { target c++11 } } +// { dg-do run { target { c++11_only || c++14_only } } } // { dg-require-atomic-builtins "" } // Copyright (C) 2012-2017 Free Software Foundation, Inc. diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/requirements/typedefs.cc b/libstdc++-v3/testsuite/29_atomics/atomic/requirements/typedefs.cc new file mode 100644 index 0000000..ebbde5e --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/requirements/typedefs.cc @@ -0,0 +1,35 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++1z } } + +#include <atomic> + +template<typename T> +constexpr bool check() +{ + typename std::atomic<T>::value_type* pv = (T*)nullptr; + typename std::atomic<T>::difference_type* pd = (std::ptrdiff_t*)nullptr; + return true; +} + +static_assert( check<int*>(), "" ); +static_assert( check<void*>(), "" ); +static_assert( check<void(*)()>(), "" ); +struct X { }; +static_assert( check<X*>(), "" ); diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/typedefs.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/typedefs.cc new file mode 100644 index 0000000..8cf605e --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/typedefs.cc @@ -0,0 +1,38 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++1z } } + +#include <atomic> + +template<typename T> +constexpr bool check() +{ + typename std::atomic<T>::value_type* pv = (T*)nullptr; + typename std::atomic<T>::difference_type* pd = (T*)nullptr; + return true; +} + +static_assert( check<signed short>(), "" ); +static_assert( check<unsigned short>(), "" ); +static_assert( check<signed int>(), "" ); +static_assert( check<unsigned int>(), "" ); +static_assert( check<signed long>(), "" ); +static_assert( check<unsigned long>(), "" ); +static_assert( check<signed long long>(), "" ); +static_assert( check<unsigned long long>(), "" );