libstdc++: Value-initialize std::atomic for C++20 (P0883R2)
authorJonathan Wakely <jwakely@redhat.com>
Sat, 11 Jan 2020 00:11:54 +0000 (00:11 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Mon, 13 Jan 2020 13:22:28 +0000 (13:22 +0000)
This implements the new requirements for C++20 that std::atomic should
initialize the atomic variable in its default constructor.

This patch does not add the deprecated attribute to atomic_init, but
that should be done at some point as it's deprecated in C++20.

The paper also deprecates the ATOMIC_FLAG_INIT macro, although we can't
apply the deprecated attribute to a macro.

PR libstdc++/58605
* include/bits/atomic_base.h (__cpp_lib_atomic_value_initialization):
Define.
(__atomic_flag_base, __atomic_base, __atomic_base<_PTp*>)
(__atomic_float): Add default member initializer for C++20.
* include/std/atomic (atomic): Likewise.
(atomic::atomic()): Remove noexcept-specifier on default constructor.
* include/std/version (__cpp_lib_atomic_value_initialization): Define.
* testsuite/29_atomics/atomic/cons/assign_neg.cc: Adjust dg-error line
number.
* testsuite/29_atomics/atomic/cons/copy_neg.cc: Likewise.
* testsuite/29_atomics/atomic/cons/value_init.cc: New test.
* testsuite/29_atomics/atomic_flag/cons/value_init.cc: New test.
* testsuite/29_atomics/atomic_flag/requirements/trivial.cc: Adjust
expected result for is_trivially_default_constructible.
* testsuite/29_atomics/atomic_float/requirements.cc: Likewise.
* testsuite/29_atomics/atomic_float/value_init.cc: New test.
* testsuite/29_atomics/atomic_integral/cons/assign_neg.cc: Likewise.
* testsuite/29_atomics/atomic_integral/cons/copy_neg.cc: Likewise.
* testsuite/29_atomics/atomic_integral/cons/value_init.cc
* testsuite/29_atomics/atomic_integral/requirements/trivial.cc: Adjust
expected results for is_trivially_default_constructible.
* testsuite/util/testsuite_common_types.h (has_trivial_dtor): Add
new test generator.

16 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/atomic_base.h
libstdc++-v3/include/std/atomic
libstdc++-v3/include/std/version
libstdc++-v3/testsuite/29_atomics/atomic/cons/assign_neg.cc
libstdc++-v3/testsuite/29_atomics/atomic/cons/copy_neg.cc
libstdc++-v3/testsuite/29_atomics/atomic/cons/value_init.cc [new file with mode: 0644]
libstdc++-v3/testsuite/29_atomics/atomic_flag/cons/value_init.cc [new file with mode: 0644]
libstdc++-v3/testsuite/29_atomics/atomic_flag/requirements/trivial.cc
libstdc++-v3/testsuite/29_atomics/atomic_float/requirements.cc
libstdc++-v3/testsuite/29_atomics/atomic_float/value_init.cc [new file with mode: 0644]
libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/assign_neg.cc
libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/copy_neg.cc
libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/value_init.cc [new file with mode: 0644]
libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/trivial.cc
libstdc++-v3/testsuite/util/testsuite_common_types.h

index 79a5887f7d09c5720fb52828aca6f683d1932eaa..6d090f490ac19ac77540c94915b044612321e027 100644 (file)
@@ -1,3 +1,30 @@
+2020-01-13  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/58605
+       * include/bits/atomic_base.h (__cpp_lib_atomic_value_initialization):
+       Define.
+       (__atomic_flag_base, __atomic_base, __atomic_base<_PTp*>)
+       (__atomic_float): Add default member initializer for C++20.
+       * include/std/atomic (atomic): Likewise.
+       (atomic::atomic()): Remove noexcept-specifier on default constructor.
+       * include/std/version (__cpp_lib_atomic_value_initialization): Define.
+       * testsuite/29_atomics/atomic/cons/assign_neg.cc: Adjust dg-error line
+       number.
+       * testsuite/29_atomics/atomic/cons/copy_neg.cc: Likewise.
+       * testsuite/29_atomics/atomic/cons/value_init.cc: New test.
+       * testsuite/29_atomics/atomic_flag/cons/value_init.cc: New test.
+       * testsuite/29_atomics/atomic_flag/requirements/trivial.cc: Adjust
+       expected result for is_trivially_default_constructible.
+       * testsuite/29_atomics/atomic_float/requirements.cc: Likewise.
+       * testsuite/29_atomics/atomic_float/value_init.cc: New test.
+       * testsuite/29_atomics/atomic_integral/cons/assign_neg.cc: Likewise.
+       * testsuite/29_atomics/atomic_integral/cons/copy_neg.cc: Likewise.
+       * testsuite/29_atomics/atomic_integral/cons/value_init.cc
+       * testsuite/29_atomics/atomic_integral/requirements/trivial.cc: Adjust
+       expected results for is_trivially_default_constructible.
+       * testsuite/util/testsuite_common_types.h (has_trivial_dtor): Add
+       new test generator.
+
 2020-01-10  Jonathan Wakely  <jwakely@redhat.com>
 
        * testsuite/util/testsuite_iterators.h: Improve comment.
index 3d7b72cb61fa2e9df390d85cd6cd1a8247d2206e..87fe0bd6000ea5bb4f6e86ab174c434f1c9c3b3f 100644 (file)
@@ -139,6 +139,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _IntTp>
     struct __atomic_base;
 
+#if __cplusplus <= 201703L
+# define _GLIBCXX20_INIT(I)
+#else
+# define __cpp_lib_atomic_value_initialization 201911L
+# define _GLIBCXX20_INIT(I) = I
+#endif
 
 #define ATOMIC_VAR_INIT(_VI) { _VI }
 
@@ -169,7 +175,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   struct __atomic_flag_base
   {
-    __atomic_flag_data_type _M_i;
+    __atomic_flag_data_type _M_i _GLIBCXX20_INIT({});
   };
 
   _GLIBCXX_END_EXTERN_C
@@ -267,7 +273,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static constexpr int _S_alignment =
        sizeof(_ITp) > alignof(_ITp) ? sizeof(_ITp) : alignof(_ITp);
 
-      alignas(_S_alignment) __int_type _M_i;
+      alignas(_S_alignment) __int_type _M_i _GLIBCXX20_INIT(0);
 
     public:
       __atomic_base() noexcept = default;
@@ -595,7 +601,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     private:
       typedef _PTp*    __pointer_type;
 
-      __pointer_type   _M_p;
+      __pointer_type   _M_p _GLIBCXX20_INIT(nullptr);
 
       // Factored out to facilitate explicit specialization.
       constexpr ptrdiff_t
@@ -1175,8 +1181,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return __atomic_impl::__sub_fetch_flt(&_M_fp, __i); }
 
     private:
