re PR c++/14755 (miscompilation in bitfielded signed integers)
authorJakub Jelinek <jakub@redhat.com>
Thu, 1 Apr 2004 15:50:11 +0000 (17:50 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 1 Apr 2004 15:50:11 +0000 (17:50 +0200)
PR c++/14755
* fold-const.c (fold) <EQ_EXPR>: Properly compute newconst in
"bitfld++ == const" to "++bitfld == const + incr" transformations.

* gcc.c-torture/execute/20040331-1.c: New test.
* gcc.dg/20040331-1.c: New test.

From-SVN: r80294

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/20040331-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/20040331-1.c [new file with mode: 0644]

index a1fffe747d4442920597aefcfcd45a7f2aadcd9a..d49190d45372d675be935ae6c3a794efc8db64ee 100644 (file)
@@ -1,3 +1,9 @@
+2004-04-01  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/14755
+       * fold-const.c (fold) <EQ_EXPR>: Properly compute newconst in
+       "bitfld++ == const" to "++bitfld == const + incr" transformations.
+
 2004-04-01  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
 
        * expr.c (get_inner_reference): Use DECL_UNSIGNED, not TREE_UNSIGNED.
index 51e986abf38a4fcb37a884e72df4d937e49b9442..772e64e5d2ae6a1d9f2310df4070dc4edbc6925a 100644 (file)
@@ -7338,12 +7338,11 @@ fold (tree expr)
          /* If VAROP is a reference to a bitfield, we must mask
             the constant by the width of the field.  */
          if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
-             && DECL_BIT_FIELD(TREE_OPERAND (TREE_OPERAND (varop, 0), 1)))
+             && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1)))
            {
              tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
              int size = TREE_INT_CST_LOW (DECL_SIZE (fielddecl));
-             tree folded_compare;
-             tree mask = 0;
+             tree folded_compare, shift;
 
              /* First check whether the comparison would come out
                 always the same.  If we don't do that we would
@@ -7355,25 +7354,12 @@ fold (tree expr)
                  || integer_onep (folded_compare))
                return omit_one_operand (type, folded_compare, varop);
 
-             if (size < HOST_BITS_PER_WIDE_INT)
-               {
-                 unsigned HOST_WIDE_INT lo = ((unsigned HOST_WIDE_INT) 1
-                                              << size) - 1;
-                 mask = build_int_2 (lo, 0);
-               }
-             else if (size < 2 * HOST_BITS_PER_WIDE_INT)
-               {
-                 HOST_WIDE_INT hi = ((HOST_WIDE_INT) 1
-                                     << (size - HOST_BITS_PER_WIDE_INT)) - 1;
-                 mask = build_int_2 (~0, hi);
-               }
-                  
-             if (mask)
-               {
-                 mask = fold_convert (TREE_TYPE (varop), mask);
-                 newconst = fold (build2 (BIT_AND_EXPR, TREE_TYPE (varop),
-                                          newconst, mask));
-               }
+             shift = build_int_2 (TYPE_PRECISION (TREE_TYPE (varop)) - size,
+                                  0);
+             newconst = fold (build2 (LSHIFT_EXPR, TREE_TYPE (varop),
+                                      newconst, shift));
+             newconst = fold (build2 (RSHIFT_EXPR, TREE_TYPE (varop),
+                                      newconst, shift));
            }
 
          return fold (build2 (code, type, varop, newconst));
index 07d0501371015fe3878495b9dd5a4f5ab402376d..af93d21eb559d90e8d7bf9a91f51a06936235d61 100644 (file)
@@ -1,3 +1,9 @@
+2004-04-01  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/14755
+       * gcc.c-torture/execute/20040331-1.c: New test.
+       * gcc.dg/20040331-1.c: New test.
+
 2004-04-01  Paul Brook  <paul@codesourcery.com>
 
        * gcc.dg/arm-mmx-1.c: Add -mabi=iwmmxt to dg-options.
diff --git a/gcc/testsuite/gcc.c-torture/execute/20040331-1.c b/gcc/testsuite/gcc.c-torture/execute/20040331-1.c
new file mode 100644 (file)
index 0000000..67b3e3a
--- /dev/null
@@ -0,0 +1,12 @@
+/* PR c++/14755 */
+extern void abort (void);
+extern void exit (int);
+
+int
+main (void)
+{
+  struct { int count: 31; } s = { 0 };
+  while (s.count--)
+    abort ();
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/20040331-1.c b/gcc/testsuite/gcc.dg/20040331-1.c
new file mode 100644 (file)
index 0000000..4cef3d3
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fwrapv" } */
+
+extern void abort (void);
+extern void exit (int);
+
+int
+main (void)
+{
+  struct { int count: 2; } s = { -2 };
+  while (s.count-- != -2)
+    abort ();
+  exit (0);
+}