re PR c++/4401 (Array subscript evaluation sometimes wrong for 64-bit architectures)
authorJakub Jelinek <jakub@redhat.com>
Wed, 20 Feb 2002 23:05:47 +0000 (00:05 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 20 Feb 2002 23:05:47 +0000 (00:05 +0100)
PR c++/4401
* c-common.c (pointer_int_sum): Moved from...
* c-typeck.c (pointer_int_sum): ...here.
* c-common.h (pointer_int_sum): Add prototype.

* typeck.c (cp_pointer_int_sum): Renamed from
pointer_int_sum, call pointer_int_sum.

* g++.dg/opt/ptrintsum1.C: New test.

From-SVN: r49916

gcc/ChangeLog
gcc/c-common.c
gcc/c-common.h
gcc/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/opt/ptrintsum1.C [new file with mode: 0644]

index b5f5fcd1e9c458e20d25c97a0212579d0ea1741d..59d8288a77a0da3565ed87b0cedd181462fab360 100644 (file)
@@ -1,3 +1,10 @@
+2002-02-20  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/4401
+       * c-common.c (pointer_int_sum): Moved from...
+       * c-typeck.c (pointer_int_sum): ...here.
+       * c-common.h (pointer_int_sum): Add prototype.
+
 2002-02-20  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/5713
index b2bdf50ef28c12f1963882ab3f9c4bc9eb9deccd..dfdacca3c55ecf6af202a251d297ea134aff4653 100644 (file)
@@ -1982,6 +1982,107 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
   return 0;
 }
 \f
+/* Return a tree for the sum or difference (RESULTCODE says which)
+   of pointer PTROP and integer INTOP.  */
+
+tree
+pointer_int_sum (resultcode, ptrop, intop)
+     enum tree_code resultcode;
+     tree ptrop, intop;
+{
+  tree size_exp;
+
+  tree result;
+  tree folded;
+
+  /* The result is a pointer of the same type that is being added.  */
+
+  tree result_type = TREE_TYPE (ptrop);
+
+  if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
+    {
+      if (pedantic || warn_pointer_arith)
+       pedwarn ("pointer of type `void *' used in arithmetic");
+      size_exp = integer_one_node;
+    }
+  else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
+    {
+      if (pedantic || warn_pointer_arith)
+       pedwarn ("pointer to a function used in arithmetic");
+      size_exp = integer_one_node;
+    }
+  else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
+    {
+      if (pedantic || warn_pointer_arith)
+       pedwarn ("pointer to member function used in arithmetic");
+      size_exp = integer_one_node;
+    }
+  else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
+    {
+      if (pedantic || warn_pointer_arith)
+       pedwarn ("pointer to a member used in arithmetic");
+      size_exp = integer_one_node;
+    }
+  else
+    size_exp = size_in_bytes (TREE_TYPE (result_type));
+
+  /* If what we are about to multiply by the size of the elements
+     contains a constant term, apply distributive law
+     and multiply that constant term separately.
+     This helps produce common subexpressions.  */
+
+  if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
+      && ! TREE_CONSTANT (intop)
+      && TREE_CONSTANT (TREE_OPERAND (intop, 1))
+      && TREE_CONSTANT (size_exp)
+      /* If the constant comes from pointer subtraction,
+        skip this optimization--it would cause an error.  */
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE
+      /* If the constant is unsigned, and smaller than the pointer size,
+        then we must skip this optimization.  This is because it could cause
+        an overflow error if the constant is negative but INTOP is not.  */
+      && (! TREE_UNSIGNED (TREE_TYPE (intop))
+         || (TYPE_PRECISION (TREE_TYPE (intop))
+             == TYPE_PRECISION (TREE_TYPE (ptrop)))))
+    {
+      enum tree_code subcode = resultcode;
+      tree int_type = TREE_TYPE (intop);
+      if (TREE_CODE (intop) == MINUS_EXPR)
+       subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
+      /* Convert both subexpression types to the type of intop,
+        because weird cases involving pointer arithmetic
+        can result in a sum or difference with different type args.  */
+      ptrop = build_binary_op (subcode, ptrop,
+                              convert (int_type, TREE_OPERAND (intop, 1)), 1);
+      intop = convert (int_type, TREE_OPERAND (intop, 0));
+    }
+
+  /* Convert the integer argument to a type the same size as sizetype
+     so the multiply won't overflow spuriously.  */
+
+  if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)
+      || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype))
+    intop = convert (type_for_size (TYPE_PRECISION (sizetype), 
+                                   TREE_UNSIGNED (sizetype)), intop);
+
+  /* Replace the integer argument with a suitable product by the object size.
+     Do this multiplication as signed, then convert to the appropriate
+     pointer type (actually unsigned integral).  */
+
+  intop = convert (result_type,
+                  build_binary_op (MULT_EXPR, intop,
+                                   convert (TREE_TYPE (intop), size_exp), 1));
+
+  /* Create the sum or difference.  */
+
+  result = build (resultcode, result_type, ptrop, intop);
+
+  folded = fold (result);
+  if (folded == result)
+    TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
+  return folded;
+}
+\f
 /* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
    or validate its data type for an `if' or `while' statement or ?..: exp.
 
index c90cbfb076b19a6e454834c665969cfe3b770358..9bb2d1ac23398c218716dcc97f172c7c69197b92 100644 (file)
@@ -538,6 +538,7 @@ extern char *get_directive_line                     PARAMS ((void));
    and, if so, perhaps change them both back to their original type.  */
 extern tree shorten_compare                    PARAMS ((tree *, tree *, tree *, enum tree_code *));
 
