I find that:
int * _Atomic foo ;
int bar[12] ;
foo = bar ;
foo += 4 ; // foo -> &bar[4] -- of course
foo = bar ;
atomic_fetch_add(&foo, 4) ; // foo -> &bar[1] -- ????
which, I confess, I did not quite expect. (Happy I looked, though !)
So, I looked at the Standard:
7.17.7.5 The atomic_fetch and modify generic functions
1 The following operations perform arithmetic and bitwise
computations. All of these operations are applicable to an
object of any atomic integer type. None of these
operations is applicable to atomic_bool.
Of course, "integer type" excludes pointers, so I guess what it does
with pointers is undefined.
Should gcc be throwing a friendly warning here ?
But the Standard goes on to say:
3 ... For signed integer types ... there are no undefined
results. ...
... For address types, the result may be an undefined
address, but the operations otherwise have no undefined
behavior.
I don't know why it feels the need to mention "address types", given
that they are not valid arguments ? [I'm assuming that by "address
types" it actually means "pointer types". I can find no other mention
of "address type".]
The "Synopsis" says:
2 #include <stdatomic.h>
<C> atomic_fetch_<key>(volatile <A> *object, <M> operand);
<C> atomic_fetch_<key>_explicit(volatile <A> *object,
<M> operand, memory_order order);
and the meaning of <A>, <C> and <M> is given in "7.17.1 Introduction",
as follows:
5 In the following synopses:
- An <A> refers to one of the atomic types.
- A <C> refers to its corresponding non-atomic type.
- An <M> refers to the type of the other argument for
arithmetic operations. For atomic integer types, <M>
is <C>. For atomic pointer types, <M> is ptrdiff_t.
As it happens, <M> only used in the Synopsis for atomic_fetch_<key>...
which is not defined for pointer types ?
I realise this is not really the place for discussion of the Standard,
but I assume that what gcc does is based on some interpretation of it.
Is there a good place to look for that interpretation ?
Chris
--------------------------
FWIW (1): the functions in gcc/glibc's <stdatomic.h> do *not* require
the various <A> arguments to be atomic types... they are perfectly happy
with ordinary types. That doesn't seem right to me.
FWIW (2): the Standard (later in 7.17.7.5) says:
5 NOTE The operation of the atomic_fetch and modify generic
functions are nearly equivalent to the operation of the
corresponding op= compound assignment operators. The only
differences are that the compound assignment operators are
not guaranteed to operate atomically, ...
Except that "6.5.16.2 Compound assignment" says:
3 A compound assignment of the form E1 op= E2 ...
... If E1 has an atomic type, compound assignment is a
read-modify-write operation with memory_order_seq_cst
memory order semantics.
which looks like a flat contradiction to me.