Prev: The noexcept keyword, deprecated exception specifications and compilers
Next: Microsoft chooses to leave C++ compiler broken
From: Arno on 17 Mar 2010 01:59 Hello, is this correct C++ code? enum E { e1, e2 }; int func(E e) { int arr[]={3,4}; return arr[e==e1]; } I have an optimized Visual C++ 8 build where arr is accessed with some large value, neither 0 nor 1. I am wondering whether this is a compiler bug. TIA, Arno -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Goran on 17 Mar 2010 12:17 On Mar 17, 5:59 pm, Arno <ascho...(a)think-cell.com> wrote: > Hello, > > is this correct C++ code? > > enum E { e1, e2 }; > > int func(E e) { > int arr[]={3,4}; > return arr[e==e1]; > > } > > I have an optimized Visual C++ 8 build where arr is accessed with some > large value, neither 0 nor 1. I am wondering whether this is a > compiler bug. Highly unlikely. If you think that has a bug, then look at the generated disassembly. Code is simple enough for the bug to be easily visible. There is a much bigger chance that you have a bug elsewhere that you somehow connected to this place in your code. Goran. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Johannes Schaub (litb) on 17 Mar 2010 12:12 Arno wrote: > Hello, > > is this correct C++ code? > > enum E { e1, e2 }; > > int func(E e) { > int arr[]={3,4}; > return arr[e==e1]; > } > > I have an optimized Visual C++ 8 build where arr is accessed with some > large value, neither 0 nor 1. I am wondering whether this is a > compiler bug. > Code looks alright. a[i] is equivalent to *((a)+(i)) for which it is said "The additive operators + and - group left-to-right. The usual arithmetic conversions are performed for operands of arithmetic or enumeration type.", which will convert any boolean to 1 or 0. Accessing it with an index other than 0 or 1 is a bug in the compiler. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Daniel Krügler on 17 Mar 2010 12:17 On 17 Mrz., 17:59, Arno <ascho...(a)think-cell.com> wrote: > Hello, > > is this correct C++ code? > > enum E { e1, e2 }; > > int func(E e) { > int arr[]={3,4}; > return arr[e==e1]; > } > > I have an optimized Visual C++ 8 build where arr is accessed with some > large value, neither 0 nor 1. I am wondering whether this is a > compiler bug. It is undecidable to decide whether the snippet will result in an ill-formed program without a complete program available. Depending on your actual attempt to assign a numeric value to an E you might run into undefined behavior, because of overflow, thus it might happen anything. Let's say we complete the program with the following code: int main() { func(E(2)); } The relevant parts of the C++03 standard that rule this are [dcl.enum]/5: "The underlying type of an enumeration is an integral type that can represent all the enumerator values defined in the enumeration. It is implementation-defined which integral type is used as the underlying type for an enumeration except that the underlying type shall not be larger than int unless the value of an enumerator cannot fit in an int or unsigned int.[..]" and p.6: "For an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values of the underlying type in the range bmin to bmax, where bmin and bmax are, respectively, the smallest and largest values of the smallest bit-field that can store emin and emax.81) It is possible to define an enumeration that has values not defined by any of its enumerators." This wording gives latitude to unsigned or signed underlying types, also depending on the integer representation kind (In C++0x such an enum must have an underlying integral type that is unsigned, see core issue 58). Given an unsigned underlying type, bmax is 1 in the example. The wording that directly affects above example is given in p.9 of aforementioned subclause: "An expression of arithmetic or enumeration type can be converted to an enumeration type explicitly. The value is unchanged if it is in the range of enumeration values of the enumeration type; otherwise the resulting enumeration value is unspecified." And similarly in [expr.static.cast]/7 nearly identical: "A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting enumeration value is unspecified." The problem in the wording is "in the range of enumeration values", which is not restricted by the value domain of the underlying type, but instead by the range bmin-bmax. In the example the bmax = 1 and value E(2) has an unspecified value within E. The current C++ wording can be interpreted in a way that it could allow an aggressive compiler to perform optimizations based on the assumption that the values must be within bmin and bmax. If I correctly remember, there will be a corresponding core issue added in the next updated issue list. HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Daniel Krügler on 18 Mar 2010 07:32
On 18 Mrz., 04:17, Daniel Kr�gler <daniel.krueg...(a)googlemail.com> wrote: > On 17 Mrz., 17:59, Arno <ascho...(a)think-cell.com> wrote: [..] > In the example the bmax = 1 and value E(2) has an > unspecified value within E. The current C++ wording > can be interpreted in a way that it could allow > an aggressive compiler to perform optimizations > based on the assumption that the values must be > within bmin and bmax. If I correctly remember, > there will be a corresponding core issue added > in the next updated issue list. Rereading this, I notice that the text can easily be misinterpreted. While it is true, that there is some issue involved with the current specification of enumeration values outside it's ranges, this case seems not to apply in your situation. It could happen in other situations as in: int func2(E e) { if (e > 1) throw e; // # int arr[] = {3,4}; return arr[e==e1]; } #include <iostream> int main() { try { func2(E(2)); } catch(E e) { std::cerr << "Invalid enum value: " << int(e) << std::endl; } } In this situation a C++ compiler is currently allowed to optimize the line marked with # (including the complete try/catch frame within main) away. The most likely origin of your problem without any further data available is, that you caused an overflow on a enum with signed underlying type (OK in C++03, not OK in C++0x given your example enumeration type E), which has undefined behavior. In this case the funny bool bit patterns are easily explained as traces of the higher bits that remain in the destination register during conversion to bool. HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |