From: Arno on
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
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
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
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
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! ]