This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
underlying type for enums
- From: Richard Henderson <rth at redhat dot com>
- To: jsm at polyomino dot org dot uk, Jason Merrill <jason at redhat dot com>
- Cc: gcc at gcc dot gnu dot org
- Date: Tue, 2 Dec 2003 01:06:52 -0800
- Subject: underlying type for enums
The top level problem that led me to the ENUM_BITFIELD patch earlier
this evening comes from wanting to get rid of this hack:
- /* We don't want to risk changing the type of the switch condition,
- lest stmt.c get the wrong impression about enumerations. */
- if (TREE_CODE (SWITCH_COND (switch_expr)) == NOP_EXPR)
- ret = gimplify_expr (&TREE_OPERAND (SWITCH_COND (switch_expr), 0),
- pre_p, NULL, is_gimple_val, fb_rvalue);
from gimplify_switch_expr. The root of the problem is that the C
front end currently sets TYPE_MIN/MAX_VALUE for an enumeration based
on the values of the enumerators. Since an enum type can hold values
other than the enumerators, this is clearly wrong, and it can lead
expand_end_case_type to believe that a default case is unreachable.
If I do the simple and obvious thing:
- TYPE_MIN_VALUE (enumtype) = minnode;
- TYPE_MAX_VALUE (enumtype) = maxnode;
then we run into all sorts of warnings wrt our enum bitfield
extension. Namely, we no longer believe that the enum fits.
The C++ standard defines the "underlying type" of an enum as an
integral type which can hold all of the enumerator values. It then
goes on to define what all of the possible values are based on the
set of enumerators present. Namely, the smallest and largest
values of a bit-field that can store all of the enumerators.
The C standard uses the term "compatible type". In C99 we are
given free rein to choose any signed or unsigned integer type,
including extended integer types. I don't have C90 handy to
check wording there, but since extended integer types did not
exist I don't think we have the same freedom. Anyway, let me
ignore C90 for the moment.
The easiest way to handle the enum bitfield thing, it would seem,
would be to take the extended integer type route and follow the
lead of C++ and define a type with the minimal TYPE_PRECISION
for the enumerator values. This brings up a number of issues:
(1) Need to keep the object-level ABI constant. This is fairly
easy to do. Keep the old precision selection logic, lay out
the type so that TYPE_SIZE and TYPE_MODE get set, then
override TYPE_PRECISION et al after the fact.
(2) There's a number of places that equate TYPE_PRECISION and TYPE_SIZE:
finish_struct:
/* Detect and ignore out of range field width and process valid
field widths. */
if (DECL_INITIAL (x))
{
- int max_width
- = (TYPE_MAIN_VARIANT (TREE_TYPE (x)) == boolean_type_node
- ? CHAR_TYPE_SIZE : TYPE_PRECISION (TREE_TYPE (x)));
+ int max_width = tree_low_cst (TYPE_SIZE (TREE_TYPE (x)), 1);
This is the only one I'm certain about. The language in C99 is
clear about this being the size of the representation.
c_promoting_integer_type_p:
/* ??? Technically all enumerations not larger than an int
promote to an int. But this is used along code paths
that only want to notice a size change. */
- return TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node);
+ return tree_int_cst_lt (TYPE_SIZE (t), TYPE_SIZE (integer_type_node));
This case is "needed" to suppress warnings for va_arg(l, enum). As
noted in the ??? comment, this is technically already incorrect; the
change here merely preserves the fiction. Making this dependent on
pedantic is infeasable without moving the __builtin_va_arg warning
out of the middle-end. Which wouldn't be a bad thing...
comptypes:
if (TREE_CODE (t1) == ENUMERAL_TYPE)
- t1 = c_common_type_for_size (TYPE_PRECISION (t1), TREE_UNSIGNED (t1));
+ t1 = c_common_type_for_size (tree_low_cst (TYPE_SIZE (t1), 1),
+ TREE_UNSIGNED (t1));
This case is to preserve
__builtin_types_compatible_p (typeof (dingos), typeof (cranberry))
when the two enumerations have different ranges of enumerators.
This is almost certainly technically wrong, since to my reading
compatible enumerators must have the exact same values. Also,
to be completely correct we should indeed be changing the result
of this function applied to an enum and unsigned int, since now
we're compatible with the not-really-named __builtin_int_4_bits.
But I can see what's desired by the Altivec horribleness that
uses this feature, and we want to preserve that somehow.
(3) Changing the compatible type changes (or ought to change) the
rank of enums wrt promotion. I'll grant that any programs that
are affected by this were broken, but we should keep that in mind.
Given all of this, plus the likelyhood that we can't set TYPE_PRECISION
to a non-standard value for C90, I am lead to wonder if this is the correct
direction to go.
Perhaps I should just set the compatible type to int or unsigned int
(or larger ad needed), leave TYPE_MIN/MAX_VALUE set correctly for those
types, and handle the bit-field too small warning another way. It would
not be hard, for instance, to store the required width in lang_type.
Thoughts?
r~