https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102800
Bug ID: 102800 Summary: Incorrect UB warning with aggressive-loop-optimizations Product: gcc Version: 11.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: phil at phord dot com Target Milestone: --- I found this spurious warning occurs since gcc 11.1. It does not occur in 10.3 or previous versions that I tested. I believe this is a different bug from PR100801 because that bug started appearing in 9.1. This bug seems to be very sensitive to changes from this minimal code: ----------------[ Source ]----------------- /* Compiled with: gcc-11 -O2 -c test.c */ void bar(char x); void foo(char * begin) { // end = ALIGN(begin, 8); char * end = begin + 7 - ((((unsigned long)begin) - 1) % 8); if (begin != end) { long long x = end - begin; do bar(x); while(--x != 0); } } static char buff[1024] = { 0 }; void test(int i) { foo(buff + i * 8); } ------------[ Compiler output ]------------- In function 'void foo(char*)', inlined from 'void test(int)' at <source>:16:8: <source>:9:19: warning: iteration 0x8000000000000000 invokes undefined behavior [-Waggressive-loop-optimizations] 9 | while(--x != 0); | ~~~~^~~~ <source>:9:19: note: within this loop -------------------------------------------- Notice we don't enter the loop unless x will be greater than zero because of the `begin != end` check, and because end >= begin due to the ALIGN math. The compiled code appears to be correct. Only the spurious warning is a problem. (In fact, the compiled code is optimized out where the warning is generated because the inlined function has nothing to do. But the code is called from elsewhere, so size and correctness matter, of course.) I found several workarounds: > Change x to unsigned. Produces exact same obj output but no warning: unsigned long long x = end - begin; > Change x to short (int16_t). Produces exact same obj output but no warning: short x = end - begin; > Compare with > 0 instead of != 0. Compiled output is 1 opcode longer: while(--x > 0); > Use calculated x value to determine whether to enter loop. long long x = end - begin; if (x > 0) do bar(x); while(--x != 0); ---- I just noticed this bug (spurious warning) appears in 9.3 and earlier if I change this line from != to <: if (begin < end) { I guess it is this subtle difference that I think is a new bug. But maybe this is a dup of PR100801 after all.