On 09/18/2017 06:19 AM, Florian Weimer wrote:
I would like to see the GCC project to document that if the address of a member is taken, this does not constitute an access to the object as a whole.That is, in the following code: #include <stdatomic.h> struct S { _Atomic int a; int b; }; int load_a (struct S *p) { return atomic_load_explicit (&p->a, memory_order_relaxed); } int store_b (struct S *p, int b) { p->b = b; } If one thread calls load_a and another thread calls store_b on the same struct S *, no data race happens. This is an extension over the C standard because of the way “->” is defined. C requires that E1->E2 it is evaluated as (*(E1))->E2, and *E1 is defined as an access to the entire struct, so there is a data race in load_a with the assignment in store_b.
It's true that E1->E2 is equivalent to (*(E1))->E2 (this is made clear in C11 by Footnote 96) but C doesn't use the term "access" in the definition of the * operator. The * operator is defined to result in an lvalue that designates an object, and operator . to evaluate the first operand, which doesn't imply accessing it. If E1->E2 implied accessing all members of *E1 then there would be no way to assign an initial value to just the E2 member without also accessing all other members of *E1, even those that haven't yet been initialized. Martin
