This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: enumeration value ... not handled in switch
- From: Daniel Brockman <daniel at brockman dot se>
- To: gcc at gcc dot gnu dot org
- Cc: hartmut dot schirmer at arcormail dot de
- Date: Tue, 11 Jan 2005 06:32:22 +0100
- Subject: Re: enumeration value ... not handled in switch
- References: <1F5C7ECB324CD411B58600D0B723F181779402@oehhex01.becker.de>
At 2001-09-26, Joerg Faschingbauer writes:
> From: "Schirmer, Hartmut" <SchirmerH@Innovative-Systems.de>
> Subject: enumeration value ... not handled in switch
> Date: Mon, 24 Sep 2001 10:06:21 +0200
>
> > Hi,
> >
> > is there any way to tell GCC to warn about unhandled
> > enum values in switch-case statements even if a default
> > case is present?
> >
> > Currently I have to do ugly things like
> >
> > flag = 0;
> > switch ( e )
> > {
> > case e1: flag = 1; break;
> > case e2: flag = 1; break;
> > }
> > if ( !flag )
> > {
> > // default case
> > }
> >
> > to get both, the default case and the warning.
> >
> > Adding an attribute to default: would be ok in this case.
>
> This is bug #3780. I'll be cleaning up my patch a bit (although it
> won't become less dirty by doing so :-) and submit it. (This won't
> happen before two weeks, though.)
(The original message is archived [1].)
Bug #3780 [2] doesn't seem to adress the issue brought up by Hartmut,
namely that adding a default case to a switch statement has the
sometimes-unfortunate side effect of turning off the warning about
unhandled enumeration values.
As it seems, this problem cannot be solved without adding an attribute
that declares a default case to be exceptional.
Consider the following code:
struct fruit
{
enum { APPLE, MELON, ORANGE } type;
...
} fruit;
...
switch (fruit.type)
{
case APPLE:
...; break;
case MELON:
...; break;
case ORANGE:
...; break;
}
Here, as soon as another value is added to the enum, gcc will warn
about the switch statement not handling it.
But what if `fruit_type' is neither `APPLE' nor `ORANGE'? The fact
that this is an impossible situation implies that when it *does*
occur, the program is in an undefined state. Thus, it should fail as
quickly and noisily as possible:
switch (fruit.type)
{
case APPLE:
...; break;
case MELON:
...; break;
case ORANGE:
...; break;
default:
abort ();
}
However, adding this guard prevents gcc from warning about unhandled
enumeration values.
The problem is that gcc cannot distinguish default cases intended to
detect impossible situations from those intended as catch-alls for
unspecified but valid enumeration values, such as this one:
switch (fruit.type)
{
case APPLE:
handle_apple (&fruit);
break;
default:
handle_other_fruit (&fruit);
}
Here, the impossible situations are deferred to `handle_other_fruit'.
Ideally, C would allow both kinds of default cases simultaneously when
switching on enums. For example, why not use the `extern' keyword?
switch (fruit.type)
{
case APPLE:
handle_apple (&fruit);
break;
default:
handle_other_fruit (&fruit);
break;
extern:
abort ();
}
Really, we don't want to do that, and it is not what I am proposing.
But the above syntax is simple syntactic sugar for the following:
switch (fruit.type)
{
case APPLE:
handle_apple (&fruit);
break;
case MELON:
case ORANGE:
handle_other_fruit (&fruit);
break;
default:
abort ();
}
The only missing piece here is being able to declare that the default
case is intended to handle *exceptional* cases only:
switch (fruit.type)
{
case APPLE:
handle_apple (&fruit);
break;
case MELON:
case ORANGE:
handle_other_fruit (&fruit);
break;
default __attribute__ ((exceptional)):
abort ();
}
The meaning of the `exceptional' attribute is simple: Any default
case with this attribute does not in itself prevent warnings about
unanticipated enumeration values.
This change would stop people from being forced to artificially choose
between run-time sanity and compile-time helpfulness.
Thanks,
--
Daniel Brockman <daniel@brockman.se>
[1] http://gcc.gnu.org/ml/gcc/2001-09/msg01034.html
[2] http://gcc.gnu.org/bugzilla/show_bug.cgi?id=3780