./:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Sep 2008 05:36:31 +0000 (05:36 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Sep 2008 05:36:31 +0000 (05:36 +0000)
* varasm.c (narrowing_initializer_constant_valid_p): New
static function.
(initializer_constant_valid_p): Call it.
testsuite/:
* g++.dg/init/const7.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@140025 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/init/const7.C [new file with mode: 0644]
gcc/varasm.c

index ecb3bdc..036e97b 100644 (file)
@@ -1,3 +1,9 @@
+2008-09-04  Ian Lance Taylor  <iant@google.com>
+
+       * varasm.c (narrowing_initializer_constant_valid_p): New
+       static function.
+       (initializer_constant_valid_p): Call it.
+
 2008-09-04  Jeff Law  <law@redhat.com>
 
        * fold-const.c (native_encode_real): Fix computation of WORDS.
index e2e111f..35c2f99 100644 (file)
@@ -1,3 +1,7 @@
+2008-09-04  Ian Lance Taylor  <iant@google.com>
+
+       * g++.dg/init/const7.C: New test.
+
 2008-09-04  Adam Nemet  <anemet@caviumnetworks.com>
 
        * gcc.target/mips/seq-1.c: New test.
diff --git a/gcc/testsuite/g++.dg/init/const7.C b/gcc/testsuite/g++.dg/init/const7.C
new file mode 100644 (file)
index 0000000..18d0462
--- /dev/null
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-fdump-tree-gimple" }
+
+struct s { int x, y; };
+short offsets[1] = {
+  ((char*) &(((struct s*)16)->y) - (char *)16),
+};
+
+// This ensures that we get a dump whether or not the bug is present.
+void fn() { }
+
+// { dg-final { scan-tree-dump-not "initialization"  "gimple" } }
+// { dg-final { cleanup-tree-dump "gimple" } }
index 5aa0140..5728d19 100644 (file)
@@ -4063,6 +4063,73 @@ constructor_static_from_elts_p (const_tree ctor)
          && !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
 }
 
+/* A subroutine of initializer_constant_valid_p.  VALUE is either a
+   MINUS_EXPR or a POINTER_PLUS_EXPR, and ENDTYPE is a narrowing
+   conversion to something smaller than a pointer.  This returns
+   null_pointer_node if the resulting value is an absolute constant
+   which can be used to initialize a static variable.  Otherwise it
+   returns NULL.  */
+
+static tree
+narrowing_initializer_constant_valid_p (tree value, tree endtype)
+{
+  tree op0, op1;
+
+  op0 = TREE_OPERAND (value, 0);
+  op1 = TREE_OPERAND (value, 1);
+
+  /* Like STRIP_NOPS except allow the operand mode to widen.  This
+     works around a feature of fold that simplifies (int)(p1 - p2) to
+     ((int)p1 - (int)p2) under the theory that the narrower operation
+     is cheaper.  */
+
+  while (CONVERT_EXPR_P (op0)
+        || TREE_CODE (op0) == NON_LVALUE_EXPR)
+    {
+      tree inner = TREE_OPERAND (op0, 0);
+      if (inner == error_mark_node
+         || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+         || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
+             > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+       break;
+      op0 = inner;
+    }
+
+  while (CONVERT_EXPR_P (op1)
+        || TREE_CODE (op1) == NON_LVALUE_EXPR)
+    {
+      tree inner = TREE_OPERAND (op1, 0);
+      if (inner == error_mark_node
+         || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+         || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
+             > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+       break;
+      op1 = inner;
+    }
+
+  op0 = initializer_constant_valid_p (op0, endtype);
+  op1 = initializer_constant_valid_p (op1, endtype);
+
+  /* Both initializers must be known.  */
+  if (op0 && op1)
+    {
+      if (op0 == op1)
+       return null_pointer_node;
+
+      /* Support differences between labels.  */
+      if (TREE_CODE (op0) == LABEL_DECL
+         && TREE_CODE (op1) == LABEL_DECL)
+       return null_pointer_node;
+
+      if (TREE_CODE (op0) == STRING_CST
+         && TREE_CODE (op1) == STRING_CST
+         && operand_equal_p (op0, op1, 1))
+       return null_pointer_node;
+    }
+
+  return NULL_TREE;
+}
+
 /* Return nonzero if VALUE is a valid constant-valued expression
    for use in initializing a static variable; one that can be an
    element of a "constant" initializer.
@@ -4076,6 +4143,8 @@ constructor_static_from_elts_p (const_tree ctor)
 tree
 initializer_constant_valid_p (tree value, tree endtype)
 {
+  tree ret;
+
   switch (TREE_CODE (value))
     {
     case CONSTRUCTOR:
@@ -4216,6 +4285,14 @@ initializer_constant_valid_p (tree value, tree endtype)
          if (valid1 == null_pointer_node)
            return valid0;
        }
+
+      /* Support narrowing pointer differences.  */
+      if (TREE_CODE (value) == POINTER_PLUS_EXPR)
+       {
+         ret = narrowing_initializer_constant_valid_p (value, endtype);
+         if (ret != NULL_TREE)
+           return ret;
+       }
       break;
 
     case MINUS_EXPR:
@@ -4244,62 +4321,10 @@ initializer_constant_valid_p (tree value, tree endtype)
        }
 
       /* Support narrowing differences.  */
-      if (INTEGRAL_TYPE_P (endtype))
-       {
-         tree op0, op1;
+      ret = narrowing_initializer_constant_valid_p (value, endtype);
+      if (ret != NULL_TREE)
+       return ret;
 
-         op0 = TREE_OPERAND (value, 0);
-         op1 = TREE_OPERAND (value, 1);
-
-         /* Like STRIP_NOPS except allow the operand mode to widen.
-            This works around a feature of fold that simplifies
-            (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
-            that the narrower operation is cheaper.  */
-
-         while (CONVERT_EXPR_P (op0)
-                || TREE_CODE (op0) == NON_LVALUE_EXPR)
-           {
-             tree inner = TREE_OPERAND (op0, 0);
-             if (inner == error_mark_node
-                 || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
-                 || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
-                     > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
-               break;
-             op0 = inner;
-           }
-
-         while (CONVERT_EXPR_P (op1)
-                || TREE_CODE (op1) == NON_LVALUE_EXPR)
-           {
-             tree inner = TREE_OPERAND (op1, 0);
-             if (inner == error_mark_node
-                 || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
-                 || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
-                     > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
-               break;
-             op1 = inner;
-           }
-
-         op0 = initializer_constant_valid_p (op0, endtype);
-         op1 = initializer_constant_valid_p (op1, endtype);
-
-         /* Both initializers must be known.  */
-         if (op0 && op1)
-           {
-             if (op0 == op1)
-               return null_pointer_node;
-
-             /* Support differences between labels.  */
-             if (TREE_CODE (op0) == LABEL_DECL
-                 && TREE_CODE (op1) == LABEL_DECL)
-               return null_pointer_node;
-
-             if (TREE_CODE (op0) == STRING_CST
-                 && TREE_CODE (op1) == STRING_CST
-                 && operand_equal_p (op0, op1, 1))
-               return null_pointer_node;
-           }
-       }
       break;
 
     default: