Skip to content

Commit 070deb4

Browse files
authored
Merge 2025-02 CWG Motion 6
P3475R2 Defang and deprecate memory_order::consume
2 parents aef9d70 + 08c96b4 commit 070deb4

File tree

7 files changed

+58
-261
lines changed

7 files changed

+58
-261
lines changed

source/basic.tex

Lines changed: 6 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -6319,7 +6319,7 @@
63196319
operations on mutexes\iref{thread} that are specially identified as
63206320
synchronization operations. These operations play a special role in making
63216321
assignments in one thread visible to another. A synchronization operation on one
6322-
or more memory locations is either a consume operation, an acquire operation, a
6322+
or more memory locations is either an acquire operation, a
63236323
release operation, or both an acquire and release operation. A synchronization
63246324
operation without an associated memory location is a fence and can be either an
63256325
acquire fence, a release fence, or both an acquire and release fence. In
@@ -6375,122 +6375,17 @@
63756375
the value written'' by the last mutex release.
63766376
\end{note}
63776377

6378-
\pnum
6379-
An evaluation $A$ \defn{carries a dependency} to an evaluation $B$ if
6380-
\begin{itemize}
6381-
\item
6382-
the value of $A$ is used as an operand of $B$, unless:
6383-
\begin{itemize}
6384-
\item
6385-
$B$ is an invocation of any specialization of
6386-
\tcode{std::kill_dependency}\iref{atomics.order}, or
6387-
\item
6388-
$A$ is the left operand of a built-in logical \logop{and} (\tcode{\&\&},
6389-
see~\ref{expr.log.and}) or logical \logop{or} (\tcode{||}, see~\ref{expr.log.or})
6390-
operator, or
6391-
\item
6392-
$A$ is the left operand of a conditional (\tcode{?:}, see~\ref{expr.cond})
6393-
operator, or
6394-
\item
6395-
$A$ is the left operand of the built-in comma (\tcode{,})
6396-
operator\iref{expr.comma}; \end{itemize} or
6397-
\item
6398-
$A$ writes a scalar object or bit-field $M$, $B$ reads the value
6399-
written by $A$ from $M$, and $A$ is sequenced before $B$, or
6400-
\item
6401-
for some evaluation $X$, $A$ carries a dependency to $X$, and
6402-
$X$ carries a dependency to $B$.
6403-
\end{itemize}
6404-
\begin{note}
6405-
``Carries a dependency to'' is a subset of ``is sequenced before'',
6406-
and is similarly strictly intra-thread.
6407-
\end{note}
6408-
6409-
\pnum
6410-
An evaluation $A$ is \defn{dependency-ordered before} an evaluation
6411-
$B$ if
6412-
\begin{itemize}
6413-
\item
6414-
$A$ performs a release operation on an atomic object $M$, and, in
6415-
another thread, $B$ performs a consume operation on $M$ and reads
6416-
the value written by $A$, or
6417-
6418-
\item
6419-
for some evaluation $X$, $A$ is dependency-ordered before $X$ and
6420-
$X$ carries a dependency to $B$.
6421-
6422-
\end{itemize}
6423-
\begin{note}
6424-
The relation ``is dependency-ordered before'' is analogous to
6425-
``synchronizes with'', but uses release/consume in place of release/acquire.
6426-
\end{note}
6427-
6428-
\pnum
6429-
An evaluation $A$ \defn{inter-thread happens before} an evaluation $B$
6430-
if
6431-
\begin{itemize}
6432-
\item
6433-
$A$ synchronizes with $B$, or
6434-
\item
6435-
$A$ is dependency-ordered before $B$, or
6436-
\item
6437-
for some evaluation $X$
6438-
\begin{itemize}
6439-
\item
6440-
$A$ synchronizes with $X$ and $X$
6441-
is sequenced before $B$, or
6442-
\item
6443-
$A$ is sequenced before $X$ and $X$
6444-
inter-thread happens before $B$, or
6445-
\item
6446-
$A$ inter-thread happens before $X$ and $X$
6447-
inter-thread happens before $B$.
6448-
\end{itemize}
6449-
\end{itemize}
6450-
\begin{note}
6451-
The ``inter-thread happens before'' relation describes arbitrary
6452-
concatenations of ``sequenced before'', ``synchronizes with'' and
6453-
``dependency-ordered before'' relationships, with two exceptions. The first
6454-
exception is that a concatenation never ends with
6455-
``dependency-ordered before'' followed by ``sequenced before''. The reason for
6456-
this limitation is that a consume operation participating in a
6457-
``dependency-ordered before'' relationship provides ordering only with respect
6458-
to operations to which this consume operation actually carries a dependency. The
6459-
reason that this limitation applies only to the end of such a concatenation is
6460-
that any subsequent release operation will provide the required ordering for a
6461-
prior consume operation. The second exception is that a concatenation never
6462-
consist entirely of ``sequenced before''. The reasons for this
6463-
limitation are (1) to permit ``inter-thread happens before'' to be transitively
6464-
closed and (2) the ``happens before'' relation, defined below, provides for
6465-
relationships consisting entirely of ``sequenced before''.
6466-
\end{note}
6467-
64686378
\pnum
64696379
An evaluation $A$ \defn{happens before} an evaluation $B$
6470-
(or, equivalently, $B$ \defn{happens after} $A$) if
6471-
\begin{itemize}
6472-
\item $A$ is sequenced before $B$, or
6473-
\item $A$ inter-thread happens before $B$.
6474-
\end{itemize}
6475-
The implementation shall ensure that no program execution demonstrates a cycle
6476-
in the ``happens before'' relation.
6477-
\begin{note}
6478-
This cycle would otherwise be
6479-
possible only through the use of consume operations.
6480-
\end{note}
6481-
6482-
\pnum
6483-
An evaluation $A$ \defn{simply happens before} an evaluation $B$
6380+
(or, equivalently, $B$ happens after $A$)
64846381
if either
64856382
\begin{itemize}
64866383
\item $A$ is sequenced before $B$, or
64876384
\item $A$ synchronizes with $B$, or
6488-
\item $A$ simply happens before $X$ and
6489-
$X$ simply happens before $B$.
6385+
\item $A$ happens before $X$ and $X$ happens before $B$.
64906386
\end{itemize}
64916387
\begin{note}
6492-
In the absence of consume operations,
6493-
the happens before and simply happens before relations are identical.
6388+
An evaluation does not happen before itself.
64946389
\end{note}
64956390

64966391
\pnum
@@ -6503,7 +6398,7 @@
65036398
sequentially consistent atomic operations\iref{atomics.order}, or
65046399
\item there are evaluations $B$ and $C$
65056400
such that $A$ is sequenced before $B$,
6506-
$B$ simply happens before $C$, and
6401+
$B$ happens before $C$, and
65076402
$C$ is sequenced before $D$, or
65086403
\item there is an evaluation $B$ such that
65096404
$A$ strongly happens before $B$, and
@@ -6512,7 +6407,7 @@
65126407
\begin{note}
65136408
Informally, if $A$ strongly happens before $B$,
65146409
then $A$ appears to be evaluated before $B$
6515-
in all contexts. Strongly happens before excludes consume operations.
6410+
in all contexts.
65166411
\end{note}
65176412

65186413
\pnum

source/compatibility.tex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,8 +2386,8 @@
23862386
Avoid hard to diagnose or non-portable constructs.
23872387
\effect
23882388
Names of attribute identifiers may not be used as macro names. Valid \CppIII{}
2389-
code that defines \tcode{override}, \tcode{final},
2390-
\tcode{carries_dependency}, or \tcode{noreturn} as macros is invalid in this
2389+
code that defines \tcode{override}, \tcode{final}, or
2390+
\tcode{noreturn} as macros is invalid in this
23912391
revision of \Cpp{}.
23922392

