re PR c++/26534 ([4.1] bitfield wrong optimize)
authorMark Mitchell <mark@codesourcery.com>
Sun, 23 Apr 2006 18:04:33 +0000 (18:04 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sun, 23 Apr 2006 18:04:33 +0000 (18:04 +0000)
2006-04-23  Mark Mitchell  <mark@codesourcery.com>

PR c++/26534
* c-common.h (c_build_bitfield_integer_type): Declare.
* c-decl.c (c_build_bitfield_integer_type): Move to ...
* c-common.c (c_build_bitfield_integer_type): ... here.

2006-04-23  Mark Mitchell  <mark@codesourcery.com>

PR c++/26534
* cp-tree.h (is_bitfield_expr_with_lowered_type): New function.
* typeck.c (is_bitfield_expr_with_lowered_type): New function.
(decay_conversion): Convert bitfield expressions to the correct
type.
(build_modify_expr): Remove spurious conversions.
* class.c (layout_class_type): Modify the type of bitfields to
indicate a limited range.
* call.c (standard_conversion): Adjust the type of bitfield
expressions used in an rvalue context.
(build_conditional_expr): Likewise.

2006-04-23  Mark Mitchell  <mark@codesourcery.com>

PR c++/26534
* g++.dg/opt/bitfield1.C: New test.
* g++.dg/compat/abi/bitfield1_main.C: Add -w.
* g++.dg/compat/abi/bitfield1_x.C: Likewise.
* g++.dg/compat/abi/bitfield1_y.C: Likewise.
* g++.dg/compat/abi/bitfield2_main.C: Likewise.
* g++.dg/compat/abi/bitfield2_x.C: Likewise.
* g++.dg/compat/abi/bitfield2_y.C: Likewise.
* g++.dg/abi/bitfield1.C: Add dg-warning markers.
* g++.dg/abi/bitfield2.C: Likewise.
* g++.dg/init/bitfield1.C: Likewise.

From-SVN: r113199

23 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-common.h
gcc/c-decl.c
gcc/configure
gcc/configure.ac
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/typeck.c
gcc/print-tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/bitfield1.C
gcc/testsuite/g++.dg/abi/bitfield2.C
gcc/testsuite/g++.dg/compat/abi/bitfield1_main.C
gcc/testsuite/g++.dg/compat/abi/bitfield1_x.C
gcc/testsuite/g++.dg/compat/abi/bitfield1_y.C
gcc/testsuite/g++.dg/compat/abi/bitfield2_main.C
gcc/testsuite/g++.dg/compat/abi/bitfield2_x.C
gcc/testsuite/g++.dg/compat/abi/bitfield2_y.C
gcc/testsuite/g++.dg/init/bitfield1.C
gcc/testsuite/g++.dg/opt/bitfield1.C [new file with mode: 0644]

index ea6d17b..08fc7c0 100644 (file)
@@ -1,3 +1,10 @@
+2006-04-23  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/26534
+       * c-common.h (c_build_bitfield_integer_type): Declare.
+       * c-decl.c (c_build_bitfield_integer_type): Move to ...
+       * c-common.c (c_build_bitfield_integer_type): ... here.
+
 2006-04-23  Roger Sayle  <roger@eyesopen.com>
 
        PR target/21283
index 1a11c3b..35982e5 100644 (file)
@@ -1871,6 +1871,31 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type)
     return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp);
 }
 
+/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP.  */
+
+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);
+}
+
 /* The C version of the register_builtin_type langhook.  */
 
 void
index ed93f97..5636685 100644 (file)
@@ -644,6 +644,7 @@ extern tree c_common_type_for_size (unsigned int, int);
 extern tree c_common_unsigned_type (tree);
 extern tree c_common_signed_type (tree);
 extern tree c_common_signed_or_unsigned_type (int, tree);
+extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int);
 extern tree c_common_truthvalue_conversion (tree);
 extern void c_apply_type_quals_to_decl (int, tree);
 extern tree c_sizeof_or_alignof_type (tree, bool, int);
index db906b4..f4d3330 100644 (file)
@@ -3814,29 +3814,6 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_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
index fe6f1bd..9137c44 100755 (executable)
                lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h"
            fi
            ;;
