The answer to this question is covered in proposal: Fixing the rules for type-based aliasing which we will see, unfortunately was not resolved in 2010 when the proposal was made which is covered in Hedquist, Bativa, November 2010 minutes . Therefore C11 does not contain a resolution to N1520
, so this is an open issue:
There does not seem to be any way that this matter will be
resolved at this meeting. Each thread of proposed approaches
leads to more questions. 1 1:48 am, Thurs, Nov 4, 2010.
ACTION – Clark do more work in
N1520
opens saying (emphasis mine going forward):
Richard Hansen pointed out a problem in the type-based aliasing
rules, as follows:
My question concerns the phrasing of bullet 5 of 6.5p7 (aliasing as it applies to unions/aggregates). Unless my understanding of
effective type is incorrect, it seems like the union/aggregate
condition should apply to the effective type, not the lvalue type.
Here are some more details:
Take the following code snippet as an example:
union {int a; double b;} u;
u.a = 5;
From my understanding of the definition of effective type (6.5p6), the effective type of the object at location &u is union {int a;
double b;}. The type of the lvalue expression that is accessing the
object at &u (in the second line) is int.
From my understanding of the definition of compatible type (6.2.7), int is not compatible with union {int a; double b;}, so
bullets 1 and 2 of 6.5p7 do not apply. int is not the signed or
unsigned type of the union type, so bullets 3 and 4 do not apply. int
is not a character type, so bullet 6 does not apply.
That leaves bullet 5. However, int is not an aggregate or union
type, so that bullet also does not apply. That means that the above
code violates the aliasing rule, which it obviously should not.
I believe that bullet 5 should be rephrased to indicate that if the
effective type (not the lvalue type) is an aggregate or union type
that contains a member with type compatible with the lvalue type, then
the object may be accessed.
Effectively, what he points out is that the rules are asymmetrical
with respect to struct/union membership. I have been aware of this
situation, and considered it a (non-urgent) problem, for quite some
time. A series of examples will better illustrate the problem. (These
examples were originally presented at the Santa Cruz meeting.)
In my experience with questions about whether aliasing is valid based
on type constraints, the question is invariably phrased in terms of
loop invariance. Such examples bring the problem into extremely sharp
focus.
And the relevant example that applies to this situation would be 3
which is as follows:
struct S { int a, b; };
void f3(int *pi, struct S *ps1, struct S const *ps2)
{
for (*pi = 0; *pi < 10; ++*pi) {
*ps1++ = *ps2;
}
}
The question here is whether the object *ps2 may be accessed (and
especially modified) by assigning to the lvalue *pi — and if so,
whether the standard actually says so. It could be argued that this is
not covered by the fifth bullet of 6.5p7, since *pi does not have
aggregate type at all.
**Perhaps the intention is that the question should be turned around: is
it allowed to access the value of the object pi by the lvalue ps2.
Obviously, this case would be covered by the fifth bullet.
All I can say about this interpretation is that it never occurred to
me as a possibility until the Santa Cruz meeting, even though I've
thought about these rules in considerable depth over the course of
many years. Even if this case might be considered to be covered by the
existing wording, I'd suggest that it might be worth looking for a
less opaque formulation.
The following discussion and proposed solutions are very long and hard to summarize but seems to end with a removal of the aforementioned bullet five and resolve the issue with adjustments to other parts of 6.5
. But as noted above this issues involved were not resolvable and I don't see a follow-up proposal.
So it would seem the standard wording permits the scenario the OP demonstrates although my understanding is that this was unintentional and therefore I would avoid it and it could potentially change in later standards to be non-conforming.