-      alignas(_S_alignment) _Fp _M_fp;
+      alignas(_S_alignment) _Fp _M_fp _GLIBCXX20_INIT(0);
     };
+#undef _GLIBCXX20_INIT
 
   template<typename _Tp,
           bool = is_integral_v<_Tp>, bool = is_floating_point_v<_Tp>>
index 6177c477be16389433e690d455aaf1c1d1dff993..66c62381e6b07701edee34928e49d104fbae9daf 100644 (file)
@@ -165,6 +165,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
   };
 
+#if __cplusplus <= 201703L
+# define _GLIBCXX20_INIT(I)
+#else
+# define _GLIBCXX20_INIT(I) = I
+#endif
 
   /**
    *  @brief Generic atomic type, primary class template.
@@ -185,7 +190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       static constexpr int _S_alignment
         = _S_min_alignment > alignof(_Tp) ? _S_min_alignment : alignof(_Tp);
 
-      alignas(_S_alignment) _Tp _M_i;
+      alignas(_S_alignment) _Tp _M_i _GLIBCXX20_INIT(_Tp());
 
       static_assert(__is_trivially_copyable(_Tp),
                    "std::atomic requires a trivially copyable type");
@@ -194,7 +199,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                    "Incomplete or zero-sized types are not supported");
 
     public:
-      atomic() noexcept = default;
+      atomic() = default;
       ~atomic() noexcept = default;
       atomic(const atomic&) = delete;
       atomic& operator=(const atomic&) = delete;
@@ -348,7 +353,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return compare_exchange_strong(__e, __i, __m,
                                        __cmpexch_failure_order(__m)); }
     };
-
+#undef _GLIBCXX20_INIT
 
   /// Partial specialization for pointer types.
   template<typename _Tp>
index 81b9112e02a7ebdec3e5d97947fe2e7e1da0ca13..d8a97767453542bc03cb6457c52c762994395836 100644 (file)
 #if __cplusplus > 201703L
 // c++2a
 #define __cpp_lib_atomic_ref 201806L
+#define __cpp_lib_atomic_value_initialization 201911L
 #define __cpp_lib_bitops 201907L
 #define __cpp_lib_bounded_array_traits 201902L
 #if __cpp_concepts
index 306ea5acc1b2e2ca19ac6f7babb14d252a5f0577..d93eacc786312453c85c80d4b1774c7e636dda9e 100644 (file)
@@ -27,5 +27,5 @@ int main()
   return 0;
 }
 
-// { dg-error "deleted" "" { target *-*-* } 639 }
+// { dg-error "deleted" "" { target *-*-* } 659 }
 // { dg-prune-output "include" }
index 5032912fc935683385d48f0e959eb77999c55fda..03ecdd42ae15d7a9a45b71dc4d8553cc8915f82a 100644 (file)
@@ -27,5 +27,5 @@ int main()
   return 0;
 }
 
-// { dg-error "deleted" "" { target *-*-* } 678 }
+// { dg-error "deleted" "" { target *-*-* } 698 }
 // { dg-prune-output "include" }
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/cons/value_init.cc b/libstdc++-v3/testsuite/29_atomics/atomic/cons/value_init.cc
new file mode 100644 (file)
index 0000000..8620c7c
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 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++2a" }
+// { dg-do run { target c++2a } }
+
+#include <atomic>
+
+#ifndef __cpp_lib_atomic_value_initialization
+# error "Feature test macro for atomic value-initialization is missing"
+#elif __cpp_lib_atomic_value_initialization < 201911L
+# error "Feature test macro for atomic value-initialization has wrong value"
+#endif
+
+#include <testsuite_hooks.h>
+
+struct A
+{
+  constexpr A() : val(42) { }
+  int val;
+};
+
+constexpr std::atomic<A> a;
+
+void
+test01()
+{
+  VERIFY(a.load().val == 42);
+  static_assert(!std::is_nothrow_default_constructible_v<std::atomic<A>>);
+}
+
+struct B
+{
+  constexpr B() noexcept : val(99) { }
+  int val;
+};
+
+constexpr std::atomic<B> b;
+
+void
+test02()
+{
+  VERIFY(b.load().val == 99);
+  static_assert(std::is_nothrow_default_constructible_v<std::atomic<B>>);
+}
+
+constexpr std::atomic<int*> c;
+
+void
+test03()
+{
+  VERIFY(c.load() == nullptr);
+  static_assert(std::is_nothrow_default_constructible_v<std::atomic<int*>>);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/cons/value_init.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/cons/value_init.cc
new file mode 100644 (file)
index 0000000..547e406
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (C) 2020 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++2a" }
+// { dg-do run { target c++2a } }
+
+#include <atomic>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::atomic_flag f;
+  VERIFY(!f.test_and_set());
+  VERIFY(f.test_and_set());
+  static_assert(std::is_nothrow_default_constructible_v<std::atomic_flag>);
+}
+
+int
+main()
+{
+  test01();
+}
index d08adf8af43835f26b8db39f101ab913daaf57e9..ecf7ace1976d044e114d9cab5ac2fd5d066a0add 100644 (file)
 
 void test01()
 {
+#if __cplusplus <= 201703L
   __gnu_test::has_trivial_cons_dtor test;
+#else
+  __gnu_test::has_trivial_dtor test;
+#endif
   test.operator()<std::atomic_flag>();
 }
index 1599655a9b6d0d4ced031ff9efad5e70dfb0f686..b8a556291d113fe8f6b2d48a050ba0f1e5e4ec32 100644 (file)
@@ -25,7 +25,7 @@ test01()
 {
   using A = std::atomic<float>;
   static_assert( std::is_standard_layout_v<A> );
-  static_assert( std::is_trivially_default_constructible_v<A> );
+  static_assert( !std::is_trivially_default_constructible_v<A> );
   static_assert( std::is_trivially_destructible_v<A> );
   static_assert( std::is_same_v<A::value_type, float> );
   static_assert( std::is_same_v<A::difference_type, A::value_type> );
@@ -41,7 +41,7 @@ test02()
 {
   using A = std::atomic<double>;
   static_assert( std::is_standard_layout_v<A> );
-  static_assert( std::is_trivially_default_constructible_v<A> );
+  static_assert( !std::is_trivially_default_constructible_v<A> );
   static_assert( std::is_trivially_destructible_v<A> );
   static_assert( std::is_same_v<A::value_type, double> );
   static_assert( std::is_same_v<A::difference_type, A::value_type> );
@@ -57,7 +57,7 @@ test03()
 {
   using A = std::atomic<long double>;
   static_assert( std::is_standard_layout_v<A> );
-  static_assert( std::is_trivially_default_constructible_v<A> );
+  static_assert( !std::is_trivially_default_constructible_v<A> );
   static_assert( std::is_trivially_destructible_v<A> );
   static_assert( std::is_same_v<A::value_type, long double> );
   static_assert( std::is_same_v<A::difference_type, A::value_type> );
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/value_init.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/value_init.cc
new file mode 100644 (file)
index 0000000..237c0dd
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (C) 2020 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++2a" }
+// { dg-do run { target c++2a } }
+
+#include <atomic>
+#include <testsuite_hooks.h>
+
+constexpr std::atomic<double> a;
+
+void
+test01()
+{
+  VERIFY(a.load() == 0);
+  static_assert(std::is_nothrow_default_constructible_v<std::atomic<double>>);
+}
+
+int
+main()
+{
+  test01();
+}
index d842761d2f7d36c4c5c64dac8a05f6f487381594..3c164b4870196e0080e63baa3a443bafad24f104 100644 (file)
@@ -28,5 +28,5 @@ int main()
   return 0;
 }
 
-// { dg-error "deleted" "" { target *-*-* } 639 }
+// { dg-error "deleted" "" { target *-*-* } 659 }
 // { dg-prune-output "include" }
index a83a214278f32ff50d61a03723b9774ebf357c57..0131ba2c915f5d4ed5282ee1a5efc975b40d3112 100644 (file)
@@ -28,5 +28,5 @@ int main()
   return 0;
 }
 
-// { dg-error "deleted" "" { target *-*-* } 678 }
+// { dg-error "deleted" "" { target *-*-* } 698 }
 // { dg-prune-output "include" }
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/value_init.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/value_init.cc
new file mode 100644 (file)
index 0000000..fa1eb7a
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (C) 2020 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++2a" }
+// { dg-do run { target c++2a } }
+
+#include <atomic>
+#include <testsuite_hooks.h>
+
+constexpr std::atomic<int> a;
+
+void
+test01()
+{
+  VERIFY(a.load() == 0);
+  static_assert(std::is_nothrow_default_constructible_v<std::atomic<int>>);
+}
+
+int
+main()
+{
+  test01();
+}
index aac121874005ba6173c7e744e952ad1b4f39b25d..36aa248552fdc8227d10c6c44c8dcf2902ff0bcf 100644 (file)
 
 void test01()
 {
+#if __cplusplus <= 201703L
   __gnu_test::has_trivial_cons_dtor test;
+#else
+  __gnu_test::has_trivial_dtor test;
+#endif
   __gnu_cxx::typelist::apply_generator(test,
                                       __gnu_test::atomic_integrals::type());
 }
index ab3d961f0af96076ac1c60c7d612caa676dc9c42..2795df36ca32015a6e53178c1ee488373c987fc8 100644 (file)
@@ -558,7 +558,6 @@ namespace __gnu_test
       }
   };
 
-  // Generator to test standard layout
   struct has_trivial_cons_dtor
   {
     template<typename _Tp>
@@ -582,6 +581,27 @@ namespace __gnu_test
       }
   };
 
+  struct has_trivial_dtor
+  {
+    template<typename _Tp>
+      void
+      operator()()
+      {
+       struct _Concept
+       {
+         void __constraint()
+         {
+           typedef std::is_trivially_destructible<_Tp> dtor_p;
+           static_assert(dtor_p::value, "destructor not trivial");
+         }
+       };
+
+       void (_Concept::*__x)() __attribute__((unused))
+         = &_Concept::__constraint;
+      }
+  };
+
+  // Generator to test standard layout
   struct standard_layout
   {
     template<typename _Tp>