re PR c++/55137 (Unexpected static structure initialization)
authorJakub Jelinek <jakub@redhat.com>
Thu, 6 Dec 2012 14:37:09 +0000 (15:37 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 6 Dec 2012 14:37:09 +0000 (15:37 +0100)
PR c++/55137
* fold-const.c (fold_binary_loc) <associate>: Don't introduce
TREE_OVERFLOW through reassociation.  If type doesn't have defined
overflow, but one or both of the operands do, use the wrapping type
for reassociation and only convert to type at the end.

* g++.dg/opt/pr55137.C: New test.
* gcc.c-torture/execute/pr55137.c: New test.

From-SVN: r194250

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/opt/pr55137.C [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/pr55137.c [new file with mode: 0644]

index 6b63bc237380ecf53d232e39ad161c5c3ac7a38b..348a6f6a0bba13ba70f62805c351da1575eff9dd 100644 (file)
@@ -1,3 +1,11 @@
+2012-12-06  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/55137
+       * fold-const.c (fold_binary_loc) <associate>: Don't introduce
+       TREE_OVERFLOW through reassociation.  If type doesn't have defined
+       overflow, but one or both of the operands do, use the wrapping type
+       for reassociation and only convert to type at the end.
+
 2012-12-06  Richard Biener  <rguenther@suse.de>
 
        * gimple-fold.c (fold_stmt_1): Remove code handling folding
index 071fb8c15abd6b5a6b10ef64150db753ba67d2bc..0a8b90a5d09c48fa7415d06a023c43fcc73adee8 100644 (file)
@@ -10348,6 +10348,7 @@ fold_binary_loc (location_t loc,
        {
          tree var0, con0, lit0, minus_lit0;
          tree var1, con1, lit1, minus_lit1;
+         tree atype = type;
          bool ok = true;
 
          /* Split both trees into variables, constants, and literals.  Then
@@ -10363,10 +10364,24 @@ fold_binary_loc (location_t loc,
          if (code == MINUS_EXPR)
            code = PLUS_EXPR;
 
-         /* With undefined overflow we can only associate constants with one
-            variable, and constants whose association doesn't overflow.  */
+         /* With undefined overflow prefer doing association in a type
+            which wraps on overflow, if that is one of the operand types.  */
          if ((POINTER_TYPE_P (type) && POINTER_TYPE_OVERFLOW_UNDEFINED)
              || (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type)))
+           {
+             if (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+                 && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
+               atype = TREE_TYPE (arg0);
+             else if (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+                      && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1)))
+               atype = TREE_TYPE (arg1);
+             gcc_assert (TYPE_PRECISION (atype) == TYPE_PRECISION (type));
+           }
+
+         /* With undefined overflow we can only associate constants with one
+            variable, and constants whose association doesn't overflow.  */
+         if ((POINTER_TYPE_P (atype) && POINTER_TYPE_OVERFLOW_UNDEFINED)
+             || (INTEGRAL_TYPE_P (atype) && !TYPE_OVERFLOW_WRAPS (atype)))
            {
              if (var0 && var1)
                {
@@ -10378,14 +10393,14 @@ fold_binary_loc (location_t loc,
                  if (CONVERT_EXPR_P (tmp0)
                      && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp0, 0)))
                      && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp0, 0)))
-                         <= TYPE_PRECISION (type)))
+                         <= TYPE_PRECISION (atype)))
                    tmp0 = TREE_OPERAND (tmp0, 0);
                  if (TREE_CODE (tmp1) == NEGATE_EXPR)
                    tmp1 = TREE_OPERAND (tmp1, 0);
                  if (CONVERT_EXPR_P (tmp1)
                      && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp1, 0)))
                      && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp1, 0)))
