Commit 7552da58 by Jakub Jelinek Committed by Jakub Jelinek

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
parent 00fae85d
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.
......
......@@ -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.
......
......@@ -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. */
......
......@@ -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. */
......
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.
......
......@@ -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.
......
......@@ -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.
......
// 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment