summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2002-02-21 00:05:47 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2002-02-21 00:05:47 +0100
commit7552da58e17fb0e2c53a03bd986eee6baea79730 (patch)
tree61e2d388e4c9e1800d174ed4d1ad82befd143f53 /gcc
parent00fae85dcb96cb20e723b37ae16dcf1cf09434da (diff)
downloadgcc-7552da58e17fb0e2c53a03bd986eee6baea79730.tar.gz
re PR c++/4401 (Array subscript evaluation sometimes wrong for 64-bit architectures)
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/c-common.c101
-rw-r--r--gcc/c-common.h1
-rw-r--r--gcc/c-typeck.c90
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/typeck.c94
-rw-r--r--gcc/testsuite/ChangeLog2
-rw-r--r--gcc/testsuite/g++.dg/opt/ptrintsum1.C29
8 files changed, 152 insertions, 177 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b5f5fcd1e9c..59d8288a77a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,12 @@
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
* c-decl.c (duplicate_decls): Return 0 if issued error about
redeclaration.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index b2bdf50ef28..dfdacca3c55 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -1982,6 +1982,107 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
return 0;
}
+/* 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;
+}
+
/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
or validate its data type for an `if' or `while' statement or ?..: exp.
diff --git a/gcc/c-common.h b/gcc/c-common.h
index c90cbfb076b..9bb2d1ac233 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -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. */
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index dd8abdd11f7..4ee7cb3b697 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -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)
}
}
-/* 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. */
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 97591842633..b4a5b0bcf24 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,10 @@
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
redeclaration.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 62d17a8cfd9..6ca524233d8 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 65b5ecbb594..ebf920fc0f8 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..a6a3c9727db
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/ptrintsum1.C
@@ -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);
+}