+extern tree pointer_int_sum                    PARAMS ((enum tree_code, tree, tree));
 extern unsigned int min_precision              PARAMS ((tree, int));
 
 /* Add qualifiers to a type, in the fashion for C.  */
index dd8abdd11f75181e787a39176daa99e72dc901b5..4ee7cb3b69757f38e4f1f8cb1d3ac52a2e38d4f3 100644 (file)
@@ -58,7 +58,6 @@ static tree decl_constant_value_for_broken_optimization PARAMS ((tree));
 static tree default_function_array_conversion  PARAMS ((tree));
 static tree lookup_field               PARAMS ((tree, tree));
 static tree convert_arguments          PARAMS ((tree, tree, tree, tree));
-static tree pointer_int_sum            PARAMS ((enum tree_code, tree, tree));
 static tree pointer_diff               PARAMS ((tree, tree));
 static tree unary_complex_lvalue       PARAMS ((enum tree_code, tree, int));
 static void pedantic_lvalue_warning    PARAMS ((enum tree_code));
@@ -2637,95 +2636,6 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
   }
 }
 \f
-/* Return a tree for the sum or difference (RESULTCODE says which)
-   of pointer PTROP and integer INTOP.  */
-
-static tree
-pointer_int_sum (resultcode, ptrop, intop)
-     enum tree_code resultcode;
-     tree ptrop, intop;
-{
-  tree size_exp;
-
-  tree result;
-  tree folded;
-
-  /* The result is a pointer of the same type that is being added.  */
-
-  tree result_type = TREE_TYPE (ptrop);
-
-  if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("pointer of type `void *' used in arithmetic");
-      size_exp = integer_one_node;
-    }
-  else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("pointer to a function used in arithmetic");
-      size_exp = integer_one_node;
-    }
-  else
-    size_exp = c_size_in_bytes (TREE_TYPE (result_type));
-
-  /* If what we are about to multiply by the size of the elements
-     contains a constant term, apply distributive law
-     and multiply that constant term separately.
-     This helps produce common subexpressions.  */
-
-  if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
-      && ! TREE_CONSTANT (intop)
-      && TREE_CONSTANT (TREE_OPERAND (intop, 1))
-      && TREE_CONSTANT (size_exp)
-      /* If the constant comes from pointer subtraction,
-        skip this optimization--it would cause an error.  */
-      && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE
-      /* If the constant is unsigned, and smaller than the pointer size,
-        then we must skip this optimization.  This is because it could cause
-        an overflow error if the constant is negative but INTOP is not.  */
-      && (! TREE_UNSIGNED (TREE_TYPE (intop))
-         || (TYPE_PRECISION (TREE_TYPE (intop))
-             == TYPE_PRECISION (TREE_TYPE (ptrop)))))
-    {
-      enum tree_code subcode = resultcode;
-      tree int_type = TREE_TYPE (intop);
-      if (TREE_CODE (intop) == MINUS_EXPR)
-       subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
-      /* Convert both subexpression types to the type of intop,
-        because weird cases involving pointer arithmetic
-        can result in a sum or difference with different type args.  */
-      ptrop = build_binary_op (subcode, ptrop,
-                              convert (int_type, TREE_OPERAND (intop, 1)), 1);
-      intop = convert (int_type, TREE_OPERAND (intop, 0));
-    }
-
-  /* Convert the integer argument to a type the same size as sizetype
-     so the multiply won't overflow spuriously.  */
-
-  if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)
-      || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype))
-    intop = convert (type_for_size (TYPE_PRECISION (sizetype), 
-                                   TREE_UNSIGNED (sizetype)), intop);
-
-  /* Replace the integer argument with a suitable product by the object size.
-     Do this multiplication as signed, then convert to the appropriate
-     pointer type (actually unsigned integral).  */
-
-  intop = convert (result_type,
-                  build_binary_op (MULT_EXPR, intop,
-                                   convert (TREE_TYPE (intop), size_exp), 1));
-
-  /* Create the sum or difference.  */
-
-  result = build (resultcode, result_type, ptrop, intop);
-
-  folded = fold (result);
-  if (folded == result)
-    TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
-  return folded;
-}
-
 /* Return a tree for the difference of pointers OP0 and OP1.
    The resulting tree has type int.  */
 
