When compiling mpfr-2.3.1 with gcc-4.3, one gets the following warning (among others): {{{ lngamma.c: In function 'mpfr_lngamma_aux': lngamma.c:160: warning: 'B' may be used uninitialized in this function }}} However, looking at the code shows that this variable cannot be used uninitialized: * a variable Bm is initialized to zero * if Bm=0, B is initialized using an auxiliary function, and Bm is set to 2 (this code is in a do { ... } while loop, thus is always executed)
It is most likely the case, that we have to use predicated PHI nodes to detect that the variable is no unitialized.
The severity should probably be changed to enhancement because gcc behaves as documented (well, almost). What can be done IMHO is: 1. Split the -Wuninitialized into two different warnings: one for which gcc knows that the variable is uninitialized and one for which it cannot decide. -Wuninitialized currently does both. 2. Provide an extension so that the user can tell gcc not to emit a warning for some particular variable. This would sometimes be better than adding a dummy initialization (which has its own drawbacks). In the mean time, make the documentation better concerning -Wuninitialized: change the first sentence "Warn if an automatic variable is used without first being initialized [...]" to "Warn if an automatic variable *may be* used without first being initialized" (though the behavior is detailed later).
A way to tell gcc a variable is not uninitialized is to perform self-initialization like int i = i; this will cause no code generation but inhibits the warning. Other compilers may warn about this construct of course.
(In reply to comment #3) > A way to tell gcc a variable is not uninitialized is to perform > self-initialization like > > int i = i; This doesn't seem to be valid C code. > this will cause no code generation but inhibits the warning. Other compilers > may warn about this construct of course. Or worse, generate non-working code.
BTW, the i = i trick, which is guaranteed to be valid and no-op only *after* i has been initialized doesn't avoid the warning in such a case. I don't know if this would be a good feature (the main drawback I can see would be to miss warnings when this is a result of macro expansion). For instance: #include <assert.h> int foo (int x) { int y; assert (x == 0 || x == 1); if (x == 0) y = 1; else if (x == 1) y = 2; y = y; /* to tell the compiler that y has been initialized */ return y; }
(In reply to comment #5) > BTW, the i = i trick it only works in the initializer and not as a statement after the fact. That is: #include <assert.h> int foo (int x) { int y = y; assert (x == 0 || x == 1); if (x == 0) y = 1; else if (x == 1) y = 2; return y; } Will work, also with the jump threading, GCC should be able to figure out that y is always inlined (except when -DNDEBUG is used). -- Pinski
(In reply to comment #6) > (In reply to comment #5) > > BTW, the i = i trick > > it only works in the initializer and not as a statement after the fact. But in such a case, as i is not initialized yet, this may be undefined behavior with some C implementations.
Please provide a preprocessed reduced testcase as similar to the original as possible. I think this is not only predicated PHI but our representation of loops may also have something to do.
(In reply to comment #8) > Please provide a preprocessed reduced testcase as similar to the original as > possible. Here's a similar testcase. $ cat tst.c void *foo (void); void bar (void *); void f (void) { int init = 0; void *p; while (1) { if (init == 0) { p = foo (); init = 2; } bar (p); } } $ gcc -Wall -O2 tst.c -c tst.c: In function 'f': tst.c:7: warning: 'p' may be used uninitialized in this function This is quite strange: if I replace the value 2 by 1 or if I replace foo() by 0, the warning is no longer displayed. Note: in the reality (in MPFR), the variable I called init here is the size of the array (0 when the array hasn't been allocated yet).
(In reply to comment #9) > (In reply to comment #8) > > Please provide a preprocessed reduced testcase as similar to the original as > > possible. > > Here's a similar testcase. Thanks. This is the optimized SSA dump: f () { voidD.39 * pD.1952; intD.0 initD.1951; # BLOCK 2 freq:1 # PRED: ENTRY [100.0%] (fallthru,exec) # SUCC: 3 [100.0%] (fallthru,exec) # BLOCK 3 freq:10000 # PRED: 2 [100.0%] (fallthru,exec) 5 [100.0%] (fallthru,dfs_back,exec) # initD.1951_1 = PHI <0(2), initD.1951_2(5)> # pD.1952_3 = PHI <pD.1952_6(D)(2), pD.1952_4(5)> [/home/manuel/src/pr36296.c : 11] if (initD.1951_1 == 0) goto <bb 4>; else goto <bb 5>; # SUCC: 4 [29.0%] (true,exec) 5 [71.0%] (false,exec) # BLOCK 4 freq:2900 # PRED: 3 [29.0%] (true,exec) [/home/manuel/src/pr36296.c : 13] # SMT.10D.1967_13 = VDEF <SMT.10D.1967_10> { SMT.10D.1967 } pD.1952_7 = fooD.1945 (); # SUCC: 5 [100.0%] (fallthru,exec) # BLOCK 5 freq:10000 # PRED: 3 [71.0%] (false,exec) 4 [100.0%] (fallthru,exec) # initD.1951_2 = PHI <initD.1951_1(3), 2(4)> # pD.1952_4 = PHI <pD.1952_3(3), pD.1952_7(4)> [/home/manuel/src/pr36296.c : 16] # SMT.10D.1967_14 = VDEF <SMT.10D.1967_11> { SMT.10D.1967 } barD.1947 (pD.1952_4); [/home/manuel/src/pr36296.c : 17] goto <bb 3>; # SUCC: 3 [100.0%] (fallthru,dfs_back,exec) } Because we create a PHI node for p in BB 3, we think that p can be used uninitialized. Notice also that we are not able to move the 'if' and the call to foo() out of the infinite loop. This is perhaps a missed optimization. > This is quite strange: if I replace the value 2 by 1 or if I replace foo() by > 0, the warning is no longer displayed. If you replace foo() by 0, then CCP just assumes the p is always 0. In fact, it will remove p altogether, even if you use 'if (init == 2)', thus missing a real uninitialized use. This behaviour is known to hide warnings, both correct and wrong warnings. If I replace the value 2 by 1 I still get the warning in GCC 4.4, so that really sounds strange. Are you sure about that? Anyway, this is a confirmed bug but not easy to fix.
(In reply to comment #10) > If I replace the value 2 by 1 I still get the warning in GCC 4.4, so that > really sounds strange. Are you sure about that? Yes and here Debian's GCC 4.4 snapshot has the same behavior as GCC 4.3.1 (also from Debian). Also, the optimized trees are not the same for 1 and 2. vin% cat tst.c void *foo (void); void bar (void *); void f (void) { int init = 0; void *p; while (1) { if (init == 0) { p = foo (); init = INIT; } bar (p); } } vin% gcc --version gcc.real (Debian 4.3.1-9) 4.3.1 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. vin% gcc -Wall -O2 tst.c -c -fdump-tree-optimized -DINIT=1 vin% cat tst.c.126t.optimized ;; Function f (f) Analyzing Edge Insertions. f () { void * p; <bb 2>: p = foo (); <bb 3>: bar (p); goto <bb 3>; } vin% gcc -Wall -O2 tst.c -c -fdump-tree-optimized -DINIT=2 tst.c: In function 'f': tst.c:7: warning: 'p' may be used uninitialized in this function vin% cat tst.c.126t.optimized ;; Function f (f) Analyzing Edge Insertions. f () { void * p; int init; <bb 2>: init = 0; <bb 3>: if (init == 0) goto <bb 4>; else goto <bb 5>; <bb 4>: p = foo (); init = 2; <bb 5>: bar (p); goto <bb 3>; } vin% /usr/lib/gcc-snapshot/bin/gcc --version gcc (Debian 20080802-1) 4.4.0 20080802 (experimental) [trunk revision 138551] Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. vin% /usr/lib/gcc-snapshot/bin/gcc -Wall -O2 tst.c -c -DINIT=1 vin% /usr/lib/gcc-snapshot/bin/gcc -Wall -O2 tst.c -c -DINIT=2 tst.c: In function 'f': tst.c:7: warning: 'p' may be used uninitialized in this function vin%
The key difference is -ftree-vrp (which is enabled at -O2). With INIT=2, it is missing the obvious optimization that it detects with INIT=1. I wonder if this is expected (after all, it is value-RANGE-propagation) or there is a PR open about this. Notice that any two consecutive integers trigger the optimization 0,1 but also 1,2 and thus remove the bogus uninitialized warning.
*** Bug 37361 has been marked as a duplicate of this bug. ***
(In reply to comment #8) > Please provide a preprocessed reduced testcase as similar to the original as > possible. > > I think this is not only predicated PHI but our representation of loops may > also have something to do. > I'm not sure whether following warrants a new bug entry so doing it here, sorry, if it was inappropriate. Following code, triggers: "repro.c:5: warning: 'b' may be used uninitialized in this function" with 4.3.0 and 4.3.1 on PowerPC when invoked like this: gcc -c -O -Wuninitialized repro.c int f (void); int g (int a) { int b; if (a) b = f (); asm volatile ("#"); if (a) return b; return 1; }
(In reply to comment #14) > I'm not sure whether following warrants a new bug entry so doing it here, > sorry, > if it was inappropriate. That is a different case. This PR is about loops. Your case is about initialization and use guarded by the same predicate. I think there is already a bug report for this. But it is always better to open a new bug report in case of doubt.
(In reply to comment #3) > A way to tell gcc a variable is not uninitialized is to perform > self-initialization like > > int i = i; > > this will cause no code generation but inhibits the warning. Other compilers > may warn about this construct of course. What makes things worse about this workaround is that even protecting this by a #if defined(__GNUC__) may not be sufficient as other compilers may claim GNUC compatibility and behave differently. This is the case of clang (at least under Debian): http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=705583 The only good solution would be to fix the bug. I've checked that it is still there in the trunk revision 197260 (current Debian's gcc-snapshot).
(In reply to comment #16) > (In reply to comment #3) > > A way to tell gcc a variable is not uninitialized is to perform > > self-initialization like > > > > int i = i; > > > > this will cause no code generation but inhibits the warning. Other compilers > > may warn about this construct of course. > The only good solution would be to fix the bug. I've checked that it is still > there in the trunk revision 197260 (current Debian's gcc-snapshot). If you mean to fix the false warning, then you are likely to wait a long long time (in order of years) because it doesn't seem a trivial thing to fix and there are very very few people with enough GCC knowledge to fix it (and they are busy with other things). What would be trivial to fix (but require persistence, patience and time) is to implement this idea: http://gcc.gnu.org/ml/gcc/2010-08/msg00297.html that is, either __attribute__ ((initialized)) or _Pragma("GCC diagnostic ignored \"-Wuninitialized\""). (Personally, I prefer the latter, since it reuses existing code). Add as a follow-up, get rid of the non-portable valgrind-unfriendly i=i idiom that has caused so much grief over the years. However, we still need someone with the persistence, patience and time to implement this and get it past the powers that be.
In fact, we should have removed the i=i idiom a long time ago. The correct thing to do (as Linus says) is to initialize the variable to a sensible value to silence the warning: http://lwn.net/Articles/529954/ If GCC is smart enough to remove the initialization, then there is no harm. If GCC is not smart enough, then the code is probably complex enough that GCC cannot optimize it properly and this is why it gives a false positive, so the fake initialization is the least of your worries.
(In reply to comment #2) > 1. Split the -Wuninitialized into two different warnings: one for which gcc > knows that the variable is uninitialized and one for which it cannot decide. > -Wuninitialized currently does both. Note that -Wmaybe-uninitialized is available since at least GCC 4.8.0
(In reply to comment #18) > In fact, we should have removed the i=i idiom a long time ago. The correct > thing to do (as Linus says) is to initialize the variable to a sensible value > to silence the warning: http://lwn.net/Articles/529954/ There is no real sensible value except some trap value. Letting the variable uninitialized at that point (the declaration) allows some tools, like the Formalin compiler described in WG14/N1637, to detect potential problems if the variable is really used uninitialized. (In reply to comment #19) > Note that -Wmaybe-uninitialized is available since at least GCC 4.8.0 OK, so a solution would be to add a configure test for projects that don't want such warnings (while still using -Wall) to see whether -Wno-maybe-uninitialized is supported.
(In reply to comment #20) > OK, so a solution would be to add a configure test for projects that don't want > such warnings (while still using -Wall) to see whether -Wno-maybe-uninitialized > is supported. When an unrecognized warning option is requested (e.g., -Wunknown-warning), GCC will emit a diagnostic stating that the option is not recognized. However, if the -Wno- form is used, the behavior is slightly different: No diagnostic will be produced for -Wno-unknown-warning unless other diagnostics are being produced. This allows the use of new -Wno- options with old compilers, but if something goes wrong, the compiler will warn that an unrecognized option was used.
(In reply to comment #20) > (In reply to comment #18) > > In fact, we should have removed the i=i idiom a long time ago. The correct > > thing to do (as Linus says) is to initialize the variable to a sensible value > > to silence the warning: http://lwn.net/Articles/529954/ > > There is no real sensible value except some trap value. Letting the variable > uninitialized at that point (the declaration) allows some tools, like the > Formalin compiler described in WG14/N1637, to detect potential problems if the > variable is really used uninitialized. That doesn't contradict my assessment above that i=i idiom should die. With the Pragma one can choose to ignore GCC warnings if they don't want to initialize the value. The trap value would be an additional improvement, but someone needs to implement it. Clang has fsanitize=undefined-trap: http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation
(In reply to comment #21) > When an unrecognized warning option is requested (e.g., -Wunknown-warning), GCC > will emit a diagnostic stating that the option is not recognized. However, if > the -Wno- form is used, the behavior is slightly different: No diagnostic will > be > produced for -Wno-unknown-warning unless other diagnostics are being produced. That was mainly for pre-4.7 GCC versions, where without the i=i idiom, one would get the usual "may be used uninitialized in this function" warning because -Wno-maybe-uninitialized is not supported, but also the unrecognized command line option "-Wno-maybe-uninitialized" warning because there was already a warning. However this may not really be important.
BTW, since with the latest GCC versions (such as Debian's GCC 4.7.2), the warning is no longer issued with -Wno-maybe-uninitialized, perhaps the bug severity could be lowered to "enhancement".
All tests included in this BZ were tested and work fine on the trunk.
*** Bug 260998 has been marked as a duplicate of this bug. *** Seen from the domain http://volichat.com Page where seen: http://volichat.com/adult-chat-rooms Marked for reference. Resolved as fixed @bugzilla.