[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #25 from tony3 at GarlandConsulting dot us 2010-05-04 16:06 --- (In reply to comment #24) > G++ 4.6 will no longer optimize away the exit condition unless -fstrict-enums > is specified. > I'm very encouraged by this. Thanks for responding to this concern. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #24 from jason at gcc dot gnu dot org 2010-05-04 04:47 --- G++ 4.6 will no longer optimize away the exit condition unless -fstrict-enums is specified. -- jason at gcc dot gnu dot org changed: What|Removed |Added CC||jason at gcc dot gnu dot org http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #23 from tony3 at GarlandConsulting dot us 2010-01-28 17:16 --- Jonathan, Thanks for explaining that operation outside the norm is unspecified such that the compiler can do anything and everything. >I think a warning for this would be helpful, but asking for the compiler to >assume types can have values that they can't have is not a good idea. In the absence of making enumerations more useful (in the standard--which is unlikely), I completely agree: a warning would be helpful. Enough said by me. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #22 from jwakely dot gcc at gmail dot com 2010-01-28 10:13 --- (In reply to comment #14) > > So does the C++ standard say that it is acceptable for the compiler to drop > support for an out-of-range enumeration value in a way that the programmer has > no idea it happens--but to support out-of-range enumeration values in other > situations? The standard says nothing about warnings, a program is either correct or not. If it's not correct, the standard doesn't apply. The standard only defines what happens if you stick to its rules. It can't possibly legislate what happens if you go outside those rules, pretty much by definition. > In other words, if gcc is so provably correct according to the standard in > refusing to support an out-of-range-by-one enumeration value, why does it run > the code at lesser optimization levels? Couldn't the fact that it runs the > code > without complaint in the majority of cases by considered a bug? No. Undefined behaviour is undefined, not defined to behave consistently at all optimisation levels. I think a warning for this would be helpful, but asking for the compiler to assume types can have values that they can't have is not a good idea. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #21 from tony3 at GarlandConsulting dot us 2010-01-27 22:24 --- Thanks for that last example which does illustrate a condition where -O0 terminates and -O2 never does. So we've established there are other looping situations where the compiler does the same thing as in the enumeration examples above and converts a finite loop at -O0 to an infinite loop at -O2. So the enumeration behavior is not unique. But does that really establish that this what the compiler should do (I know it is "free to" do it, but should it)? Surely the bulk of programmers would find this surprising and disconcerting! Isn't it more likely to contribute to a serious failure in the field some day? Especially in situations where the enumeration values are well within an 8-bit quantity. In any event, I'm still wondering though about how similar in practice your example is to the enumeration situation? How much typical looping code is written as your example shows. In other words, it would be very rare to encounter in typical code. For one, you are not testing against a value at the top end of its defined range. I guess I don't have anything more to say by way of appeal other than this is one of those situations which may be "technically correct" and make some compiler implementers satisfied, but which will continue to trip up programmers who simply are trying to get something to work and are unaware of the dangers of combining enumeration range checks + enumeration values ending just before a power of two + -O2. Is it really true that providing a warning whenever a comparison results in an implied check against a value beyond the range of the native type would cause lots of grief for existing code? I guess I haven't seen situations where people make such comparisons and they don't expect them to work. Anyway, it seems clear I'm unable to make enough of a case to motivate gcc developers to consider changing the behavior of the compiler and we'll have to live with the situation. Thanks for your patience and explanations. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #20 from pinskia at gcc dot gnu dot org 2010-01-27 21:10 --- (In reply to comment #19) > Try: Actually that code is defined as signed char++ is defined to be signed char = (signed char) ((int)i + 1); by the C/C++ promotion rules. #include main() { for (signed i = 1 ; i >= -2 ; i++) { printf( "%d ", i); } } CUT --- That will cause different behavior at different optimization levels. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #19 from pinskia at gcc dot gnu dot org 2010-01-27 21:08 --- Try: #include main() { for (signed char i = 1 ; i >= -2 ; i++) { printf( "%d ", i); } } The first one will never overflow the integer range as you have i <= 127 which is always true with no overflow happening. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #18 from tony3 at GarlandConsulting dot us 2010-01-27 20:56 --- Thanks for the correction - I missed that aspect. However, a signed version of my simple example still upholds what I'm trying to comment on: it behaves the same way regardless of optimization level (at least as far as the loop exit is in view) -- a forever loop. #include main() { for (char i = 1 ; i <= 127 ; i++) { printf( "%d ", i); } } This program is always a forever loop, regardless of optimizer setting. The enumeration situation is not--which is my main point: trying to avoid surprising unexpected changes in operation as one changes the optimizer setting. Incidentally, in the above program, the actual print results differ between -O0 and -O2. At -O0 the printed values increment up to 127 and then, as expected change to -128 and count upwards. At -O2 the values increment up to 127 and then continue upward to huge positive integer values (e.g., I terminated the test at 4101552 and counting). It seems at -O2 that the value is no longer considered 8-bit signed. In any case, the forever loop remains a forever loop and doesn't morph into anything radically different. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #17 from pinskia at gcc dot gnu dot org 2010-01-27 20:43 --- > Your analogy is helpful, but a bit like comparing apples with oranges. The > reason being that the compiler executes integer overflow loops identically for > all optimization settings. Is it? unsigned integers don't overflow by definition. They wrap. Now signed integers overflow and change with different optimization levels. That is what I was trying to compare with this case, not unsigned integer wrapping. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #16 from tony3 at GarlandConsulting dot us 2010-01-27 20:39 --- Your analogy is helpful, but a bit like comparing apples with oranges. The reason being that the compiler executes integer overflow loops identically for all optimization settings. The following program compiles without warning at all optimization levels and executes as a forever loop in all cases: #include main() { for (unsigned char i = 1 ; i <= 255 ; i++) { printf( "%d ", i); } } This example supports my point that the compiler ought not to silently convert an exiting loop into a forever loop based on optimizer settings because in this case it consistently operates the same--and testing will be sure to catch it if it is unintended. Having now given up on trying to convince the gcc folks that enumeration testing would be greatly facilitated by extending the allowable comparison range by 1 (in both directions), my point has reduced itself to saying that the compiler is essentially whimsical and unpredictable in that code that runs as expected 99% of the time becomes an infinite loop without warning in the 1% case. This is not what happens with integer overflow. I submit that if the above integer example operated like enumerations--causing a terminated loop 99% of time but converting to a forever loop at -O2, then the compiler would have been modified long ago because lots more people would have been tripped up by it. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #15 from pinskia at gcc dot gnu dot org 2010-01-27 20:24 --- Think of overflow, it is overflowing the range. We don't warn for integer overflow for loops as that would make the noise level huge for most code. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #14 from tony3 at GarlandConsulting dot us 2010-01-27 20:03 --- Yes, I'm now aware that gcc "meets the minimal requirements" of the C++ standard. That isn't my point. My point is whether what it does is acceptable behavior given that there are no warnings or errors. And I'm suggesting that it should either: 1. Be modified to work with all enumeration values (in or out of range) that fit within a byte. This would make the compiler OPERATE THE SAME WAY in all scenarios in the lion's share of situations. 2. Issue a warning or error when the programmer accidentally relies upon values outside of the defined enumeration range: period. (For sure when the enumeration happens to have 3, 7, 15, 31, 63, 127, etc. as the largest value--but better in all cases.) The issue is that gcc, in its present operation does not help the programmer and in fact is misleading. It should either be practical and provide support for what many programmers expect--no matter what the optimization level--or it should flag it as bad code and refuse to run it at any optimization level. The situation where it silently accepts it and runs it in the 99% case, but then converts it silently to a forever loop in the 1% case is simply a recipe for trouble. So does the C++ standard say that it is acceptable for the compiler to drop support for an out-of-range enumeration value in a way that the programmer has no idea it happens--but to support out-of-range enumeration values in other situations? In other words, if gcc is so provably correct according to the standard in refusing to support an out-of-range-by-one enumeration value, why does it run the code at lesser optimization levels? Couldn't the fact that it runs the code without complaint in the majority of cases by considered a bug? -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #13 from pinskia at gcc dot gnu dot org 2010-01-27 19:10 --- Well the behavior as defined by the C++ standard is explicitly unspecified so GCC is ok to what it does. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #12 from tony3 at GarlandConsulting dot us 2010-01-27 19:01 --- Here's a modified version of the original code which is intended to show just how arbitrary the compiler optimization is from a programmer's perspective. Here are two loops: one exits as expected, the other does not. The only difference between the two loops is the use of an automatic variable in one of the two inline functions which test the exist condition. Is this really how you want gcc to operate? Is it truly acceptable to the general programming population that such a subtle difference in a supporting function can lead to a forever loop in one case and not in another? Both of the range testing functions perform the comparison with all their arguments promoted to int. Yet one never returns false. // Compile and run: g++ -O2 test.cpp && ./a.out #include enum ENUM_VALUE { ENUM_VALUE_FIRST = 1, ENUM_VALUE_A, ENUM_VALUE_B, ENUM_VALUE_C, ENUM_VALUE_D, ENUM_VALUE_E, ENUM_VALUE_LAST }; inline bool enumInRangeWorks(const ENUM_VALUE& eVal) { int val = eVal; return ( (static_cast(ENUM_VALUE_FIRST) <= val) && (val <= static_cast(ENUM_VALUE_LAST)) ); } inline bool enumInRangeFails(const ENUM_VALUE& eVal) { return ( (static_cast(ENUM_VALUE_FIRST) <= static_cast(eVal)) && (static_cast(eVal) <= static_cast(ENUM_VALUE_LAST)) ); } main() { printf("Compiled on %s %s\n", __DATE__, __TIME__); // This loop works correctly. The extra counter is not needed. unsigned int count = 0; for ( ENUM_VALUE id = ENUM_VALUE_FIRST; enumInRangeWorks(id); id = static_cast(id + 1) ) { printf("id=%d\n", id); // Should never need to exit this way. if (10 == count++) break; } printf("ENUMERATION COMPARISON "); printf("%s\n", count < 10? "WORKED" : "FAILED"); // This loop fails to exit. Without the special case additional // counter it results in a forever loop. count = 0; for ( ENUM_VALUE id = ENUM_VALUE_FIRST; enumInRangeFails(id); id = static_cast(id +1) ) { printf("id=%d\n", id); // Should never need to exit this way. if (10 == count++) break; } printf("ENUMERATION COMPARISON "); printf("%s\n", count < 10? "WORKED" : "FAILED"); } I'm sure the response is likely to be "the version that happens to work is invalid and therefore this is a moot point." That may be, but it does illustrate how misleading gcc is when it allows code like this to compile without warning and then behaves radically differently for minor variations. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #11 from rguenth at gcc dot gnu dot org 2010-01-20 17:40 --- Patches welcome to add diagnostics to the C++ frontend. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #10 from paolo dot carlini at oracle dot com 2010-01-20 15:48 --- Too bad, yes. -- paolo dot carlini at oracle dot com changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution||INVALID http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #9 from tony3 at GarlandConsulting dot us 2010-01-20 15:42 --- I am reopening this bug if only because I'd like to get a response to my previous comments. I can appreciated that, in your view, the compiler is 'technically correct' in making the assumption that it need not support programs which inadvertently generate an enumeration value outside of the defined range. But if you step back from this 'technical legitimacy', and look at the bigger picture, we are left with a compiler which is not doing much to help us write reliable code. In fact, it is doing just the opposite by silently accepting such code and even running it in the expected fashion when optimization is less than -O2. It is one thing to state that the compiler doesn't have to support a value which is greater than 1 less than the closest power of two, and another to make a compiler which usefully indicates when it refuses to follow where the programmer is directing it to go. All the more so when its refusal to implement an exit loop--indeed completely expunging the expected exit condition from the code--hinges on such a rare combination of incident: 1) optimization set at -O2, and 2) a maximum enumeration value which happens to fall just under a power of two. Unless this unhappy combination occurs, the code misleadingly does as the programmer expects. (Also, I would venture to say that many programmers would be extremely surprised to find that powers of 2 which fit well within 8-bits are apparently to be included in this behavior: 8, 16, 32, 64, 128.) So, given that those who know much more about enumerations and compilers than I ever will have decided that such behavior is not to be improved upon, why is it that we get no warning about it? Isn't the intention of warnings to indicate to the programmer when they have done something silly or dangerous where the results may differ from their expectations? Surely this situation falls into that category. The fact that there have been two bug reports in this regard and that a number of experienced programmers at my site found the resulting execution completely puzzling and unexpected would seem to indicate some sort of response beyond "this is technically acceptable therefore the bug report is INVALID . . . next!" is in order? -- tony3 at GarlandConsulting dot us changed: What|Removed |Added Status|RESOLVED|UNCONFIRMED Resolution|INVALID | http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #8 from tony3 at GarlandConsulting dot us 2010-01-20 00:18 --- I see what you mean. I was looking at the "wrong side" of the "<=" and not thinking about the reality that it would have to exceed the last valid value. Pretty obvious once you point it out. So now my question is why doesn't the compiler issue any warning about this? The result is a silent "forever loop" and the program hangs. Surely this is not what the programmer intended? I can appreciate that the compiler can make certain assumptions, but what I'm really trying to say here is that to truly be helpful in programming a compiler should either accept the code as valid (and try to do what is intended) or issue a warning or error saying it won't or might not. This is compounded by the fact that the code runs fine at lesser optimization levels--and compiles silently at all levels. So it is worse than silent, it is misleading in that it allows this poor programming practice during development only to turn it into a permanent hang in optimized production builds. :-) -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #7 from jakub at gcc dot gnu dot org 2010-01-19 23:56 --- This testcase also uses out of range enum value, so has undefined behavior as well. For ENUM_VALUE_LAST which is a power of 2 minus 1 the for loop condition still lets the body to be executed, then id = static_cast(id+1) i.e. id = static_cast(ENUM_VALUE_LAST+1) is the out of range value. The compiler can assume that no enum value is larger than ENUM_VALUE_LAST if it is a power of 2 minus 1 (i.e. the largest value of the underlying type). -- jakub at gcc dot gnu dot org changed: What|Removed |Added Status|UNCONFIRMED |RESOLVED Resolution||INVALID http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #6 from tony3 at GarlandConsulting dot us 2010-01-19 23:05 --- There is a related bug here: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36170 But unlike that bug which uses an out-of-range enum value, this case does not. We are testing 'value <= max_valid_enum_value'. So I've entered this as a different bug for reconsideration about how the compiler is handling valid enumeration values in -O2. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #5 from tony3 at GarlandConsulting dot us 2010-01-19 22:58 --- Created an attachment (id=19664) --> (http://gcc.gnu.org/bugzilla/attachment.cgi?id=19664&action=view) Assembler input which works correctly compiled at -O1 In this sample, the exit condition is properly tested as can be seen in the assembly listing. The difference between this file and test.s shows how the exit condition gets optimized out. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #4 from tony3 at GarlandConsulting dot us 2010-01-19 22:56 --- Created an attachment (id=19663) --> (http://gcc.gnu.org/bugzilla/attachment.cgi?id=19663&action=view) ARM gcc 4.4.1 output at assembler input level. This shows the same problem in gcc for the ARM. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #3 from tony3 at GarlandConsulting dot us 2010-01-19 22:54 --- Here is the compiler information: g++ -v Using built-in specs. Target: i586-suse-linux Configured with: ../configure --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib --libexecdir=/usr/lib --enable-languages=c,c++,objc,fortran,obj-c++,java,ada --enable-checking=release --with-gxx-include-dir=/usr/include/c++/4.3 --enable-ssp --disable-libssp --with-bugurl=http://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --disable-libgcj --with-slibdir=/lib --with-system-zlib --enable-__cxa_atexit --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --program-suffix=-4.3 --enable-version-specific-runtime-libs --enable-linux-futex --without-system-libunwind --with-cpu=generic --build=i586-suse-linux Thread model: posix gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #2 from tony3 at GarlandConsulting dot us 2010-01-19 22:53 --- Created an attachment (id=19662) --> (http://gcc.gnu.org/bugzilla/attachment.cgi?id=19662&action=view) Compiler output ready to feed to assembler--the problem can be seen here. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810
[Bug c++/42810] Enumeration with sequential values has its for-loop exit condition optimized out.
--- Comment #1 from tony3 at GarlandConsulting dot us 2010-01-19 22:53 --- Created an attachment (id=19661) --> (http://gcc.gnu.org/bugzilla/attachment.cgi?id=19661&action=view) Preprocessed version of the test.cpp file. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42810