Here's a simple example of where -Wuninitialized is rather useless at default optimization: $ cat foo.c #include <stdlib.h> int main(void) { char *oops; free(oops); void *other = #ifdef RELIABLE NULL #else &oops #endif ; return !other; } $ gcc -Werror -Wall -Wuninitialized -o foo -c foo.c $ gcc -Werror -Wall -Wuninitialized -o foo -c foo.c -DRELIABLE foo.c: In function ‘main’: foo.c:5:9: error: ‘oops’ is used uninitialized in this function [-Werror=uninitialized] free(oops); ^ cc1: all warnings being treated as errors $ gcc -Werror -Wall -Wuninitialized -o foo -c foo.c -O2 foo.c: In function ‘main’: foo.c:5:9: error: ‘oops’ is used uninitialized in this function [-Werror=uninitialized] free(oops); ^ cc1: all warnings being treated as errors $ gcc -Werror -Wall -Wuninitialized -o foo -c foo.c -DRELIABLE -O2 foo.c: In function ‘main’: foo.c:5:9: error: ‘oops’ is used uninitialized in this function [-Werror=uninitialized] free(oops); ^ cc1: all warnings being treated as errors I understand that -O2 enables better uninitialization checks, but I find it quite awkward that even without -O2, the mere taking an address of a variable hides it from the uninit checker. My end goal is to have a macro that does a one-shot evaluation of its argument: #define FREE(x) { typeof(x) *_x = &(x); free(*_x); *_x = NULL; } for safety, but that macro kills -Wuninit checking by virtue of the fact that it takes the address of the pointer. Even if I limit myself to a macro that evaluates its argument more than once (and forcing me to audit code to avoid FREE(side-effects) - if only there were a way to make the compiler automatically barf if it encounters side effects in a macro argument), I am unable to come up with a way to get the uninit checking that gcc provides regardless of optimization without also having the safety of ensuring the pointer isn't abused after the fact.
So you want the warning even with -O0? I am not sure that, without optimization, the internal representation can detect this case.
Note that this has nothing to do with the fact that the uninitialized var is a pointer: void test(char); int main(void) { char oops; test(oops); char *other = &oops; return !other; }
Since the engine is able to warn at -O0 when I _don't_ take the address, I don't see why the warning is lost by the mere action of taking the address.
The warning machinery is only able to warn about vars in SSA form, vars which must live in memory can't be warned on easily. So, for such variables you only get warnings if the compiler is able as part of some optimization make the var non-addressable (e.g. inlining and propagation can help that, etc.), or scalar replacement of aggregates is able to break appart larger aggregates and use SSA form for those. Thus, you get better warnings with optimizations.
*** Bug 58711 has been marked as a duplicate of this bug. ***
Jakub's comments in c#4 are 100% accurate. This isn't something we're going to change/fix. Sorry.