+        *)
+           # This language is not enabled; skip it.
+           continue
+           ;;
         esac
 
        if test -f $srcdir/$subdir/lang.opt; then
index 447f827..2fa8d99 100644 (file)
@@ -3325,6 +3325,10 @@ changequote(,)dnl
                lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h"
            fi
            ;;
+        *)
+           # This language is not enabled; skip it.
+           continue
+           ;;  
         esac
 changequote([,])dnl
 
index 711fb7c..a0a44a5 100644 (file)
@@ -1,3 +1,17 @@
+2006-04-23  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/26534
+       * cp-tree.h (is_bitfield_expr_with_lowered_type): New function.
+       * typeck.c (is_bitfield_expr_with_lowered_type): New function.
+       (decay_conversion): Convert bitfield expressions to the correct
+       type.
+       (build_modify_expr): Remove spurious conversions.
+       * class.c (layout_class_type): Modify the type of bitfields to
+       indicate a limited range. 
+       * call.c (standard_conversion): Adjust the type of bitfield
+       expressions used in an rvalue context.
+       (build_conditional_expr): Likewise.
+       
 2006-04-22  Kazu Hirata  <kazu@codesourcery.com>
 
        * decl.c: Fix comment typos.
index c982645..6743f92 100644 (file)
@@ -623,7 +623,16 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
       conv = build_conv (ck_lvalue, from, conv);
     }
   else if (fromref || (expr && lvalue_p (expr)))
-    conv = build_conv (ck_rvalue, from, conv);
+    {
+      if (expr)
+       {
+         tree bitfield_type;
+         bitfield_type = is_bitfield_expr_with_lowered_type (expr);
+         if (bitfield_type)
+           from = bitfield_type;
+       }
+      conv = build_conv (ck_rvalue, from, conv);
+    }
 
    /* Allow conversion between `__complex__' data types.  */
   if (tcode == COMPLEX_TYPE && fcode == COMPLEX_TYPE)
@@ -3196,8 +3205,12 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3)
      array-to-pointer (_conv.array_), and function-to-pointer
      (_conv.func_) standard conversions are performed on the second
      and third operands.  */
-  arg2_type = TREE_TYPE (arg2);
-  arg3_type = TREE_TYPE (arg3);
+  arg2_type = is_bitfield_expr_with_lowered_type (arg2);
+  if (!arg2_type)
+    arg2_type = TREE_TYPE (arg2);
+  arg3_type = is_bitfield_expr_with_lowered_type (arg3);
+  if (!arg3_type)
+    arg3_type = TREE_TYPE (arg3);
   if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type))
     {
       /* Do the conversions.  We don't these for `void' type arguments
index cc26cb8..1cf87dc 100644 (file)
@@ -4727,6 +4727,29 @@ layout_class_type (tree t, tree *virtuals_p)
                 "classes to be placed at different locations in a "
                 "future version of GCC", field);
 
+      /* The middle end uses the type of expressions to determine the
+        possible range of expression values.  In order to optimize
+        "x.i > 7" to "false" for a 2-bit bitfield "i", the middle end
+        must be made aware of the width of "i", via its type.  
+
+         Because C++ does not have integer types of arbitrary width,
+        we must (for the purposes of the front end) convert from the
+        type assigned here to the declared type of the bitfield
+        whenever a bitfield expression is used as an rvalue.
+        Similarly, when assigning a value to a bitfield, the value
+        must be converted to the type given the bitfield here.  */
+      if (DECL_C_BIT_FIELD (field))
+       {
+         tree ftype;
+         unsigned HOST_WIDE_INT width;
+         ftype = TREE_TYPE (field);
+         width = tree_low_cst (DECL_SIZE (field), /*unsignedp=*/1);
+         if (width != TYPE_PRECISION (ftype))
+           TREE_TYPE (field) 
+             = c_build_bitfield_integer_type (width, 
+                                              TYPE_UNSIGNED (ftype));
+       }
+
       /* If we needed additional padding after this field, add it
         now.  */
       if (padding)
index 0848747..34cccc0 100644 (file)
@@ -4351,6 +4351,7 @@ extern tree cxx_sizeof_or_alignof_expr            (tree, enum tree_code);
 extern tree cxx_sizeof_or_alignof_type         (tree, enum tree_code, bool);
 #define cxx_sizeof_nowarn(T) cxx_sizeof_or_alignof_type (T, SIZEOF_EXPR, false)
 extern tree inline_conversion                  (tree);
+extern tree is_bitfield_expr_with_lowered_type  (tree); 
 extern tree decay_conversion                   (tree);
 extern tree default_conversion                 (tree);
 extern tree build_class_member_access_expr      (tree, tree, tree, bool);
index a7bdd55..7fc6cab 100644 (file)
@@ -1398,21 +1398,47 @@ invalid_nonstatic_memfn_p (tree expr)
   return false;
 }
 
