For reference, here's the restrict
qualifier's rather convoluted definition (from C99 6.7.3.1 "Formal definition of restrict"):
Let D be a declaration of an ordinary
identifier that provides a means of
designating an object P as a
restrict-qualified pointer to type T.
If D appears inside a block and
does not have storage class
extern, let B denote the block. If D
appears in the list of parameter
declarations of a function
definition, let B denote the
associated block. Otherwise, let B
denote 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 E is said to be based on
object P if (at some sequence point
in the execution of B prior to the
evaluation of E) modifying P to point
to a copy of the array object into
which it formerly pointed would change
the value of E. Note that "based" is
defined only for expressions with
pointer types.
During each execution of B, let L be
any lvalue that has &L based on P. If
L is used to access the value of the
object X that it designates, and X is
also modified (by any means), then the
following requirements apply: T shall
not be const-qualified. Every other
lvalue used to access the value of X
shall also have its address based on
P. Every access that modifies X shall
be considered also to modify P, for
the purposes of this subclause. If P
is assigned the value of a pointer
expression E that is based on another
restricted pointer object P2,
associated with block B2, then either
the execution of B2 shall begin before
the execution of B, or the
execution of B2 shall end prior to
the assignment. If these
requirements are not met, then the
behavior is undefined.
Here an execution of B means that
portion of the execution of the
program that would correspond to the
lifetime of an object with scalar type
and automatic storage duration
associated with B.
My reading of the above means that in your first question, a
cannot be assigned to b
, even inside a "child" block - the result is undefined. Such an assignment could be made if b
were declared in that 'sub-block', but since b
is declared at the same scope as a
, the assignment cannot be made.
For question 2, the assignments between c
and d
also result in undefined behavior (in both cases).
The relevant bit from the standard (for both questions) is:
If P is assigned the value of a
pointer expression E that is based on
another restricted pointer object P2,
associated with block B2, then either
the execution of B2 shall begin before
the execution of B, or the
execution of B2 shall end prior to
the assignment.
Since the restricted pointers are associated with the same block, it's not possible for block B2 to begin before the execution of B, or for B2 to end prior to the assignment (since B and B2 are the same block).
The standard gives an example that makes this pretty clear (I think - the clarity of the restrict
definition's 4 short paragraphs is on par with C++'s name resolution rules):
EXAMPLE 4:
The rule limiting assignments between
restricted pointers does not
distinguish between a function call
and an equivalent nested block.
With one exception, only
"outer-to-inner" assignments between
restricted pointers declared in nested
blocks have defined behavior.
{
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
}
}