Skip to content

Commit

Permalink
Implement LWG-4169 std::atomic<T>'s default constructor should be c…
Browse files Browse the repository at this point in the history
…onstrained (#5128)

Co-authored-by: Casey Carter <cacarter@microsoft.com>
  • Loading branch information
frederick-vs-ja and CaseyCarter authored Dec 5, 2024
1 parent 059a1b0 commit b60bb78
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 18 deletions.
27 changes: 10 additions & 17 deletions stl/inc/atomic
Original file line number Diff line number Diff line change
Expand Up @@ -586,8 +586,7 @@ struct _Atomic_storage {

_Atomic_storage() = default;

/* implicit */ constexpr _Atomic_storage(conditional_t<is_reference_v<_Ty>, _Ty, const _TVal> _Value) noexcept
: _Storage(_Value) {
/* implicit */ constexpr _Atomic_storage(const _Ty& _Value) noexcept : _Storage(_Value) {
// non-atomically initialize this atomic
}

Expand Down Expand Up @@ -714,13 +713,11 @@ public:

template <class _Ty>
struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics

using _TVal = remove_reference_t<_Ty>;

_Atomic_storage() = default;

/* implicit */ constexpr _Atomic_storage(conditional_t<is_reference_v<_Ty>, _Ty, const _TVal> _Value) noexcept
: _Storage{_Value} {
/* implicit */ constexpr _Atomic_storage(const _Ty& _Value) noexcept : _Storage{_Value} {
// non-atomically initialize this atomic
}

Expand Down Expand Up @@ -817,13 +814,11 @@ struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics

template <class _Ty>
struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics

using _TVal = remove_reference_t<_Ty>;

_Atomic_storage() = default;

/* implicit */ constexpr _Atomic_storage(conditional_t<is_reference_v<_Ty>, _Ty, const _TVal> _Value) noexcept
: _Storage{_Value} {
/* implicit */ constexpr _Atomic_storage(const _Ty& _Value) noexcept : _Storage{_Value} {
// non-atomically initialize this atomic
}

Expand Down Expand Up @@ -919,13 +914,11 @@ struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics

template <class _Ty>
struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics

using _TVal = remove_reference_t<_Ty>;

_Atomic_storage() = default;

/* implicit */ constexpr _Atomic_storage(conditional_t<is_reference_v<_Ty>, _Ty, const _TVal> _Value) noexcept
: _Storage{_Value} {
/* implicit */ constexpr _Atomic_storage(const _Ty& _Value) noexcept : _Storage{_Value} {
// non-atomically initialize this atomic
}

Expand Down Expand Up @@ -1021,13 +1014,11 @@ struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics

template <class _Ty>
struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics

using _TVal = remove_reference_t<_Ty>;

_Atomic_storage() = default;

/* implicit */ constexpr _Atomic_storage(conditional_t<is_reference_v<_Ty>, _Ty, const _TVal> _Value) noexcept
: _Storage{_Value} {
/* implicit */ constexpr _Atomic_storage(const _Ty& _Value) noexcept : _Storage{_Value} {
// non-atomically initialize this atomic
}

Expand Down Expand Up @@ -1148,7 +1139,8 @@ struct _Atomic_storage<_Ty&, 16> { // lock-free using 16-byte intrinsics

_Atomic_storage() = default;

/* implicit */ constexpr _Atomic_storage(conditional_t<is_reference_v<_Ty&>, _Ty&, const _TVal> _Value) noexcept
// TRANSITION, ABI: replace _this_ occurrence of '_Ty&' with 'const _Ty&'
/* implicit */ constexpr _Atomic_storage(_Ty& _Value) noexcept
: _Storage{_Value} {} // non-atomically initialize this atomic

void store(const _TVal _Value) noexcept { // store with sequential consistency
Expand Down Expand Up @@ -2121,10 +2113,11 @@ public:

using value_type = _Ty;

using _Base::_Base;

template <class _Uty = _Ty, enable_if_t<is_default_constructible_v<_Uty>, int> = 0>
constexpr atomic() noexcept(is_nothrow_default_constructible_v<_Ty>) : _Base() {}

/* implicit */ constexpr atomic(const _Ty _Value) noexcept : _Base(_Value) {}

atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
Expand Down
13 changes: 12 additions & 1 deletion tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <limits>
#include <new>
#include <type_traits>


using namespace std;

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
Expand Down Expand Up @@ -438,6 +438,17 @@ STATIC_ASSERT(atomic<void*>::is_always_lock_free);
STATIC_ASSERT(atomic<int (*)(int)>::is_always_lock_free);
#endif // _HAS_CXX17

// Also test LWG-4169 std::atomic<T>'s default constructor should be constrained
// (backported to C++14/17 modes as we backported P0883R2)
STATIC_ASSERT(is_default_constructible_v<atomic<int>>);
STATIC_ASSERT(is_default_constructible_v<atomic<bool>>);
STATIC_ASSERT(is_default_constructible_v<atomic<void*>>);
STATIC_ASSERT(is_default_constructible_v<atomic<X>>);
STATIC_ASSERT(is_default_constructible_v<atomic<Y>>);
STATIC_ASSERT(!is_default_constructible_v<atomic<reference_wrapper<int>>>);
STATIC_ASSERT(!is_default_constructible_v<atomic<reference_wrapper<const int>>>);
STATIC_ASSERT(!is_default_constructible_v<atomic<reference_wrapper<int()>>>);


// Also test P0418R2 atomic compare_exchange memory_order Requirements
void test_compare_exchange_relaxed_memory_orders() {
Expand Down

0 comments on commit b60bb78

Please sign in to comment.