This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [c++] switch ( enum ) vs. default statment.


PaweÅ Sikora wrote:

> typedef enum { X, Y } E;
> int f( E e )
> {
>         switch ( e )
>         {
>                 case X: return -1;
>                 case Y: return +1;
>         }
> }
> 
> In this example g++ produces a warning:
> 
> e.cpp: In function âint f(E)â:
> e.cpp:9: warning: control reaches end of non-void function
> 
> Adding `default' statemnet to `switch' removes the warning but
> in C++ out-of-range values in enums are undefined.

Not quite.  They are unspecified; see below.

> I see no reason to handling any kind of UB ( especially this ).
> IMHO this warning is a bug in C++ frontend.

This is a tricky issue.  You are correct that the values of "E" are
exactly { 0, 1 } (or, equivalently, { X, Y }).  But, the underlying type
of the enumeration is at least "char".  And, the standard says that
assigning an integer value to enumeration type has unspecified behavior
if it outside the range of the enumeration.

So:

  E e;
  e = (E) 7;

has unspecified behavior, which is defined as:

"behavior,  for  a well-formed program construct and correct data, that
depends on the implementation.  The implementation is not required to
document which behavior occurs."

Because the program is unspecified, not undefined, the usual "this could
erase your disk" thinking does not apply.  Unspecified is meant to be
more like Ada's bounded errors (though not as closely specified), in
that something vaguely sensible is supposed to happen.

For GCC, what happens (though we need not document it) is that the value
is converted to the underlying type -- but not masked down to { 0, 1 },
because that masking would be costly.  So, "((int) e == 7)" may be true
after the assignment above.  (Perhaps, in some modes GCC may optimize
away the assignment because it will "know" that "e" cannot be 7, but it
does not do so at -O2.)

So, now, what should we do about the warning?  I think there are good
arguments in both directions.  On the one hand, portable programs cannot
assume that assigning out-of-range values to "e" does anything
predictable, so portable programs should never do that.  So, if you've
written the entire program and are sure that it's portable, you don't
want the warning.  On the other hand, if you are writing a portable
library designed to be used with other people's programs, you might
every well want the warning -- because you can't be sure that they're
not going to pass "7" in as the value of "e", and you may want to be
robust in the face of this *unspecified* behavior.

In practice, this warning from GCC is keyed off what it thinks the
effective range of "E" is.  If it starts assuming that "e" can only have
the values { 0, 1 }, it will also stop warning about the missing case.
It would be hard to stop emitting the warning without making that
assumption, and it may not be easy to make the assumption, but still
avoid the expensive masking operations.

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]