Patch for bug 22421

Joseph S. Myers joseph@codesourcery.com
Sat Jul 16 16:05:00 GMT 2005


This patch fixes bug 22421, problems with passing bit-field types to
format functions.

There were two underlying issues:

* 32-bit bit-fields were given an extended integer type, but C99
  requires extended integer types to have lesser rank than standard
  types of the same width and GCC didn't know to promote such types to
  int.  Fixed by preferring standard types if available for
  bit-fields.  (It's already the case that if the bit-field has the
  same width at the underlying type, the underlying type is used, so
  this didn't appear for int:32, only for long:32 where long is 64
  bits.)

* Diagnostics failed to indicate that types were bit-field types,
  leading to the problem diagnostic quoted in bug 21962, "format
  '%012llx' expects type 'long long unsigned int', but argument 2 has
  type 'long long unsigned int'".  Fixed by saying "long long unsigned
  int:48" in the diagnostic (on systems where long is 64 bits, it will
  say "long unsigned int:48", hence the pattern used for this
  diagnostic in the testcase).  There is no default promotion for
  bit-fields wider than int, so they need to be cast to be used as
  printf arguments.

Bootstrapped with no regressions on x86_64-unknown-linux-gnu, mainline
and 4.0 branch.  Applied to mainline and 4.0 branch.

-- 
Joseph S. Myers               http://www.srcf.ucam.org/~jsm28/gcc/
    jsm@polyomino.org.uk (personal mail)
    joseph@codesourcery.com (CodeSourcery mail)
    jsm28@gcc.gnu.org (Bugzilla assignments and CCs)

2005-07-16  Joseph S. Myers  <joseph@codesourcery.com>

	PR c/22421
	* c-decl.c (c_build_bitfield_integer_type): New function.
	(finish_struct): Call it.
	* c-pretty-print.c (pp_c_type_specifier): Handle bit-field types.

testsuite:
2005-07-16  Joseph S. Myers  <joseph@codesourcery.com>

	PR c/22421
	* gcc.dg/format/bitfld-1.c: New test.

diff -rupN GCC.orig/gcc/c-decl.c GCC/gcc/c-decl.c
--- GCC.orig/gcc/c-decl.c	2005-07-10 12:26:45.000000000 +0000
+++ GCC/gcc/c-decl.c	2005-07-15 21:25:35.000000000 +0000
@@ -3774,6 +3774,30 @@ check_bitfield_type_and_width (tree *typ
 	warning (0, "%qs is narrower than values of its type", name);
     }
 }
+
+/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP.  */
+static tree
+c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp)
+{
+  /* Extended integer types of the same width as a standard type have
+     lesser rank, so those of the same width as int promote to int or
+     unsigned int and are valid for printf formats expecting int or
+     unsigned int.  To avoid such special cases, avoid creating
+     extended integer types for bit-fields if a standard integer type
+     is available.  */
+  if (width == TYPE_PRECISION (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+  if (width == TYPE_PRECISION (signed_char_type_node))
+    return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+  if (width == TYPE_PRECISION (short_integer_type_node))
+    return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+  if (width == TYPE_PRECISION (long_integer_type_node))
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+  if (width == TYPE_PRECISION (long_long_integer_type_node))
+    return (unsignedp ? long_long_unsigned_type_node
+	    : long_long_integer_type_node);
+  return build_nonstandard_integer_type (width, unsignedp);
+}
 
 /* Given declspecs and a declarator,
    determine the name and type of the object declared
@@ -5376,7 +5400,7 @@ finish_struct (tree t, tree fieldlist, t
 	  if (width != TYPE_PRECISION (type))
 	    {
 	      TREE_TYPE (*fieldlistp)
-	        = build_nonstandard_integer_type (width, TYPE_UNSIGNED (type));
+		= c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type));
 	      DECL_MODE (*fieldlistp) = TYPE_MODE (TREE_TYPE (*fieldlistp));
 	    }
 	  DECL_INITIAL (*fieldlistp) = 0;
diff -rupN GCC.orig/gcc/c-pretty-print.c GCC/gcc/c-pretty-print.c
--- GCC.orig/gcc/c-pretty-print.c	2005-06-25 09:53:52.000000000 +0000
+++ GCC/gcc/c-pretty-print.c	2005-07-15 21:52:29.000000000 +0000
@@ -315,10 +315,21 @@ pp_c_type_specifier (c_pretty_printer *p
     case INTEGER_TYPE:
     case REAL_TYPE:
       if (TYPE_NAME (t))
-        t = TYPE_NAME (t);
+	{
+	  t = TYPE_NAME (t);
+	  pp_c_type_specifier (pp, t);
+	}
       else
-        t = c_common_type_for_mode (TYPE_MODE (t), TYPE_UNSIGNED (t));
-      pp_c_type_specifier (pp, t);
+	{
+	  int prec = TYPE_PRECISION (t);
+	  t = c_common_type_for_mode (TYPE_MODE (t), TYPE_UNSIGNED (t));
+	  pp_c_type_specifier (pp, t);
+	  if (TYPE_PRECISION (t) != prec)
+	    {
+	      pp_string (pp, ":");
+	      pp_decimal_int (pp, prec);
+	    }
+	}
       break;
 
     case TYPE_DECL:
diff -rupN GCC.orig/gcc/testsuite/gcc.dg/format/bitfld-1.c GCC/gcc/testsuite/gcc.dg/format/bitfld-1.c
--- GCC.orig/gcc/testsuite/gcc.dg/format/bitfld-1.c	1970-01-01 00:00:00.000000000 +0000
+++ GCC/gcc/testsuite/gcc.dg/format/bitfld-1.c	2005-07-15 21:42:45.000000000 +0000
@@ -0,0 +1,46 @@
+/* Test for printf formats and bit-fields: bug 22421.  */
+/* Origin: Joseph Myers <joseph@codesourcery.com> */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu99 -Wformat" } */
+
+#include "format.h"
+
+struct s {
+  unsigned int u1 : 1;
+  signed int s1 : 1;
+  unsigned int u15 : 15;
+  signed int s15 : 15;
+  unsigned int u16 : 16;
+  signed int s16 : 16;
+  unsigned long u31 : 31;
+  signed long s31 : 31;
+  unsigned long u32 : 32;
+  signed long s32 : 32;
+  unsigned long long u48 : 48;
+} x;
+
+void
+foo (void)
+{
+  printf ("%d%u", x.u1, x.u1);
+  printf ("%d%u", x.s1, x.s1);
+  printf ("%d%u", x.u15, x.u15);
+  printf ("%d%u", x.s15, x.s15);
+  printf ("%d%u", x.u16, x.u16);
+  printf ("%d%u", x.s16, x.s16);
+  printf ("%d%u", x.u31, x.u31);
+  printf ("%d%u", x.s31, x.s31);
+#if __LONG_MAX__ > 2147483647 && __INT_MAX__ >= 2147483647
+  /* If long is wider than 32 bits, the 32-bit bit-fields are int or
+     unsigned int or promote to those types.  Otherwise, long is 32
+     bits and the bit-fields are of type plain long or unsigned
+     long.  */
+  printf ("%d%u", x.u32, x.u32);
+  printf ("%d%u", x.s32, x.s32);
+#else
+  printf ("%ld%lu", x.u32, x.u32);
+  printf ("%ld%lu", x.s32, x.s32);
+#endif
+  printf ("%llu", x.u48); /* { dg-warning "has type '.*unsigned int:48'" } */
+  printf ("%llu", (unsigned long long)x.u48);
+}



More information about the Gcc-patches mailing list