From 84320b0be2e9182ceeb110cebb98cd7006c484ab Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor <iant@google.com>
Date: Fri, 5 Sep 2008 05:36:31 +0000
Subject: [PATCH] varasm.c (narrowing_initializer_constant_valid_p): New static
 function.

./:	* varasm.c (narrowing_initializer_constant_valid_p): New
	static function.
	(initializer_constant_valid_p): Call it.
testsuite/:
	* g++.dg/init/const7.C: New test.

From-SVN: r140025
---
 gcc/ChangeLog                      |   6 ++
 gcc/testsuite/ChangeLog            |   4 +
 gcc/testsuite/g++.dg/init/const7.C |  13 +++
 gcc/varasm.c                       | 135 +++++++++++++++++------------
 4 files changed, 103 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/init/const7.C

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ecb3bdca277e..036e97bd92cc 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e2e111f7237f..35c2f992e516 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 000000000000..18d04625db2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/const7.C
@@ -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" } }
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 5aa0140e002a..5728d195e095 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -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:
-- 
GitLab