If I have a switch statement that handles all enum cases explicitly, is the compiler allowed to optimise away the default case statement?
enum MyEnum {
ZERO = 0,
ONE = 1,
TWO = 2,
THREE = 3,
};
bool foo(MyEnum e) {
switch(e) {
case ZERO:
case ONE:
case TWO:
case THREE:
return true;
default: // Could a compiler optimise this away?
return false;
}
}
Cpp Reference says regarding enums (emphasis mine):
Values of integer, floating-point, and enumeration types can be converted by static_cast or explicit cast, to any enumeration type. If the underlying type is not fixed and the source value is out of range, the behavior is undefined. (The source value, as converted to the enumeration's underlying type if floating-point, is in range if it would fit in the smallest bit field large enough to hold all enumerators of the target enumeration.) Otherwise, the result is the same as the result of implicit conversion to the underlying type.
Which indicates it would be allowed to optimise out the default statement in the above example since the underlying type is not fixed and every 2-bit value is specified (though maybe you would need to include negative values to -4).
However, it is not clear if this also applies to fixed type enums or enum classes.
In practice, GCC, clang, and MSVC do not assume that the enum is one of the defined values. (Godbolt with full optimization enabled like -O3 -std=c 20
.)
Is that a missed optimization, or is the standard saying that if the implementation picks int
as the underlying type (even though you didn't specify) then any int
value is legal?
CodePudding user response:
Yes, I guess in theory they could. There is no standard-sanctioned way to reach the default
. There may be some room to argue about memcpy
/std::bit_cast
from the underlying type to the enumeration, but I don't think that works out. As you are quoting, the standard says what the possible values are, so other object representations can't map to additional values. The standard currently doesn't even guarantee same representation as the underlying type for the values (although that may be a defect).
However, it wouldn't be compatible with C where all values of the underlying type are allowed. Since the smallest possible underlying type is char
which is at least 8 bits wide, it will always be possible to reach the default
in C.
So I don't expect any compiler to do that.
Enumerations with fixed underlying type are specified differently and guaranteed to support all values of the underlying type.
CodePudding user response:
Some compilers are very aggressive with assumptions that undefined behaviour doesn’t happen (and therefore optimise code away). But in C, it is just too easy to create an enum value that doesn’t match any case. And the code that you showed was explicitly intended to detect incorrect values.
I have never seen or heard of a compiler optimising this case away. Different in a language like Swift where setting an enum to a value that isn’t mentioned as a case is very , very hard to do.