This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix packed enums in bitfields
- To: Richard Henderson <rth at redhat dot com>, Zack Weinberg <zackw at Stanford dot EDU>
- Subject: [PATCH] Fix packed enums in bitfields
- From: Jakub Jelinek <jakub at redhat dot com>
- Date: Fri, 2 Feb 2001 12:14:34 +0100
- Cc: gcc-patches at gcc dot gnu dot org
- Reply-To: Jakub Jelinek <jakub at redhat dot com>
Hi!
The following testcase prints warnings like:
warning: width of `A' exceeds its type
and does not give the expected 2 byte size of the whole thing as e.g. one
driver in linux-2.4.0 expects (and gcc used to work that way e.g. in egcs
1.1.2 or 2.95.x).
The change which broke this is Zack's 2000-01-05 change to finish_enum which
now may leave TYPE_PRECISION of packed enums and also not packed enums requiring
bigger type than int not corresponding to any type (e.g. in this case
TYPE_PRECISION of the A and B enums is 2). What was the reason for this
change? Making sure TYPE_PRECISION of such enums is TYPE_PRECISION of some
type_for_size type fixes this (see below).
Another solution would be just to patch finish_struct to do something like:
int max_width;
if (TYPE_MAIN_VARIANT (TREE_TYPE (x)) == c_bool_type_node)
max_width = CHAR_TYPE_SIZE;
+ else if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE)
+ {
+ max_width = TYPE_PRECISION (TREE_TYPE (x));
+ if (max_width <= TYPE_PRECISION (integer_type_node))
+ max_width = TYPE_PRECISION (integer_type_node);
+ else
+ {
+ tree narrowest = type_for_size (max_width, 1);
+ if (narrowest)
+ max_width = TYPE_PRECISION (integer_type_node);
+ }
+ }
else
max_width = TYPE_PRECISION (TREE_TYPE (x));
if (tree_int_cst_sgn (DECL_INITIAL (x)) < 0)
error_with_decl (x, "negative width in bit-field %s'");
else if (0 < compare_tree_int (DECL_INITIAL (x), max_width))
pedwarn_with_decl (x, "width of %s' exceeds its type");
(which would accept more things than 2.95.2 but IMHO it does not contradict
any standards, e.g. stuff like:
typedef struct {
enum {
A0 = 0, A1 = 1, A2 = 2
} __attribute__((packed)) A:16;
} foo;
). I have changed finish_enum because I'm not sure what other parts of
compiler might be unhappy about the change of TYPE_PRECISION for packed
enums.
Ok to commit provided it bootstraps and creates no regressions?
2001-02-02 Jakub Jelinek <jakub@redhat.com>
* c-decl.c (finish_enum): Revert part of 2000-01-05 change.
* gcc.dg/20010202-1.c: New test.
* gcc.dg/991209-1.c: Compile on whole ia32 family, not just i386.
--- gcc/c-decl.c.jj Fri Feb 2 00:47:25 2001
+++ gcc/c-decl.c Fri Feb 2 12:54:36 2001
@@ -5610,13 +5610,19 @@ finish_enum (enumtype, values, attribute
unsign = (tree_int_cst_sgn (minnode) >= 0);
precision = MAX (min_precision (minnode, unsign),
min_precision (maxnode, unsign));
- if (!TYPE_PACKED (enumtype))
- precision = MAX (precision, TYPE_PRECISION (integer_type_node));
- if (type_for_size (precision, unsign) == 0)
+ if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
{
- warning ("enumeration values exceed range of largest integer");
- precision = TYPE_PRECISION (long_long_integer_type_node);
+ tree narrowest = type_for_size (precision, unsign);
+ if (narrowest == 0)
+ {
+ warning ("enumeration values exceed range of largest integer");
+ narrowest = long_long_integer_type_node;
+ }
+
+ precision = TYPE_PRECISION (narrowest);
}
+ else
+ precision = TYPE_PRECISION (integer_type_node);
if (precision == TYPE_PRECISION (integer_type_node))
enum_value_type = type_for_size (precision, 0);
--- gcc/testsuite/gcc.dg/20010202-1.c.jj Fri Feb 2 12:20:29 2001
+++ gcc/testsuite/gcc.dg/20010202-1.c Fri Feb 2 12:22:28 2001
@@ -0,0 +1,24 @@
+/* { dg-do compile { target i?86-*-* sparc*-*-* } } */
+/* { dg-options "-O2" } */
+
+typedef enum { false, true } __attribute__ ((packed)) boolean;
+typedef struct {
+ enum {
+ A0 = 0, A1 = 1, A2 = 2
+ } __attribute__((packed)) A:3;
+ enum {
+ B0 = 0, B1 = 1, B2 = 2
+ } __attribute__((packed)) B:3;
+ boolean C:1;
+ boolean D:1;
+ unsigned char :8;
+} foo;
+foo x = { A2, B1, false, true };
+
+int main(void)
+{
+ if (sizeof (foo) != 2 || __alignof__ (foo) != 1)
+ abort ();
+
+ exit (0);
+}
--- gcc/testsuite/gcc.dg/991209-1.c.jj Tue Oct 10 17:34:06 2000
+++ gcc/testsuite/gcc.dg/991209-1.c Fri Feb 2 12:21:41 2001
@@ -1,4 +1,4 @@
-/* { dg-do compile { target i386-*-* } } */
+/* { dg-do compile { target i?86-*-* } } */
int foo ()
{
Jakub