index 975918426331f3d05f68afb06484aba4bb648d36..b4a5b0bcf2461eb4b6e29e482c563cf177c66e0c 100644 (file)
@@ -1,3 +1,8 @@
+2002-02-20  Jakub Jelinek  <jakub@redhat.com>
+
+       * typeck.c (cp_pointer_int_sum): Renamed from
+       pointer_int_sum, call pointer_int_sum.
+
 2002-02-20  Jakub Jelinek  <jakub@redhat.com>
 
        * decl.c (duplicate_decls): Return 0 if issued error about
index 62d17a8cfd94e7fbecb71f4776ba80dcbda25471..6ca524233d8d6aa5b2dbd0395fb98077ede54aae 100644 (file)
@@ -45,7 +45,7 @@ Boston, MA 02111-1307, USA.  */
 
 static tree convert_for_assignment PARAMS ((tree, tree, const char *, tree,
                                          int));
-static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree));
+static tree cp_pointer_int_sum PARAMS ((enum tree_code, tree, tree));
 static tree rationalize_conditional_expr PARAMS ((enum tree_code, tree));
 static int comp_target_parms PARAMS ((tree, tree));
 static int comp_ptr_ttypes_real PARAMS ((tree, tree, int));
@@ -3452,9 +3452,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case PLUS_EXPR:
       /* Handle the pointer + int case.  */
       if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
-       return pointer_int_sum (PLUS_EXPR, op0, op1);
+       return cp_pointer_int_sum (PLUS_EXPR, op0, op1);
       else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
-       return pointer_int_sum (PLUS_EXPR, op1, op0);
+       return cp_pointer_int_sum (PLUS_EXPR, op1, op0);
       else
        common = 1;
       break;
@@ -3467,7 +3467,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        return pointer_diff (op0, op1, common_type (type0, type1));
       /* Handle pointer minus int.  Just like pointer plus int.  */
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
-       return pointer_int_sum (MINUS_EXPR, op0, op1);
+       return cp_pointer_int_sum (MINUS_EXPR, op0, op1);
       else
        common = 1;
       break;
@@ -4072,94 +4072,14 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
    of pointer PTROP and integer INTOP.  */
 
 static tree