23932393
\rSec2[diff.cpp03.language.support]{\ref{support}:

source/declarations.tex

Lines changed: 3 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -9550,86 +9550,6 @@
95509550
\end{codeblock}
95519551
\end{example}
95529552

9553-
\rSec2[dcl.attr.depend]{Carries dependency attribute}%
9554-
\indextext{attribute!carries dependency}
9555-
9556-
\pnum
9557-
The \grammarterm{attribute-token} \tcode{carries_dependency} specifies
9558-
dependency propagation into and out of functions.
9559-
No
9560-
\grammarterm{attribute-argument-clause} shall be present. The attribute may be
9561-
applied to a parameter of a function or lambda, in
9562-
which case it specifies that the initialization of the parameter carries a
9563-
dependency to\iref{intro.multithread} each lvalue-to-rvalue
9564-
conversion\iref{conv.lval} of that object. The attribute may also be applied
9565-
to a function or a lambda call operator, in which case it
9566-
specifies that the return value, if any, carries a dependency to the evaluation
9567-
of the function call expression.
9568-
9569-
\pnum
9570-
The first declaration of a function shall specify the \tcode{carries_dependency} attribute for its
9571-
\grammarterm{declarator-id} if any declaration of the function specifies the
9572-
\tcode{carries_dependency} attribute. Furthermore, the first declaration of a function shall specify
9573-
the \tcode{carries_dependency} attribute for a parameter if any declaration of that function
9574-
specifies the \tcode{carries_dependency} attribute for that parameter. If a function or one of its
9575-
parameters is declared with the \tcode{carries_dependency} attribute in its first declaration in one
9576-
translation unit and the same function or one of its parameters is declared without the
9577-
\tcode{carries_dependency} attribute in its first declaration in another translation unit, the
9578-
program is ill-formed, no diagnostic required.
9579-
9580-
\pnum
9581-
\begin{note}
9582-
The \tcode{carries_dependency} attribute does not change the meaning of the
9583-
program, but might result in generation of more efficient code.
9584-
\end{note}
9585-
9586-
\pnum
9587-
\begin{example}
9588-
\begin{codeblock}
9589-
/* Translation unit A. */
9590-
9591-
struct foo { int* a; int* b; };
9592-
std::atomic<struct foo *> foo_head[10];
9593-
int foo_array[10][10];
9594-
9595-
[[carries_dependency]] struct foo* f(int i) {
9596-
return foo_head[i].load(memory_order::consume);
9597-
}
9598-
9599-
int g(int* x, int* y [[carries_dependency]]) {
9600-
return kill_dependency(foo_array[*x][*y]);
9601-
}
9602-
9603-
/* Translation unit B. */
9604-
9605-
[[carries_dependency]] struct foo* f(int i);
9606-
int g(int* x, int* y [[carries_dependency]]);
9607-
9608-
int c = 3;
9609-
9610-
void h(int i) {
9611-
struct foo* p;
9612-
9613-
p = f(i);
9614-
do_something_with(g(&c, p->a));
9615-
do_something_with(g(p->a, &c));
9616-
}
9617-
\end{codeblock}
9618-
9619-
The \tcode{carries_dependency} attribute on function \tcode{f} means that the
9620-
return value carries a dependency out of \tcode{f}, so that the implementation
9621-
need not constrain ordering upon return from \tcode{f}. Implementations of
9622-
\tcode{f} and its caller may choose to preserve dependencies instead of emitting
9623-
hardware memory ordering instructions (a.k.a.\ fences).
9624-
Function \tcode{g}'s second parameter has a \tcode{carries_dependency} attribute,
9625-
but its first parameter does not. Therefore, function \tcode{h}'s first call to
9626-
\tcode{g} carries a dependency into \tcode{g}, but its second call does not. The
9627-
implementation might need to insert a fence prior to the second call to
9628-
\tcode{g}.
9629-
\end{example}
9630-
\indextext{attribute|)}%
9631-
\indextext{declaration|)}
9632-
96339553
\rSec2[dcl.attr.deprecated]{Deprecated attribute}%
96349554
\indextext{attribute!deprecated}
96359555

@@ -10106,3 +10026,6 @@
1010610026
could have the same address as \tcode{buckets}
1010710027
if their respective types are all empty.
1010810028
\end{example}
10029+
10030+
\indextext{attribute|)}%
10031+
\indextext{declaration|)}

source/future.tex

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,9 @@
854854
void atomic_init(volatile atomic<T>*, typename atomic<T>::value_type) noexcept;
855855
template<class T>
856856
void atomic_init(atomic<T>*, typename atomic<T>::value_type) noexcept;
857+
template<class T>
858+
constexpr T kill_dependency(T y) noexcept; // freestanding
859+
inline constexpr memory_order memory_order_consume = memory_order::consume; // freestanding
857860

858861
#define @\libmacro{ATOMIC_VAR_INIT}@(value) @\seebelow@
859862
}
@@ -924,3 +927,24 @@
924927
\end{codeblock}
925928
\end{example}
926929
\end{itemdescr}
930+
931+
\rSec2[depr.atomics.order]{\tcode{memory_order::consume}}
932+
933+
\indexlibrarymember{consume}{memory_order}%
934+
\pnum
935+
The memory_order enumeration contains an additional enumerator:
936+
\begin{codeblock}
937+
consume = 1
938+
\end{codeblock}
939+
The \tcode{memory_order::consume} enumerator is allowed wherever
940+
\tcode{memory_order::acquire} is allowed, and it has the same meaning.
941+
942+
\begin{itemdecl}
943+
template<class T> constexpr T kill_dependency(T y) noexcept;
944+
\end{itemdecl}
945+
946+
\begin{itemdescr}
947+
\pnum
948+
\returns
949+
\tcode{y}.
950+
\end{itemdescr}

source/preprocessor.tex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,6 @@
400400
\topline
401401
\lhdr{Attribute} & \rhdr{Value} \\ \rowsep
402402
\tcode{assume} & \tcode{202207L} \\
403-
\tcode{carries_dependency} & \tcode{200809L} \\
404403
\tcode{deprecated} & \tcode{201309L} \\
405404
\tcode{fallthrough} & \tcode{201603L} \\
406405
\tcode{likely} & \tcode{201803L} \\

0 commit comments

Comments
 (0)