Ahh, no, it's not a version thing. I didn't read the man page carefully enough:
Code:
-Wstrict-aliasing
This option is only active when -fstrict-aliasing is active. It warns about code
which might break the strict aliasing rules that the compiler is using for
optimization. The warning does not catch all cases, but does attempt to catch the
more common pitfalls. It is included in -Wall. It is equivalent to
-Wstrict-aliasing=3
-Wstrict-aliasing=n
This option is only active when -fstrict-aliasing is active. It warns about code
which might break the strict aliasing rules that the compiler is using for
optimization. Higher levels correspond to higher accuracy (fewer false positives).
Higher levels also correspond to more effort, similar to the way -O works.
-Wstrict-aliasing is equivalent to -Wstrict-aliasing=n, with n=3.
Level 1: Most aggressive, quick, least accurate. Possibly useful when higher levels
do not warn but -fstrict-aliasing still breaks the code, as it has very few false
negatives. However, it has many false positives. Warns for all pointer conversions
between possibly incompatible types, even if never dereferenced. Runs in the frontend
only.
Level 2: Aggressive, quick, not too precise. May still have many false positives (not
as many as level 1 though), and few false negatives (but possibly more than level 1).
Unlike level 1, it only warns when an address is taken. Warns about incomplete types.
Runs in the frontend only.
Level 3 (default for -Wstrict-aliasing): Should have very few false positives and few
false negatives. Slightly slower than levels 1 or 2 when optimization is enabled.
Takes care of the common pun+dereference pattern in the frontend:
"*(int*)&some_float". If optimization is enabled, it also runs in the backend, where
it deals with multiple statement cases using flow-sensitive points-to information.
Only warns when the converted pointer is dereferenced. Does not warn about incomplete
types.
<snip>
-fstrict-aliasing
Allow the compiler to assume the strictest aliasing rules applicable to the language
being compiled. For C (and C++), this activates optimizations based on the type of
expressions. In particular, an object of one type is assumed never to reside at the
same address as an object of a different type, unless the types are almost the same.
For example, an "unsigned int" can alias an "int", but not a "void*" or a "double". A
character type may alias any other type.
Pay special attention to code like this:
union a_union {
int i;
double d;
};
int f() {
union a_union t;
t.d = 3.0;
return t.i;
}
The practice of reading from a different union member than the one most recently
written to (called "type-punning") is common. Even with -fstrict-aliasing, type-
punning is allowed, provided the memory is accessed through the union type. So, the
code above will work as expected. However, this code might not:
int f() {
union a_union t;
int* ip;
t.d = 3.0;
ip = &t.i;
return *ip;
}
Similarly, access by taking the address, casting the resulting pointer and
dereferencing the result has undefined behavior, even if the cast uses a union type,
e.g.:
int f() {
double d = 3.0;
return ((union a_union *) &d)->i;
}
The -fstrict-aliasing option is enabled at levels -O2, -O3, -Os.
I left off the -fstrict-aliasing flag (-Wall includes -Wstrict-aliasing, but not -fstrict-aliasing). It turns out I get the same error:
Code:
$ gcc -Wall -Wextra -fstrict-aliasing -std=c99 -o foo foo.c
foo.c: In function ‘main’:
foo.c:8:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
According to the man page (the middle paragraph of the -fstrict-aliasing option), with strict aliasing enabled, you are allowed to do this via unions, but not via type casts. This actually comes from the C standard:
Originally Posted by
C99 6.5 p7
7 An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:74)
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the
object,
— a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
74) The intent of this list is to specify those circumstances in which an object may or may not be aliased.
Looks like -fstrict-aliasing causes GCC to adhere to this particular part of the standard.