First some references. The C99 Standard says this about restrict in section 6.7.3:
An object that is accessed through a restrict-qualified pointer has a special association with that pointer. This association, defined in 6.7.3.1 below, requires that all accesses to that object use, directly or indirectly, the value of that particular pointer.117) The intended use of the
restrictqualifier (like theregisterstorage class) is to promote optimization, and deleting all instances of the qualifier from all preprocessing translation units composing a conforming program does not change its meaning (i.e., observable behavior).
And then (§6.7.3.1 "Formal definition of restrict"):
Let
Dbe a declaration of an ordinary identifier that provides a means of designating an objectPas a restrict-qualified pointer to typeT.If
Dappears inside a block and does not have storage classextern, letBdenote the block. IfDappears in the list of parameter declarations of a function definition, letBdenote the associated block. Otherwise, letBdenote the block of main (or the block of whatever function is called at program startup in a freestanding environment).In what follows, a pointer expression
Eis said to be based on objectPif (at some sequence point in the execution ofBprior to the evaluation ofE) modifyingPto point to a copy of the array object into which it formerly pointed would change the value ofE.119) Note that ''based'' is defined only for expressions with pointer types.During each execution of
B, letLbe any lvalue that has&Lbased onP. IfLis used to access the value of the objectXthat it designates, andXis also modified (by any means), then the following requirements apply:Tshall not be const-qualified. Every other lvalue used to access the value ofXshall also have its address based onP. Every access that modifiesXshall be considered also to modifyP, for the purposes of this subclause. IfPis assigned the value of a pointer expressionEthat is based on another restricted pointer objectP2, associated with blockB2, then either the execution ofB2shall begin before the execution ofB, or the execution ofB2shall end prior to the assignment. If these requirements are not met, then the behavior is undefined.
As some have pointed out, this illustrates the rules (Example 4 from the standard):
{
int * restrict p1;
int * restrict q1;
p1 = q1; // undefined behavior
{
int * restrict p2 = p1; // valid
int * restrict q2 = q1; // valid
p1 = q2; // undefined behavior
p2 = q2; // undefined behavior
}
}
Now, my first question is this: why is it okay to assign from an outer restricted pointer to an inner one?
My understanding is that nothing forbids this, which has clear aliasing:
int * restricted x = /* ... */ ;
{
int * restricted y = x;
*x = 3;
printf("%d\n", *y); // 3
*y = 4;
printf("%d\n", *x); // 4
}
Of course, the set of aliases is restricted to the two pointers.
Hence my second question: what is the difference assigning from outer to inner (allowed), but not from inner to outer (forbidden, e.g. p1 = q1; in the first example above)?