+/* If EXP is a reference to a bitfield, and the type of EXP does not
+   match the declared type of the bitfield, return the declared type
+   of the bitfield.  Otherwise, return NULL_TREE.  */
+
+tree
+is_bitfield_expr_with_lowered_type (tree exp)
+{
+  tree field;
+
+  if (TREE_CODE (exp) == COND_EXPR)
+    {
+      if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)))
+       return NULL_TREE;
+      return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 2));
+    }
+  if (TREE_CODE (exp) != COMPONENT_REF)
+    return NULL_TREE;
+  field = TREE_OPERAND (exp, 1);
+  if (TREE_CODE (field) != FIELD_DECL || !DECL_C_BIT_FIELD (field))
+    return NULL_TREE;
+  if (same_type_ignoring_top_level_qualifiers_p
+      (TREE_TYPE (exp), DECL_BIT_FIELD_TYPE (field)))
+    return NULL_TREE;
+  return DECL_BIT_FIELD_TYPE (field);
+}
+
 /* Perform the conversions in [expr] that apply when an lvalue appears
    in an rvalue context: the lvalue-to-rvalue, array-to-pointer, and
    function-to-pointer conversions.
 
-   In addition manifest constants are replaced by their values.  */
+   In addition, manifest constants are replaced by their values, and
+   bitfield references are converted to their declared types.  */
 
 tree
 decay_conversion (tree exp)
 {
   tree type;
+  tree bitfield_type;
   enum tree_code code;
 
   type = TREE_TYPE (exp);
-  code = TREE_CODE (type);
-
   if (type == error_mark_node)
     return error_mark_node;
 
@@ -1422,11 +1448,15 @@ decay_conversion (tree exp)
       return error_mark_node;
     }
 
+  bitfield_type = is_bitfield_expr_with_lowered_type (exp);
+  if (bitfield_type) 
+    exp = build_nop (bitfield_type, exp);
+
   exp = decl_constant_value (exp);
 
   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
      Leave such NOP_EXPRs, since RHS is being used in non-lvalue context.  */
-
+  code = TREE_CODE (type);
   if (code == VOID_TYPE)
     {
       error ("void value not ignored as it ought to be");
@@ -5500,11 +5530,9 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
 
        cond = build_conditional_expr
          (TREE_OPERAND (lhs, 0),
-          build_modify_expr (cp_convert (TREE_TYPE (lhs),
-                                         TREE_OPERAND (lhs, 1)),
+          build_modify_expr (TREE_OPERAND (lhs, 1),
                              modifycode, rhs),
-          build_modify_expr (cp_convert (TREE_TYPE (lhs),
-                                         TREE_OPERAND (lhs, 2)),
+          build_modify_expr (TREE_OPERAND (lhs, 2),
                              modifycode, rhs));
 
        if (cond == error_mark_node)
index 02e5c7b..eed02f2 100644 (file)
@@ -458,6 +458,9 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
          print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4);
          print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node),
                      indent + 4);
+         if (DECL_BIT_FIELD_TYPE (node))
+           print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node),
+                       indent + 4);
        }
 
       print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4);
