Skip to content

Commit bbb4626

Browse files
Dawn Perchikzygoloid
authored andcommitted
P0883R2 Fixing Atomic Initialization
[depr.atomics] Added additional deprecated sections. Also fixes NB CA 353, US 351, DE 18, and RU 6 (C++20 CD), and LWG2334.
1 parent 9124aa5 commit bbb4626

File tree

3 files changed

+108
-87
lines changed

3 files changed

+108
-87
lines changed

source/atomics.tex

Lines changed: 26 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,11 @@
5656
// \ref{atomics.types.pointer}, partial specialization for pointers
5757
template<class T> struct atomic<T*>;
5858

59-
// \ref{atomics.types.operations}, initialization
60-
#define ATOMIC_VAR_INIT(value) @\seebelow@
61-
6259
// \ref{atomics.nonmembers}, non-member functions
6360
template<class T>
6461
bool atomic_is_lock_free(const volatile atomic<T>*) noexcept;
6562
template<class T>
6663
bool atomic_is_lock_free(const atomic<T>*) noexcept;
67-
template<class T>
68-
void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
69-
template<class T>
70-
void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept;
7164
template<class T>
7265
void atomic_store(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
7366
template<class T>
@@ -261,8 +254,6 @@
261254
// \ref{atomics.flag}, flag type and operations
262255
struct atomic_flag;
263256

264-
#define ATOMIC_FLAG_INIT @\seebelow@
265-
266257
bool atomic_flag_test(const volatile atomic_flag*) noexcept;
267258
bool atomic_flag_test(const atomic_flag*) noexcept;
268259
bool atomic_flag_test_explicit(const volatile atomic_flag*, memory_order) noexcept;
@@ -1551,7 +1542,7 @@
15511542
bool is_lock_free() const volatile noexcept;
15521543
bool is_lock_free() const noexcept;
15531544

1554-
atomic() noexcept = default;
1545+
constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
15551546
constexpr atomic(T) noexcept;
15561547
atomic(const atomic&) = delete;
15571548
atomic& operator=(const atomic&) = delete;
@@ -1625,44 +1616,23 @@
16251616
operations on non-volatile objects become volatile.
16261617
\end{note}
16271618

1628-
\indexlibraryglobal{ATOMIC_VAR_INIT}%
1629-
\begin{itemdecl}
1630-
#define ATOMIC_VAR_INIT(value) @\seebelow@
1631-
\end{itemdecl}
1632-
1633-
\begin{itemdescr}
1634-
\pnum
1635-
The macro expands to a token sequence suitable for
1636-
constant initialization of
1637-
an atomic variable of static storage duration of a type that is
1638-
initialization-compatible with \tcode{value}.
1639-
\begin{note}
1640-
This operation may need to initialize locks.
1641-
\end{note}
1642-
Concurrent access to the variable being initialized, even via an atomic operation,
1643-
constitutes a data race.
1644-
\begin{example}
1645-
\begin{codeblock}
1646-
atomic<int> v = ATOMIC_VAR_INIT(5);
1647-
\end{codeblock}
1648-
\end{example}
1649-
\end{itemdescr}
1650-
16511619
\indexlibraryctor{atomic}%
16521620
\indexlibraryctor{atomic<T*>}%
16531621
\indexlibrary{\idxcode{atomic<\placeholder{integral}>}!constructor}%
16541622
\indexlibrary{\idxcode{atomic<\placeholder{floating-point}>}!constructor}%
16551623
\begin{itemdecl}
1656-
atomic() noexcept = default;
1624+
constexpr atomic() noexcept(is_nothrow_default_constructible_v<T>);
16571625
\end{itemdecl}
16581626

16591627
\begin{itemdescr}
1628+
\pnum
1629+
\mandates
1630+
\tcode{is_default_constructible_v<T>} is \tcode{true}.
1631+
16601632
\pnum
16611633
\effects
1662-
Leaves the atomic object in an uninitialized state.
1663-
\begin{note}
1664-
These semantics ensure compatibility with C.
1665-
\end{note}
1634+
Initializes the atomic object with the value of \tcode{T()}.
1635+
Initialization is not an atomic operation\iref{intro.multithread}.
16661636
\end{itemdescr}
16671637

16681638
\indexlibraryctor{atomic}%
@@ -2118,7 +2088,7 @@
21182088
bool is_lock_free() const volatile noexcept;
21192089
bool is_lock_free() const noexcept;
21202090

2121-
atomic() noexcept = default;
2091+
constexpr atomic() noexcept;
21222092
constexpr atomic(@\placeholdernc{integral}@) noexcept;
21232093
atomic(const atomic&) = delete;
21242094
atomic& operator=(const atomic&) = delete;
@@ -2195,8 +2165,8 @@
21952165
\pnum
21962166
The atomic integral specializations
21972167
are standard-layout structs.
2198-
They each have a trivial default constructor
2199-
and a trivial destructor.
2168+
They each have
2169+
a trivial destructor.
22002170

22012171
\pnum
22022172
Descriptions are provided below only for members that differ from the primary template.
@@ -2318,7 +2288,7 @@
23182288
bool is_lock_free() const volatile noexcept;
23192289
bool is_lock_free() const noexcept;
23202290

2321-
atomic() noexcept = default;
2291+
constexpr atomic() noexcept;
23222292
constexpr atomic(@\placeholder{floating-point}@) noexcept;
23232293
atomic(const atomic&) = delete;
23242294
atomic& operator=(const atomic&) = delete;
@@ -2381,8 +2351,8 @@
23812351
\pnum
23822352
The atomic floating-point specializations
23832353
are standard-layout structs.
2384-
They each have a trivial default constructor
2385-
and a trivial destructor.
2354+
They each have
2355+
a trivial destructor.
23862356

23872357
\pnum
23882358
Descriptions are provided below only for members that differ from the primary template.
@@ -2467,7 +2437,7 @@
24672437
bool is_lock_free() const volatile noexcept;
24682438
bool is_lock_free() const noexcept;
24692439

2470-
atomic() noexcept = default;
2440+
constexpr atomic() noexcept;
24712441
constexpr atomic(T*) noexcept;
24722442
atomic(const atomic&) = delete;
24732443
atomic& operator=(const atomic&) = delete;
@@ -2529,7 +2499,7 @@
25292499
\pnum
25302500
There is a partial specialization of the \tcode{atomic} class template for pointers.
25312501
Specializations of this partial specialization are standard-layout structs.
2532-
They each have a trivial default constructor and a trivial destructor.
2502+
They each have a trivial destructor.
25332503

25342504
\pnum
25352505
Descriptions are provided below only for members that differ from the primary template.
@@ -2717,7 +2687,7 @@
27172687
void notify_one() noexcept;
27182688
void notify_all() noexcept;
27192689

2720-
constexpr atomic() noexcept = default;
2690+
constexpr atomic() noexcept;
27212691
atomic(shared_ptr<T> desired) noexcept;
27222692
atomic(const atomic&) = delete;
27232693
void operator=(const atomic&) = delete;
@@ -2731,7 +2701,7 @@
27312701

27322702
\indexlibraryctor{atomic<shared_ptr<T>>}%
27332703
\begin{itemdecl}
2734-
constexpr atomic() noexcept = default;
2704+
constexpr atomic() noexcept;
27352705
\end{itemdecl}
27362706

27372707
\begin{itemdescr}
@@ -3025,7 +2995,7 @@
30252995
void notify_one() noexcept;
30262996
void notify_all() noexcept;
30272997

3028-
constexpr atomic() noexcept = default;
2998+
constexpr atomic() noexcept;
30292999
atomic(weak_ptr<T> desired) noexcept;
30303000
atomic(const atomic&) = delete;
30313001
void operator=(const atomic&) = delete;
@@ -3039,7 +3009,7 @@
30393009

30403010
\indexlibraryctor{atomic<weak_ptr<T>>}%
30413011
\begin{itemdecl}
3042-
constexpr atomic() noexcept = default;
3012+
constexpr atomic() noexcept;
30433013
\end{itemdecl}
30443014

30453015
\begin{itemdescr}
@@ -3316,29 +3286,6 @@
33163286
passed to the member function call.
33173287
If no such member function exists, the program is ill-formed.
33183288

3319-
\indexlibraryglobal{atomic_init}%
3320-
\begin{itemdecl}
3321-
template<class T>
3322-
void atomic_init(volatile atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
3323-
template<class T>
3324-
void atomic_init(atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
3325-
\end{itemdecl}
3326-
3327-
\begin{itemdescr}
3328-
\pnum
3329-
\effects
3330-
Non-atomically
3331-
initializes \tcode{*object} with value \tcode{desired}. This function shall only be applied
3332-
to objects that have been default constructed, and then only once.
3333-
\begin{note}
3334-
These semantics ensure compatibility with C.
3335-
\end{note}
3336-
\begin{note}
3337-
Concurrent access from another thread, even via an atomic operation, constitutes
3338-
a data race.
3339-
\end{note}
3340-
\end{itemdescr}
3341-
33423289
\pnum
33433290
\begin{note}
33443291
The non-member functions enable programmers to write code that can be
@@ -3350,7 +3297,7 @@
33503297
\begin{codeblock}
33513298
namespace std {
33523299
struct atomic_flag {
3353-
atomic_flag() noexcept = default;
3300+
constexpr atomic_flag() noexcept;
33543301
atomic_flag(const atomic_flag&) = delete;
33553302
atomic_flag& operator=(const atomic_flag&) = delete;
33563303
atomic_flag& operator=(const atomic_flag&) volatile = delete;
@@ -3384,25 +3331,17 @@
33843331

33853332
\pnum
33863333
The \tcode{atomic_flag} type is a standard-layout struct.
3387-
It has a trivial default constructor and a trivial destructor.
3334+
It has a trivial destructor.
33883335

3389-
\indexlibraryglobal{ATOMIC_FLAG_INIT}%
3336+
\indexlibraryctor{atomic_flag}%
33903337
\begin{itemdecl}
3391-
#define ATOMIC_FLAG_INIT @\seebelow@
3338+
constexpr atomic_flag::atomic_flag() noexcept;
33923339
\end{itemdecl}
33933340

33943341
\begin{itemdescr}
33953342
\pnum
3396-
\remarks
3397-
The macro \tcode{ATOMIC_FLAG_INIT} shall be defined in such a way that it can be used to initialize an object of type \tcode{atomic_flag} to the
3398-
clear state. The macro can be used in the form:
3399-
\begin{codeblock}
3400-
atomic_flag guard = ATOMIC_FLAG_INIT;
3401-
\end{codeblock}
3402-
It is unspecified whether the macro can be used in other initialization contexts.
3403-
For a complete static-duration object, that initialization shall be static.
3404-
Unless initialized with \tcode{ATOMIC_FLAG_INIT}, it is unspecified whether an
3405-
\tcode{atomic_flag} object has an initial state of set or clear.
3343+
\effects
3344+
Initializes \tcode{*this} to the clear state.
34063345
\end{itemdescr}
34073346

34083347
\indexlibraryglobal{atomic_flag_test}%

source/future.tex

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2487,3 +2487,84 @@
24872487
UTF-16 occurs.
24882488
\end{example}
24892489
\end{itemdescr}
2490+
2491+
\rSec1[depr.atomics]{Deprecated atomic initialization}
2492+
2493+
\pnum
2494+
The header \libheaderref{atomics} has the following additions.
2495+
2496+
\begin{codeblock}
2497+
namespace std {
2498+
template<class T>
2499+
void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
2500+
template<class T>
2501+
void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept;
2502+
2503+
#define ATOMIC_VAR_INIT(value) @\seebelow@
2504+
2505+
#define ATOMIC_FLAG_INIT @\seebelow@
2506+
}
2507+
\end{codeblock}
2508+
2509+
\rSec2[depr.atomics.nonmembers]{Non-member functions}
2510+
2511+
\indexlibraryglobal{atomic_init}%
2512+
\begin{itemdecl}
2513+
template<class T>
2514+
void atomic_init(volatile atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
2515+
template<class T>
2516+
void atomic_init(atomic<T>* object, typename atomic<T>::value_type desired) noexcept;
2517+
\end{itemdecl}
2518+
2519+
\begin{itemdescr}
2520+
\pnum
2521+
\effects
2522+
Equivalent to: \tcode{atomic_store_explicit(object, desired, memory_order_relaxed);}
2523+
\end{itemdescr}
2524+
2525+
\rSec2[depr.atomics.types.operations]{Operations on atomic types}
2526+
2527+
\indexlibraryglobal{ATOMIC_VAR_INIT}%
2528+
\begin{itemdecl}
2529+
#define ATOMIC_VAR_INIT(value) @\seebelow@
2530+
\end{itemdecl}
2531+
2532+
\begin{itemdescr}
2533+
\pnum
2534+
The macro expands to a token sequence suitable for constant initialization of
2535+
an atomic variable of static storage duration of a type that
2536+
is initialization-compatible with \tcode{value}.
2537+
\begin{note}
2538+
This operation may need to initialize locks.
2539+
\end{note}
2540+
Concurrent access to the variable being initialized,
2541+
even via an atomic operation,
2542+
constitutes a data race.
2543+
\begin{example}
2544+
\begin{codeblock}
2545+
atomic<int> v = ATOMIC_VAR_INIT(5);
2546+
\end{codeblock}
2547+
\end{example}
2548+
\end{itemdescr}
2549+
2550+
\rSec2[depr.atomics.flag]{Flag type and operations}
2551+
2552+
\indexlibraryglobal{ATOMIC_FLAG_INIT}%
2553+
\begin{itemdecl}
2554+
#define ATOMIC_FLAG_INIT @\seebelow@
2555+
\end{itemdecl}
2556+
2557+
\begin{itemdescr}
2558+
\pnum
2559+
\remarks
2560+
The macro \tcode{ATOMIC_FLAG_INIT} shall be defined in such a way that
2561+
it can be used to initialize an object of type \tcode{atomic_flag}
2562+
to the clear state.
2563+
The macro can be used in the form:
2564+
\begin{codeblock}
2565+
atomic_flag guard = ATOMIC_FLAG_INIT;
2566+
\end{codeblock}
2567+
It is unspecified whether the macro can be used
2568+
in other initialization contexts.
2569+
For a complete static-duration object, that initialization shall be static.
2570+
\end{itemdescr}

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@
563563
#define @\defnlibxname{cpp_lib_atomic_lock_free_type_aliases}@ 201907L // also in \libheader{atomic}
564564
#define @\defnlibxname{cpp_lib_atomic_ref}@ 201806L // also in \libheader{atomic}
565565
#define @\defnlibxname{cpp_lib_atomic_shared_ptr}@ 201711L // also in \libheader{memory}
566+
#define @\defnlibxname{cpp_lib_atomic_value_initialization}@ 201911L // also in \libheader{atomic}, \libheader{memory}
566567
#define @\defnlibxname{cpp_lib_atomic_wait}@ 201907L // also in \libheader{atomic}
567568
#define @\defnlibxname{cpp_lib_barrier}@ 201907L // also in \libheader{barrier}
568569
#define @\defnlibxname{cpp_lib_bit_cast}@ 201806L // also in \libheader{bit}

0 commit comments

Comments
 (0)