Skip to content

Commit b60bb78

Browse files
Implement LWG-4169 std::atomic<T>'s default constructor should be constrained (#5128)
Co-authored-by: Casey Carter <[email protected]>
1 parent 059a1b0 commit b60bb78

File tree

2 files changed

+22
-18
lines changed
  • stl/inc
  • tests/std/tests/Dev11_0863628_atomic_compare_exchange

2 files changed

+22
-18
lines changed

stl/inc/atomic

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,7 @@ struct _Atomic_storage {
586586

587587
_Atomic_storage() = default;
588588

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

@@ -714,13 +713,11 @@ public:
714713

715714
template <class _Ty>
716715
struct _Atomic_storage<_Ty, 1> { // lock-free using 1-byte intrinsics
717-
718716
using _TVal = remove_reference_t<_Ty>;
719717

720718
_Atomic_storage() = default;
721719

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

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

818815
template <class _Ty>
819816
struct _Atomic_storage<_Ty, 2> { // lock-free using 2-byte intrinsics
820-
821817
using _TVal = remove_reference_t<_Ty>;
822818

823819
_Atomic_storage() = default;
824820

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

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

920915
template <class _Ty>
921916
struct _Atomic_storage<_Ty, 4> { // lock-free using 4-byte intrinsics
922-
923917
using _TVal = remove_reference_t<_Ty>;
924918

925919
_Atomic_storage() = default;
926920

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

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

10221015
template <class _Ty>
10231016
struct _Atomic_storage<_Ty, 8> { // lock-free using 8-byte intrinsics
1024-
10251017
using _TVal = remove_reference_t<_Ty>;
10261018

10271019
_Atomic_storage() = default;
10281020

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

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

11491140
_Atomic_storage() = default;
11501141

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

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

21222114
using value_type = _Ty;
21232115

2124-
using _Base::_Base;
2125-
2116+
template <class _Uty = _Ty, enable_if_t<is_default_constructible_v<_Uty>, int> = 0>
21262117
constexpr atomic() noexcept(is_nothrow_default_constructible_v<_Ty>) : _Base() {}
21272118

2119+
/* implicit */ constexpr atomic(const _Ty _Value) noexcept : _Base(_Value) {}
2120+
21282121
atomic(const atomic&) = delete;
21292122
atomic& operator=(const atomic&) = delete;
21302123
atomic& operator=(const atomic&) volatile = delete;

tests/std/tests/Dev11_0863628_atomic_compare_exchange/test.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
#include <cstdint>
1313
#include <cstdlib>
1414
#include <cstring>
15+
#include <functional>
1516
#include <limits>
1617
#include <new>
1718
#include <type_traits>
1819

19-
2020
using namespace std;
2121

2222
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
@@ -438,6 +438,17 @@ STATIC_ASSERT(atomic<void*>::is_always_lock_free);
438438
STATIC_ASSERT(atomic<int (*)(int)>::is_always_lock_free);
439439
#endif // _HAS_CXX17
440440

441+
// Also test LWG-4169 std::atomic<T>'s default constructor should be constrained
442+
// (backported to C++14/17 modes as we backported P0883R2)
443+
STATIC_ASSERT(is_default_constructible_v<atomic<int>>);
444+
STATIC_ASSERT(is_default_constructible_v<atomic<bool>>);
445+
STATIC_ASSERT(is_default_constructible_v<atomic<void*>>);
446+
STATIC_ASSERT(is_default_constructible_v<atomic<X>>);
447+
STATIC_ASSERT(is_default_constructible_v<atomic<Y>>);
448+
STATIC_ASSERT(!is_default_constructible_v<atomic<reference_wrapper<int>>>);
449+
STATIC_ASSERT(!is_default_constructible_v<atomic<reference_wrapper<const int>>>);
450+
STATIC_ASSERT(!is_default_constructible_v<atomic<reference_wrapper<int()>>>);
451+
441452

442453
// Also test P0418R2 atomic compare_exchange memory_order Requirements
443454
void test_compare_exchange_relaxed_memory_orders() {

0 commit comments

Comments
 (0)