Hi, On Wed, 12 Oct 2011, Jakub Jelinek wrote:
> > Assignment 2 means that t->p points to s.p. Assignment 3 changes t->p and > > s.p, but the change to s.p doesn't occur through a pointer based on t->p > > or any other restrict pointer, in fact it doesn't occur through any > > explicit initialization or assignment, but rather through in indirect > > access via a different pointer. Hence the accesses to the same memory > > object at s.p[0] and t->p[0] were undefined because both accesses weren't > > through pointers based on each other. > > Only the field p in the structure is restrict qualified, there is no > restrict qualification on the other pointers (e.g. t is not restrict). > Thus, it is valid that t points to s. And, s.p[0] access is based on s.p > as well as t->p and similarly t->p[0] access is based on s.p as well as > t->p, in the sense of the ISO C99 restrict wording. IMO reading the standard to allow an access to be based "on s.p _as well as_ t->p" and that this should result in any sensible behaviour regarding restrict is interpreting too much into it. Let's do away with the fields, trying to capture the core of the disagreement. What you seem to be saying is that this code is well-defined and shouldn't return 1: int foo (int * _a, int * _b) { int * restrict a = _a; int * restrict b = _b; int * restrict *pa = wrap (&a); *pa = _b; // 1 *a = 0; **pa = 1; return *a; } I think that would go straight against the intent of restrict. I'd read the standard as making the above trick undefined. > Because, if you change t->p (or s.p) at some point in between t->p = q; > and s.p[0]; (i.e. prior to the access) to point to a copy of the array, > both s.p and t->p change. Yes, but the question is, if the very modification of t->p was valid to start with. In my example above insn 1 is a funny way to write "a = _b", i.e. reassigning the already set restrict pointer a to the one that also is already in b. Simplifying the above then leads to: int foo (int * _a, int * _b) { int * restrict a = _a; int * restrict b = _b; a = _b; *a = 0; *b = 1; return *a; } which I think is undefined because of the fourth clause (multiple modifying accesses to the same underlying object X need to go through one particular restrict chain). Seen from another perspective your reading would introduce an inconsistency with composition. Let's assume we have this function available: int tail (int * restrict a, int * restrict b) { *a = 0; *b = 1; return *a; } Clearly we can optimize this into { *a=0;*b=1;return 0; } without looking at the context. Now write the testcase or my example above in terms of that function: int goo (int *p, int *q) { struct S s, *t; s.a = 1; s.p = p; // 1 t = wrap(&s); // 2 t=&s in effect, but GCC doesn't see this t->p = q; // 3 return tail (s.p, t->p); } Now we get the same behaviour of returning a zero. Something must be undefined here, and it's not in tail itself. It's either the call of tail, the implicit modification of s.p with writes to t->p or the existence of two separate restrict pointers of the same value. I think the production of two separate equal-value restrict pointers via indirect modification is the undefinedness, and _if_ the standard can be read in a way that this is supposed to be valid then it needs to be clarified to not allow that anymore. I believe the standard should say something to the effect of disallowing modifying restrict pointers after they are initialized/assigned to once. Ciao, Michael.