From e4379a931d140a71b36eaecceace319837fda321 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Sat, 11 Jan 2020 00:11:54 +0000 Subject: [PATCH] libstdc++: Value-initialize std::atomic for C++20 (P0883R2) 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. --- libstdc++-v3/ChangeLog | 27 +++++++ libstdc++-v3/include/bits/atomic_base.h | 15 +++- libstdc++-v3/include/std/atomic | 11 ++- libstdc++-v3/include/std/version | 1 + .../29_atomics/atomic/cons/assign_neg.cc | 2 +- .../29_atomics/atomic/cons/copy_neg.cc | 2 +- .../29_atomics/atomic/cons/value_init.cc | 76 +++++++++++++++++++ .../29_atomics/atomic_flag/cons/value_init.cc | 37 +++++++++ .../atomic_flag/requirements/trivial.cc | 4 + .../29_atomics/atomic_float/requirements.cc | 6 +- .../29_atomics/atomic_float/value_init.cc | 37 +++++++++ .../atomic_integral/cons/assign_neg.cc | 2 +- .../atomic_integral/cons/copy_neg.cc | 2 +- .../atomic_integral/cons/value_init.cc | 37 +++++++++ .../atomic_integral/requirements/trivial.cc | 4 + .../testsuite/util/testsuite_common_types.h | 22 +++++- 16 files changed, 270 insertions(+), 15 deletions(-) create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic/cons/value_init.cc create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_flag/cons/value_init.cc create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_float/value_init.cc create mode 100644 libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/value_init.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 79a5887f7d0..6d090f490ac 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,30 @@ +2020-01-13 Jonathan Wakely + + 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 * testsuite/util/testsuite_iterators.h: Improve comment. diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index 3d7b72cb61f..87fe0bd6000 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -139,6 +139,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template 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, bool = is_floating_point_v<_Tp>> diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic index 6177c477be1..66c62381e6b 100644 --- a/libstdc++-v3/include/std/atomic +++ b/libstdc++-v3/include/std/atomic @@ -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 diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index 81b9112e02a..d8a97767453 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -164,6 +164,7 @@ #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 diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/cons/assign_neg.cc b/libstdc++-v3/testsuite/29_atomics/atomic/cons/assign_neg.cc index 306ea5acc1b..d93eacc7863 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic/cons/assign_neg.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic/cons/assign_neg.cc @@ -27,5 +27,5 @@ int main() return 0; } -// { dg-error "deleted" "" { target *-*-* } 639 } +// { dg-error "deleted" "" { target *-*-* } 659 } // { dg-prune-output "include" } diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/cons/copy_neg.cc b/libstdc++-v3/testsuite/29_atomics/atomic/cons/copy_neg.cc index 5032912fc93..03ecdd42ae1 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic/cons/copy_neg.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic/cons/copy_neg.cc @@ -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 index 00000000000..8620c7cd22a --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic/cons/value_init.cc @@ -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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include + +#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 + +struct A +{ + constexpr A() : val(42) { } + int val; +}; + +constexpr std::atomic a; + +void +test01() +{ + VERIFY(a.load().val == 42); + static_assert(!std::is_nothrow_default_constructible_v>); +} + +struct B +{ + constexpr B() noexcept : val(99) { } + int val; +}; + +constexpr std::atomic b; + +void +test02() +{ + VERIFY(b.load().val == 99); + static_assert(std::is_nothrow_default_constructible_v>); +} + +constexpr std::atomic c; + +void +test03() +{ + VERIFY(c.load() == nullptr); + static_assert(std::is_nothrow_default_constructible_v>); +} + +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 index 00000000000..547e4067ff3 --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/cons/value_init.cc @@ -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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +void +test01() +{ + std::atomic_flag f; + VERIFY(!f.test_and_set()); + VERIFY(f.test_and_set()); + static_assert(std::is_nothrow_default_constructible_v); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_flag/requirements/trivial.cc b/libstdc++-v3/testsuite/29_atomics/atomic_flag/requirements/trivial.cc index d08adf8af43..ecf7ace1976 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic_flag/requirements/trivial.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic_flag/requirements/trivial.cc @@ -22,6 +22,10 @@ void test01() { +#if __cplusplus <= 201703L __gnu_test::has_trivial_cons_dtor test; +#else + __gnu_test::has_trivial_dtor test; +#endif test.operator()(); } diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_float/requirements.cc b/libstdc++-v3/testsuite/29_atomics/atomic_float/requirements.cc index 1599655a9b6..b8a556291d1 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic_float/requirements.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/requirements.cc @@ -25,7 +25,7 @@ test01() { using A = std::atomic; static_assert( std::is_standard_layout_v ); - static_assert( std::is_trivially_default_constructible_v ); + static_assert( !std::is_trivially_default_constructible_v ); static_assert( std::is_trivially_destructible_v ); static_assert( std::is_same_v ); static_assert( std::is_same_v ); @@ -41,7 +41,7 @@ test02() { using A = std::atomic; static_assert( std::is_standard_layout_v ); - static_assert( std::is_trivially_default_constructible_v ); + static_assert( !std::is_trivially_default_constructible_v ); static_assert( std::is_trivially_destructible_v ); static_assert( std::is_same_v ); static_assert( std::is_same_v ); @@ -57,7 +57,7 @@ test03() { using A = std::atomic; static_assert( std::is_standard_layout_v ); - static_assert( std::is_trivially_default_constructible_v ); + static_assert( !std::is_trivially_default_constructible_v ); static_assert( std::is_trivially_destructible_v ); static_assert( std::is_same_v ); static_assert( std::is_same_v ); 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 index 00000000000..237c0dd13ed --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic_float/value_init.cc @@ -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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +constexpr std::atomic a; + +void +test01() +{ + VERIFY(a.load() == 0); + static_assert(std::is_nothrow_default_constructible_v>); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/assign_neg.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/assign_neg.cc index d842761d2f7..3c164b48701 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/assign_neg.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/assign_neg.cc @@ -28,5 +28,5 @@ int main() return 0; } -// { dg-error "deleted" "" { target *-*-* } 639 } +// { dg-error "deleted" "" { target *-*-* } 659 } // { dg-prune-output "include" } diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/copy_neg.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/copy_neg.cc index a83a214278f..0131ba2c915 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/copy_neg.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/copy_neg.cc @@ -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 index 00000000000..fa1eb7ad56f --- /dev/null +++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/cons/value_init.cc @@ -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 +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +constexpr std::atomic a; + +void +test01() +{ + VERIFY(a.load() == 0); + static_assert(std::is_nothrow_default_constructible_v>); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/trivial.cc b/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/trivial.cc index aac12187400..36aa248552f 100644 --- a/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/trivial.cc +++ b/libstdc++-v3/testsuite/29_atomics/atomic_integral/requirements/trivial.cc @@ -22,7 +22,11 @@ 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()); } diff --git a/libstdc++-v3/testsuite/util/testsuite_common_types.h b/libstdc++-v3/testsuite/util/testsuite_common_types.h index ab3d961f0af..2795df36ca3 100644 --- a/libstdc++-v3/testsuite/util/testsuite_common_types.h +++ b/libstdc++-v3/testsuite/util/testsuite_common_types.h @@ -558,7 +558,6 @@ namespace __gnu_test } }; - // Generator to test standard layout struct has_trivial_cons_dtor { template @@ -582,6 +581,27 @@ namespace __gnu_test } }; + struct has_trivial_dtor + { + template + 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