Commit e4379a93 by Jonathan Wakely

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.
parent aef85e40
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> 2020-01-10 Jonathan Wakely <jwakely@redhat.com>
* testsuite/util/testsuite_iterators.h: Improve comment. * testsuite/util/testsuite_iterators.h: Improve comment.
......
...@@ -139,6 +139,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -139,6 +139,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _IntTp> template<typename _IntTp>
struct __atomic_base; 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 } #define ATOMIC_VAR_INIT(_VI) { _VI }
...@@ -169,7 +175,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -169,7 +175,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __atomic_flag_base struct __atomic_flag_base
{ {
__atomic_flag_data_type _M_i; __atomic_flag_data_type _M_i _GLIBCXX20_INIT({});
}; };
_GLIBCXX_END_EXTERN_C _GLIBCXX_END_EXTERN_C
...@@ -267,7 +273,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -267,7 +273,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static constexpr int _S_alignment = static constexpr int _S_alignment =
sizeof(_ITp) > alignof(_ITp) ? sizeof(_ITp) : alignof(_ITp); 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: public:
__atomic_base() noexcept = default; __atomic_base() noexcept = default;
...@@ -595,7 +601,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -595,7 +601,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
private: private:
typedef _PTp* __pointer_type; typedef _PTp* __pointer_type;
__pointer_type _M_p; __pointer_type _M_p _GLIBCXX20_INIT(nullptr);
// Factored out to facilitate explicit specialization. // Factored out to facilitate explicit specialization.
constexpr ptrdiff_t constexpr ptrdiff_t
...@@ -1175,8 +1181,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1175,8 +1181,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return __atomic_impl::__sub_fetch_flt(&_M_fp, __i); } { return __atomic_impl::__sub_fetch_flt(&_M_fp, __i); }
private: private:
alignas(_S_alignment) _Fp _M_fp; alignas(_S_alignment) _Fp _M_fp _GLIBCXX20_INIT(0);
}; };
#undef _GLIBCXX20_INIT
template<typename _Tp, template<typename _Tp,
bool = is_integral_v<_Tp>, bool = is_floating_point_v<_Tp>> bool = is_integral_v<_Tp>, bool = is_floating_point_v<_Tp>>
......
...@@ -165,6 +165,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -165,6 +165,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return _M_base.compare_exchange_strong(__i1, __i2, __m); } { 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. * @brief Generic atomic type, primary class template.
...@@ -185,7 +190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -185,7 +190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static constexpr int _S_alignment static constexpr int _S_alignment
= _S_min_alignment > alignof(_Tp) ? _S_min_alignment : alignof(_Tp); = _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), static_assert(__is_trivially_copyable(_Tp),
"std::atomic requires a trivially copyable type"); "std::atomic requires a trivially copyable type");
...@@ -194,7 +199,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -194,7 +199,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"Incomplete or zero-sized types are not supported"); "Incomplete or zero-sized types are not supported");
public: public:
atomic() noexcept = default; atomic() = default;
~atomic() noexcept = default; ~atomic() noexcept = default;
atomic(const atomic&) = delete; atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete; atomic& operator=(const atomic&) = delete;
...@@ -348,7 +353,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -348,7 +353,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return compare_exchange_strong(__e, __i, __m, { return compare_exchange_strong(__e, __i, __m,
__cmpexch_failure_order(__m)); } __cmpexch_failure_order(__m)); }
}; };
#undef _GLIBCXX20_INIT
/// Partial specialization for pointer types. /// Partial specialization for pointer types.
template<typename _Tp> template<typename _Tp>
......
...@@ -164,6 +164,7 @@ ...@@ -164,6 +164,7 @@
#if __cplusplus > 201703L #if __cplusplus > 201703L
// c++2a // c++2a
#define __cpp_lib_atomic_ref 201806L #define __cpp_lib_atomic_ref 201806L
#define __cpp_lib_atomic_value_initialization 201911L
#define __cpp_lib_bitops 201907L #define __cpp_lib_bitops 201907L
#define __cpp_lib_bounded_array_traits 201902L #define __cpp_lib_bounded_array_traits 201902L
#if __cpp_concepts #if __cpp_concepts
......
...@@ -27,5 +27,5 @@ int main() ...@@ -27,5 +27,5 @@ int main()
return 0; return 0;
} }
// { dg-error "deleted" "" { target *-*-* } 639 } // { dg-error "deleted" "" { target *-*-* } 659 }
// { dg-prune-output "include" } // { dg-prune-output "include" }
...@@ -27,5 +27,5 @@ int main() ...@@ -27,5 +27,5 @@ int main()
return 0; return 0;
} }
// { dg-error "deleted" "" { target *-*-* } 678 } // { dg-error "deleted" "" { target *-*-* } 698 }
// { dg-prune-output "include" } // { dg-prune-output "include" }
// 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();
}
// 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();
}
...@@ -22,6 +22,10 @@ ...@@ -22,6 +22,10 @@
void test01() void test01()
{ {
#if __cplusplus <= 201703L
__gnu_test::has_trivial_cons_dtor test; __gnu_test::has_trivial_cons_dtor test;
#else
__gnu_test::has_trivial_dtor test;
#endif
test.operator()<std::atomic_flag>(); test.operator()<std::atomic_flag>();
} }
...@@ -25,7 +25,7 @@ test01() ...@@ -25,7 +25,7 @@ test01()
{ {
using A = std::atomic<float>; using A = std::atomic<float>;
static_assert( std::is_standard_layout_v<A> ); 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_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, float> ); static_assert( std::is_same_v<A::value_type, float> );
static_assert( std::is_same_v<A::difference_type, A::value_type> ); static_assert( std::is_same_v<A::difference_type, A::value_type> );
...@@ -41,7 +41,7 @@ test02() ...@@ -41,7 +41,7 @@ test02()
{ {
using A = std::atomic<double>; using A = std::atomic<double>;
static_assert( std::is_standard_layout_v<A> ); 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_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, double> ); static_assert( std::is_same_v<A::value_type, double> );
static_assert( std::is_same_v<A::difference_type, A::value_type> ); static_assert( std::is_same_v<A::difference_type, A::value_type> );
...@@ -57,7 +57,7 @@ test03() ...@@ -57,7 +57,7 @@ test03()
{ {
using A = std::atomic<long double>; using A = std::atomic<long double>;
static_assert( std::is_standard_layout_v<A> ); 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_trivially_destructible_v<A> );
static_assert( std::is_same_v<A::value_type, long double> ); static_assert( std::is_same_v<A::value_type, long double> );
static_assert( std::is_same_v<A::difference_type, A::value_type> ); static_assert( std::is_same_v<A::difference_type, A::value_type> );
......
// 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();
}
...@@ -28,5 +28,5 @@ int main() ...@@ -28,5 +28,5 @@ int main()
return 0; return 0;
} }
// { dg-error "deleted" "" { target *-*-* } 639 } // { dg-error "deleted" "" { target *-*-* } 659 }
// { dg-prune-output "include" } // { dg-prune-output "include" }
...@@ -28,5 +28,5 @@ int main() ...@@ -28,5 +28,5 @@ int main()
return 0; return 0;
} }
// { dg-error "deleted" "" { target *-*-* } 678 } // { dg-error "deleted" "" { target *-*-* } 698 }
// { dg-prune-output "include" } // { dg-prune-output "include" }
// 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();
}
...@@ -22,7 +22,11 @@ ...@@ -22,7 +22,11 @@
void test01() void test01()
{ {
#if __cplusplus <= 201703L
__gnu_test::has_trivial_cons_dtor test; __gnu_test::has_trivial_cons_dtor test;
#else
__gnu_test::has_trivial_dtor test;
#endif
__gnu_cxx::typelist::apply_generator(test, __gnu_cxx::typelist::apply_generator(test,
__gnu_test::atomic_integrals::type()); __gnu_test::atomic_integrals::type());
} }
...@@ -558,7 +558,6 @@ namespace __gnu_test ...@@ -558,7 +558,6 @@ namespace __gnu_test
} }
}; };
// Generator to test standard layout
struct has_trivial_cons_dtor struct has_trivial_cons_dtor
{ {
template<typename _Tp> template<typename _Tp>
...@@ -582,6 +581,27 @@ namespace __gnu_test ...@@ -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 struct standard_layout
{ {
template<typename _Tp> template<typename _Tp>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment