[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #20 from Marc Glisse --- (In reply to Vincent Lefèvre from comment #18) > OK, but then, this means that the first sentence of the > -Wmaybe-uninitialized documentation is incorrect. That's probably the "there > exists" that is problematic, because of the possible difference of what > actually exists and what the compiler sees. "There exists" is implicitly "in the internal representation at some specific stage in the optimization process", not directly in the user's code. This applies to any middle-end warning. If you want to suggest some clearer documentation...
[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #19 from Manuel López-Ibáñez --- (In reply to Vincent Lefèvre from comment #18) > OK, but then, this means that the first sentence of the > -Wmaybe-uninitialized documentation is incorrect. That's probably the "there > exists" that is problematic, because of the possible difference of what > actually exists and what the compiler sees. I don't disagree but a bug report about that will just linger forever without any useful information. Sending a documentation patch and convincing the middle-end reviewers will be more effective. Also, the same is true for any middle-end warning: https://gcc.gnu.org/wiki/cauldron2018?action=AttachFile=get=Static_Analysis_in_GCC_Middle-End.pdf
[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #18 from Vincent Lefèvre --- OK, but then, this means that the first sentence of the -Wmaybe-uninitialized documentation is incorrect. That's probably the "there exists" that is problematic, because of the possible difference of what actually exists and what the compiler sees.
[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 Manuel López-Ibáñez changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution|--- |INVALID --- Comment #17 from Manuel López-Ibáñez --- I don't think this is a bug. GCC warns at higher levels because it can inline. Doing more optimization at -O2 is a separate issue.
[Bug tree-optimization/60165] "may be used uninitialized" warning with -O3 but not with -O2
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #16 from Manuel López-Ibáñez --- (In reply to Vincent Lefèvre from comment #15) > Well, detecting uninitialized variables is equivalent to generating better > code. See the following functions. If you want to be able to remove the i == > 0 test in the first one (making generated code better), you'll solve the > warning problem in the second one. Not really, the pass that generates better code may happen after the pass that warns. And heuristics that generate better code often hide warnings: PR18501 Neither generating better code nor warning are exact methods. They rely on heuristics. The warnings are even more sensitive, because the goal of the compiler is to generate better code, not to produce accurate warnings, so information that is useful for warning is not maintained throughout. And then, there are heuristics such as not warning for f(), by assuming that it will initialize c, that are implemented because they are more often right than wrong, but they are sometimes wrong. When it can be established that they were wrong (after inlining, for example), then warnings are given. You seem to be assuming that void g1(int *p); int f1() { int c; g1(); return c; /* warn maybe-uninit */ } int g2(); int f2() { int c = g2(); return c; /* warn maybe-uninit */ } int h(int p) { int c; if (p) c = 1; return c; /* warn maybe-uninit */ } are equivalent in terms of being maybe uninitialized, and all should either be warned or not warned about. But in practice, f1() and f2() are most often a false positive and h() is almost always a real bug.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 Jakub Jelinek jakub at gcc dot gnu.org changed: What|Removed |Added CC||jakub at gcc dot gnu.org --- Comment #1 from Jakub Jelinek jakub at gcc dot gnu.org --- I don't see anything strange on it, -Wmaybe-uninitialized is a middle-end warning and as such very much depends on the optimizations, there is no guarantee you get the same warnings between different optimization levels, whether something is found as potentially uninitialized depends heavily e.g. on inlining, tail recursion etc. In this case at -O3 the function is first inlined into itself a small amount of times. I don't see anything wrong to warn here, given that the variable indeed is not initialized in some code paths (if fn2 returns zero).
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #2 from Vincent Lefèvre vincent-gcc at vinc17 dot net --- Well, the code paths in question do not necessarily exist (you could say the same thing with -O2, where the function is not inlined: there may be some code paths for which fn1() doesn't initialize c). Actually the number of maybe-uninitialized warnings should decrease when the optimization level increases, because of additional knowledge, not the opposite.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 Jakub Jelinek jakub at gcc dot gnu.org changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution|--- |INVALID --- Comment #3 from Jakub Jelinek jakub at gcc dot gnu.org --- (In reply to Vincent Lefèvre from comment #2) Well, the code paths in question do not necessarily exist (you could say the same thing with -O2, where the function is not inlined: there may be some code paths for which fn1() doesn't initialize c). The code path exists in the code, the fact that perhaps in your program such code path is never taken doesn't mean it is undesirable to warn about it. GCC has two kinds of warnings, the is uninitialized one where particular code, if executed, will always use uninitialized value, and maybe uninitialized, where it will use uninitialized value only conditionally. That is the case here. Actually the number of maybe-uninitialized warnings should decrease when the optimization level increases, because of additional knowledge, not the opposite. No, usually with more inlining it increases and should. When fn1 is not inlined, GCC intentionally does not warn that c might be uninitialized because maybe the function call could use the value or not set it unconditionally, that would lead to so huge amount of false positives for the warning that nobody would be willing to use the warning.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #4 from Richard Biener rguenth at gcc dot gnu.org --- (In reply to Jakub Jelinek from comment #3) (In reply to Vincent Lefèvre from comment #2) Well, the code paths in question do not necessarily exist (you could say the same thing with -O2, where the function is not inlined: there may be some code paths for which fn1() doesn't initialize c). The code path exists in the code, the fact that perhaps in your program such code path is never taken doesn't mean it is undesirable to warn about it. GCC has two kinds of warnings, the is uninitialized one where particular code, if executed, will always use uninitialized value, and maybe uninitialized, where it will use uninitialized value only conditionally. That is the case here. Where it of course still only assumes that the function is entered at all.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #5 from Vincent Lefèvre vincent-gcc at vinc17 dot net --- (In reply to Jakub Jelinek from comment #3) The code path exists in the code, It exists *only* if fn2() can return 0. But the fact is that in the reality, this can never happen (with the original non-reduced code, this can even be proved). the fact that perhaps in your program such code path is never taken doesn't mean it is undesirable to warn about it. GCC has two kinds of warnings, the is uninitialized one where particular code, if executed, will always use uninitialized value, and maybe uninitialized, where it will use uninitialized value only conditionally. That is the case here. But in this case, the warning is missing with -O2. No, usually with more inlining it increases and should. When fn1 is not inlined, GCC intentionally does not warn that c might be uninitialized because maybe the function call could use the value or not set it unconditionally, that would lead to so huge amount of false positives for the warning that nobody would be willing to use the warning. This is the same problem with -O3: there is a false positive here. So, you have to choose whether you want to avoid false positives or not.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #6 from Jakub Jelinek jakub at gcc dot gnu.org --- How can the compiler know that fn2 never returns 0, without inlining (not in this case), some attribute (not provided, gcc right now has returns_nonnull attribute but that is only for pointers) or some interprocedural analysis)? Of course, if you want zero false positives, the uninitialized warnings could not exist, even if you do: int foo (void) { int c; return c; } you could say that warning here is a false positive, because you might actually never call that function. For -O2 we don't warn, because then the compiler does see an opaque call that might be initializing what the arguments points to, might not, but warning in that case would just mean too many false positives as I've said before. While for -O3, when it is inlined a few times, the compiler clearly sees code paths where the value is uninitialized, and has nothing that would hint such code paths are impossible. Of course, if fn2 is guaranteed to return non-NULL, why do you even write if (fn2 (a, 0)) *p1 = b; rather than just fn2 (a, 0); *p1 = b; ?
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #7 from Vincent Lefèvre vincent-gcc at vinc17 dot net --- (In reply to Jakub Jelinek from comment #6) How can the compiler know that fn2 never returns 0, without inlining (not in this case), some attribute (not provided, gcc right now has returns_nonnull attribute but that is only for pointers) or some interprocedural analysis)? It doesn't know with -O3, but it doesn't know either with -O2 as well. That's my point (see below). For -O2 we don't warn, because then the compiler does see an opaque call that might be initializing what the arguments points to, might not, but warning in that case would just mean too many false positives as I've said before. I think it should. Or you should avoid the false positives with -O3 too. Of course, if fn2 is guaranteed to return non-NULL, why do you even write if (fn2 (a, 0)) *p1 = b; rather than just fn2 (a, 0); *p1 = b; ? That's because of creduce. But it seems that I've managed to make the warning disappear with both -O2 and -O3 even when it is clear that the value is not initialized. More later...
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 Vincent Lefèvre vincent-gcc at vinc17 dot net changed: What|Removed |Added Status|RESOLVED|UNCONFIRMED Resolution|INVALID |--- --- Comment #8 from Vincent Lefèvre vincent-gcc at vinc17 dot net --- (In reply to Vincent Lefèvre from comment #5) It exists *only* if fn2() can return 0. But the fact is that in the reality, this can never happen (with the original non-reduced code, this can even be proved). After an analysis of the MPFR code, it actually seems to be a bug in MPFR. So, the problem is the missing warning with -O2. The -Wmaybe-uninitialized rule given in the gcc man page is (for GCC 4.8): -Wmaybe-uninitialized For an automatic variable, if there exists a path from the function entry to a use of the variable that is initialized, but there exist some other paths for which the variable is not initialized, the compiler emits a warning if it cannot prove the uninitialized paths are not executed at run time. [...] This rule does *not* depend on the optimization level, except for the if it cannot prove the uninitialized paths are not executed at run time part. Indeed, the fact that a path exists or not is not something that depends on the optimizations. Concerning the if it cannot prove the uninitialized paths are not executed at run time part, GCC should be able to prove more things with -O3 than with -O2, meaning that -Wmaybe-uninitialized warnings could disappear with -O3 compared to -O2, but generally not the opposite. In the original example, GCC cannot prove anything about run time, so that according to the gcc man page, one should get a warning whatever the optimization level. I've another example (similar to the MPFR code): int fn3 (void); void fn2 (int *p) { if (fn3 ()) *p = 0; } int fn1 (void) { int c; fn2 (c); return c; } GCC doesn't give any may be used uninitialized warning (whether -O2 or -O3 is used). This is incorrect according to the above rule. BTW, for -O3, this is surprising because it is similar to the original example. I'm reopening the bug because the GCC behavior doesn't match the documentation.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #9 from Marc Glisse glisse at gcc dot gnu.org --- (In reply to Vincent Lefèvre from comment #8) The -Wmaybe-uninitialized rule given in the gcc man page is (for GCC 4.8): -Wmaybe-uninitialized For an automatic variable, if there exists a path from the function entry to a use of the variable that is initialized, but there exist some other paths for which the variable is not initialized, the compiler emits a warning if it cannot prove the uninitialized paths are not executed at run time. [...] This rule does *not* depend on the optimization level, except for the if it cannot prove the uninitialized paths are not executed at run time part. Indeed, the fact that a path exists or not is not something that depends on the optimizations. The definition of a function changes with inlining ;-) Concerning the if it cannot prove the uninitialized paths are not executed at run time part, GCC should be able to prove more things with -O3 than with -O2, meaning that -Wmaybe-uninitialized warnings could disappear with -O3 compared to -O2, but generally not the opposite. In the original example, GCC cannot prove anything about run time, so that according to the gcc man page, one should get a warning whatever the optimization level. f(i) is considered as an initialization of i. This heuristic is necessary, otherwise the number of false positives would make the warning useless. I've another example (similar to the MPFR code): int fn3 (void); void fn2 (int *p) { if (fn3 ()) *p = 0; } int fn1 (void) { int c; fn2 (c); return c; } GCC doesn't give any may be used uninitialized warning (whether -O2 or -O3 is used). This is incorrect according to the above rule. BTW, for -O3, this is surprising because it is similar to the original example. A different optimization pass (CCP) seems to notice that the value returned is either 0 or something uninitialized and thus must be 0. Maybe there is an opportunity for a warning there (though again we need to make sure it won't cause too many false positives). I don't know why you think warnings should be so well defined. They have always been a heuristic compromise.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #10 from Manuel López-Ibáñez manu at gcc dot gnu.org --- (In reply to Vincent Lefèvre from comment #8) Concerning the if it cannot prove the uninitialized paths are not executed at run time part, GCC should be able to prove more things with -O3 than with -O2, meaning that -Wmaybe-uninitialized warnings could disappear with -O3 compared to -O2, but generally not the opposite. Your assumption is mistaken because you don't seem to realize something that Jakub has said repeatedly. GCC doesn't warn *on purpose* for very common code such as { int c; f(c); return c; } if GCC doesn't know what is going on within f(), because that will trigger a lot of false positives (although it is easy to build testcases where warning would have been warranted). At -O3, that code may be converted to { int c; if (g()) c = 3 return c; } and then, even though g() may never return false, if GCC cannot prove that, then GCC will warn, because not warning will case a lot of false negatives. Such design decisions are based on experience. Now, I agree that ideally, GCC should warn for your last testcase. But I guess in that case inlining either doesn't happen or it happens too late, so GCC only sees the first case. The analysis that GCC performs are predicated on the transformations leading to better code, otherwise they are not performed. A tool for static analysis will surely inline as much as it could, not matter if the code is slower or larger, but this is not how GCC works because GCC is not a tool for static analysis. On the other hand, GCC has bugs (missed optimizations, PR24639), and it would be nice if more people worked on those, but this PR doesn't look like one.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 Manuel López-Ibáñez manu at gcc dot gnu.org changed: What|Removed |Added CC||manu at gcc dot gnu.org --- Comment #11 from Manuel López-Ibáñez manu at gcc dot gnu.org --- (In reply to Marc Glisse from comment #9) A different optimization pass (CCP) seems to notice that the value returned is either 0 or something uninitialized and thus must be 0. Maybe there is an opportunity for a warning there (though again we need to make sure it won't cause too many false positives). Actually this missed warning is the infamous PR18501.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #12 from Jakub Jelinek jakub at gcc dot gnu.org --- Only in your reading of the documentation. You clearly don't know what you are asking for, even the very common case of pthread_t th; if (pthread_create (th, NULL, tf, NULL)) goto fail; pthread_join (th, NULL); case would need to be warned about, even when there is nothing wrong about it. In your testcase, if fn1 isn't inlined, it is the same thing for GCC, a function call as a black box which could do anything to the memory pointed to by the escaped pointer (unless the function is say pure or const, at which point it couldn't store to it). If it is inlined, the compiler sees it, sees that a variable is used and in certain path has uninitialized value and in others initialized, and correctly warns.
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #13 from Marc Glisse glisse at gcc dot gnu.org --- (In reply to Manuel López-Ibáñez from comment #10) Now, I agree that ideally, GCC should warn for your last testcase. But I guess in that case inlining either doesn't happen or it happens too late, so GCC only sees the first case. Actually it is the reverse, inlining happens earlier in this new testcase (the first example was recursive, which makes the inliner more conservative). The analysis that GCC performs are predicated on the transformations leading to better code, otherwise they are not performed. A tool for static analysis will surely inline as much as it could, not matter if the code is slower or larger, but this is not how GCC works because GCC is not a tool for static analysis. Maybe we could have a wiki page explaining what options to tweak (inlining parameters, etc) for a compilation where you are only interested in warnings? (I had vaguely mentioned creating -Ow at some point, but that didn't seem such a good idea)
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #14 from Vincent Lefèvre vincent-gcc at vinc17 dot net --- (In reply to Marc Glisse from comment #9) The definition of a function changes with inlining ;-) It shouldn't: what happens at run time isn't changed by inlining. f(i) is considered as an initialization of i. This heuristic is necessary, otherwise the number of false positives would make the warning useless. Perhaps, but this isn't documented. I don't know why you think warnings should be so well defined. According to the gcc man page, it is well-defined: the rule is given explicitly. (In reply to Jakub Jelinek from comment #12) In your testcase, if fn1 isn't inlined, it is the same thing for GCC, a function call as a black box which could do anything to the memory pointed to by the escaped pointer (unless the function is say pure or const, at which point it couldn't store to it). Here you assume that the function can do anything, while Marc said that GCC assumes that i is initialized. There's a contradiction. Moreover in the case of MPFR, the called function is in the same preprocessed source file, so that it is not obvious for the user that GCC will see it as a black box (when not inlined).
[Bug tree-optimization/60165] may be used uninitialized warning with -O3 but not with -O2
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60165 --- Comment #15 from Vincent Lefèvre vincent-gcc at vinc17 dot net --- (In reply to Manuel López-Ibáñez from comment #10) Now, I agree that ideally, GCC should warn for your last testcase. But I guess in that case inlining either doesn't happen or it happens too late, so GCC only sees the first case. The analysis that GCC performs are predicated on the transformations leading to better code, otherwise they are not performed. A tool for static analysis will surely inline as much as it could, not matter if the code is slower or larger, but this is not how GCC works because GCC is not a tool for static analysis. Well, detecting uninitialized variables is equivalent to generating better code. See the following functions. If you want to be able to remove the i == 0 test in the first one (making generated code better), you'll solve the warning problem in the second one. int f(void) { int i = 0; /* some code that sets i to a nonzero value, but difficult to prove */ if (i == 0) abort(); return i; } int f(void) { int i; /* some code that sets i to a nonzero value, but difficult to prove */ return i; }