The following code (reduced from a larger testcase) when compiled at -O3 with gcc 4.7.2 produces an executable that does not terminate. Compiling with lower optimizations, current gcc trunk or the older 4.6.3 release at -O3, the executable terminates as expected. $ gcc-4.7 --version gcc-4.7 (GCC) 4.7.2 $ gcc-4.7 -O2 loop.c $ ./a.out $ gcc-4.6 -O3 loop.c $ ./a.out $ gcc-4.7 -O3 loop.c $ ./a.out <hangs> ^C $ cat loop.c int a, c, d = 1; struct { int f0; } b, f; short e; void fn1 (p1) { int g[] = { }; e = 0; for (; e != 1; e = e + 5) { int *h[] = {[0] & g[0] }; if (p1); else return; f = b; } } int main () { int i, j; i = 0; for (; i < 6; i++) { j = 8; for (; j; j--) a = 0; } fn1 (d); for (; c;); }
Works on the trunk.
Seems to have started with http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=181172 and fixed by http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=190614 Slightly cleaned up testcase: int a, c, d = 1; struct S { int s; } b, f; short e; void foo (int x) { int g[] = { }; for (e = 0; e != 1; e = e + 5) { int *h[1] = { &g[0] }; if (!x) return; f = b; } } int main () { int i, j; for (i = 0; i < 6; i++) for (j = 8; j; j--) a = 0; foo (d); while (c) ; return 0; }
Seems to me that 'e' is signed and the testcase relies on wrapping overflow (-fwrapv helps).
But e = e + 5 is avaluated as e = (short) ((int) e + 5) and thus I think it just falls down to implementation defined behavior (assuming short is smaller than int of course), because no overflow happens in the int type in which the addition is computed, and there is just cast of a larger int value to smaller short type.
You are right, of course. I remembered that gcc defined unsigned->signed conversion, but I had forgotten that it defined all narrowing conversions as well, sorry.
The fixing rev. doesn't make much sense ;) The issue must be still latent. > But e = e + 5 is avaluated as > e = (short) ((int) e + 5) not true before VRP2: short int e.2; short int e.4; ... <bb 3>: # e.2_4 = PHI <e.4_18(3), 0(2)> f = b; D.1777_45 = e.2_4 + 5; e.4_18 = D.1777_45; e = e.4_18; if (e.4_18 != 1) goto <bb 3>; else goto <bb 4>; which turns it into an endless loop. The FE shortened to e = (short int) ((short unsigned int) e + 5); but IVOPTs makes it short. There was a related bugfix by Zdenek for 4.8.
PR55481, backporting that fixes it. *** This bug has been marked as a duplicate of bug 55481 ***