This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [patch] aout+coff: Fix strict-aliasing rules error
- From: Pedro Alves <palves at redhat dot com>
- To: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- Cc: binutils at sourceware dot org
- Date: Wed, 9 Mar 2016 00:48:44 +0000
- Subject: Re: [patch] aout+coff: Fix strict-aliasing rules error
- Authentication-results: sourceware.org; auth=none
- References: <20160308135706 dot GA3994 at host1 dot jankratochvil dot net> <56DEE362 dot 2000002 at redhat dot com> <20160308204650 dot GA10607 at host1 dot jankratochvil dot net>
On 03/08/2016 08:46 PM, Jan Kratochvil wrote:
On Tue, 08 Mar 2016 15:36:18 +0100, Pedro Alves wrote:
Not clear to me why this is producing a warning. This seems like a gcc trunk
regression that should be reported and fixed in gcc instead. It's valid
to cast the pointer to a struct to a pointer to its initial member and back.
See C99 6.7.2.1 point 13 [1], or C11 6.7.2.1 point 15 [2].
"A pointer to a structure object, suitably converted, points to its
initial member (...), and vice versa."
I do not see the implication there myself but I have therefore filed it:
[6 Regression?] false strict-aliasing warning
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70143
Thanks. From your reduced test:
struct a {
int i;
};
struct b {
struct a a;
int j;
};
int main(void) {
static struct b b;
struct a *ap=(struct a *)&b;
return ((struct b *)&ap->i)->j;
}
Since 'int i' is the first field of 'struct a',
and 'struct a a' is the first field of 'struct b',
per C11 6.7.2.1 point 15, you can do:
// b -> a -> int
struct b b;
struct a *ap = (struct a *) &b;
int *ip = (int *) &ap->i;
assert ((void * )ip == (void *) &b);
// int -> a -> b
struct a *ap2 = (struct a *) ip;
struct b *bp2 = (struct b *) ap2;
assert (bp2 == &b);
IOW, '&b', 'ip', 'ap', 'ap2', and 'bp2' may, and do,
all alias each other, and that's not a violation.
Thus, since ip can alias bp2, transitively, a direct cast
from ip -> bp2 should be fine too then:
-struct a *ap2 = (struct a *) ip;
-struct b *bp2 = (struct b *) ap2;
+struct b *bp2 = (struct b *) ip;
assert (bp2 == &b);
Thus, I think that the compiler should know that transitively:
((struct b *) &ap->i)->j;
and:
((struct b *) (struct a *) &ap->i)->j;
are equivalent.
The latter seems to work around the warning, BTW.
But I may certainly be missing something. I think it's better
to wait for what the compiler experts say.
Thanks,
Pedro Alves