-pointer_int_sum (resultcode, ptrop, intop)
+cp_pointer_int_sum (resultcode, ptrop, intop)
      enum tree_code resultcode;
      register tree ptrop, intop;
 {
-  tree size_exp;
-
-  register tree result;
-  register tree folded = fold (intop);
-
-  /* The result is a pointer of the same type that is being added.  */
-
-  register tree result_type = TREE_TYPE (ptrop);
-
-  if (!complete_type_or_else (result_type, ptrop))
+  if (!complete_type_or_else (TREE_TYPE (ptrop), ptrop))
     return error_mark_node;
 
-  if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids using pointer of type `void *' in pointer arithmetic");
-      size_exp = integer_one_node;
-    }
-  else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids using a pointer-to-function in pointer arithmetic");
-      size_exp = integer_one_node;
-    }
-  else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids using a pointer to member function in pointer arithmetic");
-      size_exp = integer_one_node;
-    }
-  else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
-    {
-      if (pedantic || warn_pointer_arith)
-       pedwarn ("ISO C++ forbids using pointer to a member in pointer arithmetic");
-      size_exp = integer_one_node;
-    }
-  else
-    size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type)));
-
-  /* Needed to make OOPS V2R3 work.  */
-  intop = folded;
-  if (integer_zerop (intop))
-    return ptrop;
-
-  /* If what we are about to multiply by the size of the elements
-     contains a constant term, apply distributive law
-     and multiply that constant term separately.
-     This helps produce common subexpressions.  */
-
-  if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
-      && ! TREE_CONSTANT (intop)
-      && TREE_CONSTANT (TREE_OPERAND (intop, 1))
-      && TREE_CONSTANT (size_exp))
-    {
-      enum tree_code subcode = resultcode;
-      if (TREE_CODE (intop) == MINUS_EXPR)
-       subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
-      ptrop = cp_build_binary_op (subcode, ptrop, TREE_OPERAND (intop, 1));
-      intop = TREE_OPERAND (intop, 0);
-    }
-
-  /* Convert the integer argument to a type the same size as sizetype
-     so the multiply won't overflow spuriously.  */
-
-  if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
-    intop = cp_convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
-
-  /* Replace the integer argument with a suitable product by the object size.
-     Do this multiplication as signed, then convert to the appropriate
-     pointer type (actually unsigned integral).  */
-
-  intop = cp_convert (result_type,
-                     cp_build_binary_op (MULT_EXPR, intop,
-                                         cp_convert (TREE_TYPE (intop),
-                                                     size_exp)));
-
-  /* Create the sum or difference.  */
-
-  result = build (resultcode, result_type, ptrop, intop);
-
-  folded = fold (result);
-  if (folded == result)
-    TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
-  return folded;
+  return pointer_int_sum (resultcode, ptrop, fold (intop));
 }
 
 /* Return a tree for the difference of pointers OP0 and OP1.
index 65b5ecbb594a8f0c29227a0f5466834f18954b4c..ebf920fc0f8b5494b07178ddd6c00769b943eb08 100644 (file)
@@ -6,6 +6,8 @@
 
        * gcc.dg/noncompile/20020220-1.c: New test.
 
+       * g++.dg/opt/ptrintsum1.C: New test.
+
 2002-02-17  Jakub Jelinek  <jakub@redhat.com>
 
        * gcc.c-torture/execute/20020216-1.c: New test.
diff --git a/gcc/testsuite/g++.dg/opt/ptrintsum1.C b/gcc/testsuite/g++.dg/opt/ptrintsum1.C
new file mode 100644 (file)
index 0000000..a6a3c97
--- /dev/null
@@ -0,0 +1,29 @@
+// PR c++/4401
+// This testcase was miscompiled on 64-bit platforms, resulting to
+// operating on a[0x100000000] instead of a[0].
+// { dg-do run }
+// { dg-options "-O2" }
+
+char *a;
+char b[] = "AAAA";
+
+extern "C" void abort (void);
+extern "C" void exit (int);
+
+void foo (void)
+{
+  unsigned int i, j;
+
+  i = 2;
+  j = 3;
+  a[i + 1 - j] += i;
+}
+
+int main (void)
+{
+  a = b;
+  foo ();
+  if (b[0] != 'A' + 2)
+    abort ();
+  exit (0);
+}