re PR tree-optimization/43270 (array-bounds false negative)
2010-04-07 Richard Guenther <rguenther@suse.de> PR tree-optimization/43270 * tree-vrp.c (check_array_ref): Fix flexible array member detection. * tree-ssa-sccvn.h (fully_constant_vn_reference_p): Declare. * tree-ssa-pre.c (phi_translate_1): Adjust. (fully_constant_expression): Split out vn_reference handling to ... * tree-ssa-sccvn.c (fully_constant_vn_reference_p): ... here. Fold reads from constant strings. (vn_reference_lookup): Handle fully constant references. (vn_reference_lookup_pieces): Likewise. * Makefile.in (expmed.o-warn): Add -Wno-error. * g++.dg/warn/Warray-bounds-4.C: New testcase. * gcc.dg/Warray-bounds-7.c: Likewise. From-SVN: r158058
This commit is contained in:
parent
a775239672
commit
12bd5a1e9f
9 changed files with 196 additions and 66 deletions
|
@ -1,3 +1,17 @@
|
|||
2010-04-07 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/43270
|
||||
* tree-vrp.c (check_array_ref): Fix flexible array member
|
||||
detection.
|
||||
* tree-ssa-sccvn.h (fully_constant_vn_reference_p): Declare.
|
||||
* tree-ssa-pre.c (phi_translate_1): Adjust.
|
||||
(fully_constant_expression): Split out vn_reference handling to ...
|
||||
* tree-ssa-sccvn.c (fully_constant_vn_reference_p): ... here.
|
||||
Fold reads from constant strings.
|
||||
(vn_reference_lookup): Handle fully constant references.
|
||||
(vn_reference_lookup_pieces): Likewise.
|
||||
* Makefile.in (expmed.o-warn): Add -Wno-error.
|
||||
|
||||
2010-04-07 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* tree-sra.c (find_param_candidates): Allow scalar va_list types.
|
||||
|
|
|
@ -183,6 +183,7 @@ GCC_WARN_CXXFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn)
|
|||
build/gengtype-lex.o-warn = -Wno-error
|
||||
# mips-tfile.c contains -Wcast-qual warnings.
|
||||
mips-tfile.o-warn = -Wno-error
|
||||
expmed.o-warn = -Wno-error
|
||||
|
||||
# All warnings have to be shut off in stage1 if the compiler used then
|
||||
# isn't gcc; configure determines that. WARN_CFLAGS will be either
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2010-04-07 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/43270
|
||||
* g++.dg/warn/Warray-bounds-4.C: New testcase.
|
||||
* gcc.dg/Warray-bounds-7.c: Likewise.
|
||||
|
||||
2010-04-07 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* gnat.dg/bit_packed_array.ad[sb]: Rename into...
|
||||
|
|
37
gcc/testsuite/g++.dg/warn/Warray-bounds-4.C
Normal file
37
gcc/testsuite/g++.dg/warn/Warray-bounds-4.C
Normal file
|
@ -0,0 +1,37 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-O2 -Warray-bounds" }
|
||||
|
||||
class String
|
||||
{
|
||||
public:
|
||||
virtual unsigned long length() const = 0;
|
||||
virtual char get(unsigned long index) const = 0;
|
||||
virtual void set(unsigned long index, char value) = 0;
|
||||
virtual char& operator[] (unsigned long value) = 0;
|
||||
virtual ~String() {};
|
||||
};
|
||||
|
||||
template<unsigned long size> class FixedString : public String
|
||||
{
|
||||
private:
|
||||
char contents[size];
|
||||
|
||||
public:
|
||||
virtual unsigned long length() const { return size; }
|
||||
virtual char get(unsigned long index) const { return contents[index]; }
|
||||
virtual void set(unsigned long index, char value) { contents[index] = value; }
|
||||
virtual char& operator[] (unsigned long index) { return contents[index]; }
|
||||
|
||||
FixedString() { contents[0] = '\0'; } // { dg-warning "above array bounds" }
|
||||
};
|
||||
|
||||
void print_length (const String& string);
|
||||
|
||||
int main()
|
||||
{
|
||||
const FixedString<0> empty;
|
||||
|
||||
print_length(empty);
|
||||
|
||||
return 0;
|
||||
}
|
13
gcc/testsuite/gcc.dg/Warray-bounds-7.c
Normal file
13
gcc/testsuite/gcc.dg/Warray-bounds-7.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -Warray-bounds" } */
|
||||
|
||||
char *p;
|
||||
|
||||
int main()
|
||||
{
|
||||
p = "";
|
||||
if (p[0] == 0
|
||||
|| (p[0] == '_' && p[1] == 0)) /* { dg-bogus "array bounds" "" } */
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
|
@ -1231,49 +1231,11 @@ do_unary:
|
|||
case REFERENCE:
|
||||
{
|
||||
vn_reference_t ref = PRE_EXPR_REFERENCE (e);
|
||||
VEC (vn_reference_op_s, heap) *operands = ref->operands;
|
||||
vn_reference_op_t op;
|
||||
|
||||
/* Try to simplify the translated expression if it is
|
||||
a call to a builtin function with at most two arguments. */
|
||||
op = VEC_index (vn_reference_op_s, operands, 0);
|
||||
if (op->opcode == CALL_EXPR
|
||||
&& TREE_CODE (op->op0) == ADDR_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (op->op0, 0)) == FUNCTION_DECL
|
||||
&& DECL_BUILT_IN (TREE_OPERAND (op->op0, 0))
|
||||
&& VEC_length (vn_reference_op_s, operands) >= 2
|
||||
&& VEC_length (vn_reference_op_s, operands) <= 3)
|
||||
{
|
||||
vn_reference_op_t arg0, arg1 = NULL;
|
||||
bool anyconst = false;
|
||||
arg0 = VEC_index (vn_reference_op_s, operands, 1);
|
||||
if (VEC_length (vn_reference_op_s, operands) > 2)
|
||||
arg1 = VEC_index (vn_reference_op_s, operands, 2);
|
||||
if (TREE_CODE_CLASS (arg0->opcode) == tcc_constant
|
||||
|| (arg0->opcode == ADDR_EXPR
|
||||
&& is_gimple_min_invariant (arg0->op0)))
|
||||
anyconst = true;
|
||||
if (arg1
|
||||
&& (TREE_CODE_CLASS (arg1->opcode) == tcc_constant
|
||||
|| (arg1->opcode == ADDR_EXPR
|
||||
&& is_gimple_min_invariant (arg1->op0))))
|
||||
anyconst = true;
|
||||
if (anyconst)
|
||||
{
|
||||
tree folded = build_call_expr (TREE_OPERAND (op->op0, 0),
|
||||
arg1 ? 2 : 1,
|
||||
arg0->op0,
|
||||
arg1 ? arg1->op0 : NULL);
|
||||
if (folded
|
||||
&& TREE_CODE (folded) == NOP_EXPR)
|
||||
folded = TREE_OPERAND (folded, 0);
|
||||
if (folded
|
||||
&& is_gimple_min_invariant (folded))
|
||||
return get_or_alloc_expr_for_constant (folded);
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
tree folded;
|
||||
if ((folded = fully_constant_vn_reference_p (ref)))
|
||||
return get_or_alloc_expr_for_constant (folded);
|
||||
return e;
|
||||
}
|
||||
default:
|
||||
return e;
|
||||
}
|
||||
|
@ -1702,7 +1664,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
|
|||
ref->type,
|
||||
newoperands,
|
||||
&newref, true);
|
||||
if (newref)
|
||||
if (result)
|
||||
VEC_free (vn_reference_op_s, heap, newoperands);
|
||||
|
||||
if (result && is_gimple_min_invariant (result))
|
||||
|
|
|
@ -889,6 +889,76 @@ vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops,
|
|||
*i_p = i;
|
||||
}
|
||||
|
||||
/* Optimize the reference REF to a constant if possible or return
|
||||
NULL_TREE if not. */
|
||||
|
||||
tree
|
||||
fully_constant_vn_reference_p (vn_reference_t ref)
|
||||
{
|
||||
VEC (vn_reference_op_s, heap) *operands = ref->operands;
|
||||
vn_reference_op_t op;
|
||||
|
||||
/* Try to simplify the translated expression if it is
|
||||
a call to a builtin function with at most two arguments. */
|
||||
op = VEC_index (vn_reference_op_s, operands, 0);
|
||||
if (op->opcode == CALL_EXPR
|
||||
&& TREE_CODE (op->op0) == ADDR_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (op->op0, 0)) == FUNCTION_DECL
|
||||
&& DECL_BUILT_IN (TREE_OPERAND (op->op0, 0))
|
||||
&& VEC_length (vn_reference_op_s, operands) >= 2
|
||||
&& VEC_length (vn_reference_op_s, operands) <= 3)
|
||||
{
|
||||
vn_reference_op_t arg0, arg1 = NULL;
|
||||
bool anyconst = false;
|
||||
arg0 = VEC_index (vn_reference_op_s, operands, 1);
|
||||
if (VEC_length (vn_reference_op_s, operands) > 2)
|
||||
arg1 = VEC_index (vn_reference_op_s, operands, 2);
|
||||
if (TREE_CODE_CLASS (arg0->opcode) == tcc_constant
|
||||
|| (arg0->opcode == ADDR_EXPR
|
||||
&& is_gimple_min_invariant (arg0->op0)))
|
||||
anyconst = true;
|
||||
if (arg1
|
||||
&& (TREE_CODE_CLASS (arg1->opcode) == tcc_constant
|
||||
|| (arg1->opcode == ADDR_EXPR
|
||||
&& is_gimple_min_invariant (arg1->op0))))
|
||||
anyconst = true;
|
||||
if (anyconst)
|
||||
{
|
||||
tree folded = build_call_expr (TREE_OPERAND (op->op0, 0),
|
||||
arg1 ? 2 : 1,
|
||||
arg0->op0,
|
||||
arg1 ? arg1->op0 : NULL);
|
||||
if (folded
|
||||
&& TREE_CODE (folded) == NOP_EXPR)
|
||||
folded = TREE_OPERAND (folded, 0);
|
||||
if (folded
|
||||
&& is_gimple_min_invariant (folded))
|
||||
return folded;
|
||||
}
|
||||
}
|
||||
|
||||
/* Simplify reads from constant strings. */
|
||||
else if (op->opcode == ARRAY_REF
|
||||
&& TREE_CODE (op->op0) == INTEGER_CST
|
||||
&& integer_zerop (op->op1)
|
||||
&& VEC_length (vn_reference_op_s, operands) == 2)
|
||||
{
|
||||
vn_reference_op_t arg0;
|
||||
arg0 = VEC_index (vn_reference_op_s, operands, 1);
|
||||
if (arg0->opcode == STRING_CST
|
||||
&& (TYPE_MODE (op->type)
|
||||
== TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0->op0))))
|
||||
&& GET_MODE_CLASS (TYPE_MODE (op->type)) == MODE_INT
|
||||
&& GET_MODE_SIZE (TYPE_MODE (op->type)) == 1
|
||||
&& compare_tree_int (op->op0, TREE_STRING_LENGTH (arg0->op0)) < 0)
|
||||
return build_int_cst_type (op->type,
|
||||
(TREE_STRING_POINTER (arg0->op0)
|
||||
[TREE_INT_CST_LOW (op->op0)]));
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Transform any SSA_NAME's in a vector of vn_reference_op_s
|
||||
structures into their value numbers. This is done in-place, and
|
||||
the vector passed in is returned. */
|
||||
|
@ -1194,6 +1264,7 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type,
|
|||
{
|
||||
struct vn_reference_s vr1;
|
||||
vn_reference_t tmp;
|
||||
tree cst;
|
||||
|
||||
if (!vnresult)
|
||||
vnresult = &tmp;
|
||||
|
@ -1212,8 +1283,10 @@ vn_reference_lookup_pieces (tree vuse, alias_set_type set, tree type,
|
|||
vr1.type = type;
|
||||
vr1.set = set;
|
||||
vr1.hashcode = vn_reference_compute_hash (&vr1);
|
||||
vn_reference_lookup_1 (&vr1, vnresult);
|
||||
if ((cst = fully_constant_vn_reference_p (&vr1)))
|
||||
return cst;
|
||||
|
||||
vn_reference_lookup_1 (&vr1, vnresult);
|
||||
if (!*vnresult
|
||||
&& maywalk
|
||||
&& vr1.vuse)
|
||||
|
@ -1246,6 +1319,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
|
|||
{
|
||||
VEC (vn_reference_op_s, heap) *operands;
|
||||
struct vn_reference_s vr1;
|
||||
tree cst;
|
||||
|
||||
if (vnresult)
|
||||
*vnresult = NULL;
|
||||
|
@ -1255,6 +1329,8 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
|
|||
vr1.type = TREE_TYPE (op);
|
||||
vr1.set = get_alias_set (op);
|
||||
vr1.hashcode = vn_reference_compute_hash (&vr1);
|
||||
if ((cst = fully_constant_vn_reference_p (&vr1)))
|
||||
return cst;
|
||||
|
||||
if (maywalk
|
||||
&& vr1.vuse)
|
||||
|
|
|
@ -204,4 +204,5 @@ unsigned int get_next_value_id (void);
|
|||
unsigned int get_constant_value_id (tree);
|
||||
unsigned int get_or_alloc_constant_value_id (tree);
|
||||
bool value_id_constant_p (unsigned int);
|
||||
tree fully_constant_vn_reference_p (vn_reference_t);
|
||||
#endif /* TREE_SSA_SCCVN_H */
|
||||
|
|
|
@ -4998,23 +4998,46 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one)
|
|||
{
|
||||
value_range_t* vr = NULL;
|
||||
tree low_sub, up_sub;
|
||||
tree low_bound, up_bound = array_ref_up_bound (ref);
|
||||
tree low_bound, up_bound, up_bound_p1;
|
||||
tree base;
|
||||
|
||||
low_sub = up_sub = TREE_OPERAND (ref, 1);
|
||||
|
||||
if (!up_bound || TREE_NO_WARNING (ref)
|
||||
|| TREE_CODE (up_bound) != INTEGER_CST
|
||||
/* Can not check flexible arrays. */
|
||||
|| (TYPE_SIZE (TREE_TYPE (ref)) == NULL_TREE
|
||||
&& TYPE_DOMAIN (TREE_TYPE (ref)) != NULL_TREE
|
||||
&& TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (ref))) == NULL_TREE)
|
||||
/* Accesses after the end of arrays of size 0 (gcc
|
||||
extension) and 1 are likely intentional ("struct
|
||||
hack"). */
|
||||
|| compare_tree_int (up_bound, 1) <= 0)
|
||||
if (TREE_NO_WARNING (ref))
|
||||
return;
|
||||
|
||||
low_sub = up_sub = TREE_OPERAND (ref, 1);
|
||||
up_bound = array_ref_up_bound (ref);
|
||||
|
||||
/* Can not check flexible arrays. */
|
||||
if (!up_bound
|
||||
|| TREE_CODE (up_bound) != INTEGER_CST)
|
||||
return;
|
||||
|
||||
/* Accesses to trailing arrays via pointers may access storage
|
||||
beyond the types array bounds. */
|
||||
base = get_base_address (ref);
|
||||
if (base
|
||||
&& INDIRECT_REF_P (base))
|
||||
{
|
||||
tree cref, next = NULL_TREE;
|
||||
|
||||
if (TREE_CODE (TREE_OPERAND (ref, 0)) != COMPONENT_REF)
|
||||
return;
|
||||
|
||||
cref = TREE_OPERAND (ref, 0);
|
||||
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
|
||||
for (next = TREE_CHAIN (TREE_OPERAND (cref, 1));
|
||||
next && TREE_CODE (next) != FIELD_DECL;
|
||||
next = TREE_CHAIN (next))
|
||||
;
|
||||
|
||||
/* If this is the last field in a struct type or a field in a
|
||||
union type do not warn. */
|
||||
if (!next)
|
||||
return;
|
||||
}
|
||||
|
||||
low_bound = array_ref_low_bound (ref);
|
||||
up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound, integer_one_node, 0);
|
||||
|
||||
if (TREE_CODE (low_sub) == SSA_NAME)
|
||||
{
|
||||
|
@ -5039,14 +5062,11 @@ check_array_ref (location_t location, tree ref, bool ignore_off_by_one)
|
|||
}
|
||||
}
|
||||
else if (TREE_CODE (up_sub) == INTEGER_CST
|
||||
&& tree_int_cst_lt (up_bound, up_sub)
|
||||
&& !tree_int_cst_equal (up_bound, up_sub)
|
||||
&& (!ignore_off_by_one
|
||||
|| !tree_int_cst_equal (int_const_binop (PLUS_EXPR,
|
||||
up_bound,
|
||||
integer_one_node,
|
||||
0),
|
||||
up_sub)))
|
||||
&& (ignore_off_by_one
|
||||
? (tree_int_cst_lt (up_bound, up_sub)
|
||||
&& !tree_int_cst_equal (up_bound_p1, up_sub))
|
||||
: (tree_int_cst_lt (up_bound, up_sub)
|
||||
|| tree_int_cst_equal (up_bound_p1, up_sub))))
|
||||
{
|
||||
warning_at (location, OPT_Warray_bounds,
|
||||
"array subscript is above array bounds");
|
||||
|
|
Loading…
Add table
Reference in a new issue