This is the mail archive of the gcc-patches@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]

[PATCH] Fix packed enums in bitfields


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

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