-                         <= TYPE_PRECISION (type)))
+                         <= TYPE_PRECISION (atype)))
                    tmp1 = TREE_OPERAND (tmp1, 0);
                  /* The only case we can still associate with two variables
                     is if they are the same, modulo negation and bit-pattern
@@ -10393,16 +10408,6 @@ fold_binary_loc (location_t loc,
                  if (!operand_equal_p (tmp0, tmp1, 0))
                    ok = false;
                }
-
-             if (ok && lit0 && lit1)
-               {
-                 tree tmp0 = fold_convert (type, lit0);
-                 tree tmp1 = fold_convert (type, lit1);
-
-                 if (!TREE_OVERFLOW (tmp0) && !TREE_OVERFLOW (tmp1)
-                     && TREE_OVERFLOW (fold_build2 (code, type, tmp0, tmp1)))
-                   ok = false;
-               }
            }
 
          /* Only do something if we found more than two objects.  Otherwise,
@@ -10413,10 +10418,16 @@ fold_binary_loc (location_t loc,
                       + (lit0 != 0) + (lit1 != 0)
                       + (minus_lit0 != 0) + (minus_lit1 != 0))))
            {
-             var0 = associate_trees (loc, var0, var1, code, type);
-             con0 = associate_trees (loc, con0, con1, code, type);
-             lit0 = associate_trees (loc, lit0, lit1, code, type);
-             minus_lit0 = associate_trees (loc, minus_lit0, minus_lit1, code, type);
+             bool any_overflows = false;
+             if (lit0) any_overflows |= TREE_OVERFLOW (lit0);
+             if (lit1) any_overflows |= TREE_OVERFLOW (lit1);
+             if (minus_lit0) any_overflows |= TREE_OVERFLOW (minus_lit0);
+             if (minus_lit1) any_overflows |= TREE_OVERFLOW (minus_lit1);
+             var0 = associate_trees (loc, var0, var1, code, atype);
+             con0 = associate_trees (loc, con0, con1, code, atype);
+             lit0 = associate_trees (loc, lit0, lit1, code, atype);
+             minus_lit0 = associate_trees (loc, minus_lit0, minus_lit1,
+                                           code, atype);
 
              /* Preserve the MINUS_EXPR if the negative part of the literal is
                 greater than the positive part.  Otherwise, the multiplicative
@@ -10430,38 +10441,45 @@ fold_binary_loc (location_t loc,
                      && tree_int_cst_lt (lit0, minus_lit0))
                    {
                      minus_lit0 = associate_trees (loc, minus_lit0, lit0,
-                                                   MINUS_EXPR, type);
+                                                   MINUS_EXPR, atype);
                      lit0 = 0;
                    }
                  else
                    {
                      lit0 = associate_trees (loc, lit0, minus_lit0,
-                                             MINUS_EXPR, type);
+                                             MINUS_EXPR, atype);
                      minus_lit0 = 0;
                    }
                }
+
+             /* Don't introduce overflows through reassociation.  */
+             if (!any_overflows
+                 && ((lit0 && TREE_OVERFLOW (lit0))
+                     || (minus_lit0 && TREE_OVERFLOW (minus_lit0))))
+               return NULL_TREE;
+
              if (minus_lit0)
                {
                  if (con0 == 0)
                    return
                      fold_convert_loc (loc, type,
                                        associate_trees (loc, var0, minus_lit0,
-                                                        MINUS_EXPR, type));
+                                                        MINUS_EXPR, atype));
                  else
                    {
                      con0 = associate_trees (loc, con0, minus_lit0,
-                                             MINUS_EXPR, type);
+                                             MINUS_EXPR, atype);
                      return
                        fold_convert_loc (loc, type,
                                          associate_trees (loc, var0, con0,
-                                                          PLUS_EXPR, type));
+                                                          PLUS_EXPR, atype));
                    }
                }
 
-             con0 = associate_trees (loc, con0, lit0, code, type);
+             con0 = associate_trees (loc, con0, lit0, code, atype);
              return
                fold_convert_loc (loc, type, associate_trees (loc, var0, con0,
-                                                             code, type));
+                                                             code, atype));
            }
        }
 
index f89fe3c502664d01e5c283aa9a85d230d57fa165..ce14c922f04f443917a9f5f43fce6977ed81fa19 100644 (file)
@@ -1,3 +1,9 @@
+2012-12-06  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/55137
+       * g++.dg/opt/pr55137.C: New test.
+       * gcc.c-torture/execute/pr55137.c: New test.
+
 2012-12-06  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        * lib/target-supports.exp (check_effective_target_arm_v8_neon_ok):
diff --git a/gcc/testsuite/g++.dg/opt/pr55137.C b/gcc/testsuite/g++.dg/opt/pr55137.C
new file mode 100644 (file)
index 0000000..73f8092
--- /dev/null
@@ -0,0 +1,4 @@
+// PR c++/55137
+// { dg-do compile }
+
+enum E { F = -1 + (int) (sizeof (int) - 1) };
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr55137.c b/gcc/testsuite/gcc.c-torture/execute/pr55137.c
new file mode 100644 (file)
index 0000000..80bc973
--- /dev/null
@@ -0,0 +1,30 @@
+/* PR c++/55137 */
+
+extern void abort (void);
+
+int
+foo (unsigned int x)
+{
+  return ((int) (x + 1U) + 1) < (int) x;
+}
+
+int
+bar (unsigned int x)
+{
+  return (int) (x + 1U) + 1;
+}
+
+int
+baz (unsigned int x)
+{
+  return x + 1U;
+}
+
+int
+main ()
+{
+  if (foo (__INT_MAX__) != (bar (__INT_MAX__) < __INT_MAX__)
+      || foo (__INT_MAX__) != ((int) baz (__INT_MAX__) + 1 < __INT_MAX__))
+    abort ();
+  return 0;
+}