index 7a3fb00..f0c3a5d 100644 (file)
@@ -1,3 +1,17 @@
+2006-04-23  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/26534
+       * g++.dg/opt/bitfield1.C: New test.
+       * g++.dg/compat/abi/bitfield1_main.C: Add -w.
+       * g++.dg/compat/abi/bitfield1_x.C: Likewise.
+       * g++.dg/compat/abi/bitfield1_y.C: Likewise.
+       * g++.dg/compat/abi/bitfield2_main.C: Likewise.
+       * g++.dg/compat/abi/bitfield2_x.C: Likewise.
+       * g++.dg/compat/abi/bitfield2_y.C: Likewise.
+       * g++.dg/abi/bitfield1.C: Add dg-warning markers.
+       * g++.dg/abi/bitfield2.C: Likewise.
+       * g++.dg/init/bitfield1.C: Likewise.
+
 2006-04-23  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/25099
index c707c85..d5d04bc 100644 (file)
@@ -19,7 +19,7 @@ int main ()
 {
   A a;
 
-  a.bitS = 1;
+  a.bitS = 1; // { dg-warning "overflow" }
   a.bitU = 1;
   a.bit = 1;
 
index d4d1d58..452861e 100644 (file)
@@ -19,9 +19,9 @@ int main ()
 {
   A a;
 
-  a.bitS = 1;
+  a.bitS = 1; // { dg-warning "overflow" }
   a.bitU = 1;
-  a.bit = 1;
+  a.bit = 1;  // { dg-warning "overflow" }
 
   if (a.bitS != -1)
     return 1;
index cdb7a45..ce9aa1f 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-options "-ansi -pedantic-errors -funsigned-bitfields" }
+// { dg-options "-w -ansi -pedantic-errors -funsigned-bitfields" }
 
 // Copyright (C) 2001 Free Software Foundation, Inc.
 // Contributed by Nathan Sidwell 15 Dec 2001 <nathan@codesourcery.com>
index e081c4b..727632a 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-options "-ansi -pedantic-errors -funsigned-bitfields" }
+// { dg-options "-w -ansi -pedantic-errors -funsigned-bitfields" }
 
 #include "bitfield1.h"
 
index 10581da..2827767 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-options "-ansi -pedantic-errors -funsigned-bitfields" }
+// { dg-options "-w -ansi -pedantic-errors -funsigned-bitfields" }
 
 extern "C" void abort (void);
 
index df74037..4169843 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-options "-ansi -pedantic-errors -fsigned-bitfields" }
+// { dg-options "-w -ansi -pedantic-errors -fsigned-bitfields" }
 
 // Copyright (C) 2001 Free Software Foundation, Inc.
 // Contributed by Nathan Sidwell 15 Dec 2001 <nathan@codesourcery.com>
index 47b448d..080d21b 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-options "-ansi -pedantic-errors -fsigned-bitfields" }
+// { dg-options "-w -ansi -pedantic-errors -fsigned-bitfields" }
 
 #include "bitfield1.h"
 
index 55edab5..d275783 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-options "-ansi -pedantic-errors -fsigned-bitfields" }
+// { dg-options "-w -ansi -pedantic-errors -fsigned-bitfields" }
 
 extern "C" void abort (void);
 
index 786a116..70a06d0 100644 (file)
@@ -14,11 +14,11 @@ void f ();
 int main ()
 {
   (f(), a.j) = 1;
-  (f(), a).j = 2;
-  (b ? a.j : a2.k) = 3;
+  (f(), a).j = 2; // { dg-warning "overflow" } 
+  (b ? a.j : a2.k) = 3; // { dg-warning "overflow" } 
   (b ? a : a2).j = 0;
   ++(a.j) = 1;
-  (a.j = 2) = 3;
+  (a.j = 2) = 3; // { dg-warning "overflow" } 
 }
 
     
diff --git a/gcc/testsuite/g++.dg/opt/bitfield1.C b/gcc/testsuite/g++.dg/opt/bitfield1.C
new file mode 100644 (file)
index 0000000..4969996
--- /dev/null
@@ -0,0 +1,18 @@
+// PR c++/26534
+// { dg-do run } 
+// { dg-options "-w -O2" }
+struct X
+{
+  unsigned a:4;
+};
+
+unsigned i;
+
+int main()
+{
+  struct X x = { 63u };
+  i = x.a;
+  if (i != 15)
+    return 1;
+}