On Tue, 2017-09-19 at 07:19 +0200, Florian Weimer wrote: > On 09/18/2017 10:07 PM, Torvald Riegel wrote: > > On Mon, 2017-09-18 at 14:19 +0200, 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. > > > > There is no data race in this example; a and b are separate objects as > > far as the memory model is concerned. That's my understanding and I > > believe also the understanding in the C++ committee. > > I'm not sure what the C++ standard says in this matter. > > C++ may indeed have addressed this and related issues (e.g., that a > memory location which is passed by reference to a function is not > actually read in the caller).
The memory models of C and C++ are intended to be the same. In the example above, the values of p in both calls are supposed to be equal, so accesses go to the same object of type S; as far as the memory model is concerned, a and b are separate objects. > >> 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. > > > > If ISO C really says that this is potentially a data race, then that's a > > bug in the standard I'd say. I see no need to have an extension for > > this (module there potentially being a real bug in the standard). > > GCC relies on the implicit access to the full struct object in this case: > > struct T { > int a; > int b; > }; > > int > opt (struct T *p1, struct T *p2) > { > p1->a = 1; > p2->b = 2; > return p1->a; > } This example isn't about data races anymore, because the program effectively asserts that there are no concurrent accesses to p1->a or p2->b. Nonetheless, I see that you are wondering what forbids aliasing of p1->a and p2->b. I don't know enough about (the standardese around) unions to comment on what precisely would prevent aliasing through unions.