re PR c/22421 (problems with -Wformat and bit-fields)
authorJoseph Myers <joseph@codesourcery.com>
Sat, 16 Jul 2005 16:01:57 +0000 (17:01 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Sat, 16 Jul 2005 16:01:57 +0000 (17:01 +0100)
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:
* gcc.dg/format/bitfld-1.c: New test.

From-SVN: r102091

gcc/ChangeLog
gcc/c-decl.c
gcc/c-pretty-print.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format/bitfld-1.c [new file with mode: 0644]

index 8b57b80..a9faa79 100644 (file)
@@ -1,3 +1,10 @@
+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.
+
 2005-07-16  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * c-typeck.c (digest_init): Call 'convert_for_assignment'
index 67c72a5..aff59bc 100644 (file)
@@ -3774,6 +3774,30 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
        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);
+}
 \f
 /* Given declspecs and a declarator,
    determine the name and type of the object declared
@@ -5376,7 +5400,7 @@ finish_struct (tree t, tree fieldlist, tree attributes)
          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;
index ebd917e..6276923 100644 (file)
@@ -315,10 +315,21 @@ pp_c_type_specifier (c_pretty_printer *pp, tree t)
     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:
index 30bde12..6590ad7 100644 (file)
@@ -1,3 +1,8 @@
+2005-07-16  Joseph S. Myers  <joseph@codesourcery.com>
+
+       PR c/22421
+       * gcc.dg/format/bitfld-1.c: New test.
+
 2005-07-15  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/22204
diff --git a/gcc/testsuite/gcc.dg/format/bitfld-1.c b/gcc/testsuite/gcc.dg/format/bitfld-1.c
new file mode 100644 (file)
index 0000000..2cea5d2
--- /dev/null
@@ -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);
+}