[PATCH][4.6] Improve array bound warnings, fix PR43270
Richard Guenther
rguenther@suse.de
Tue Mar 9 14:00:00 GMT 2010
This fixes flexible array member detection in VRP (well, somewhat).
Mainly it avoids it for non-indirect reference bases and fixes
the detection for zero-sized arrays.
That causes some fallout during bootstrap - we warn for dead code
as in the added gcc.dg/Warray-bounds-7.c, because VN doesn't properly
handle reads from constant strings. I fixed that.
Then we come along expmed.c:init_expmed ... ugh. Completely bogus stuff.
So I added -Wno-error.
Bootstrapped and tested on x86_64-unknown-linux-gnu.
Queueing for 4.6, the VN bits need to be completed and
expmed.c:init_expmed needs a rewrite ...
Richard.
2010-03-09 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 (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.
* Makefile.in (expmed.o-warn): Add -Wno-error.
* g++.dg/warn/Warray-bounds-4.C: New testcase.
* gcc.dg/Warray-bounds-7.c: Likewise.
Index: gcc/tree-vrp.c
===================================================================
*** gcc/tree-vrp.c.orig 2010-03-08 15:10:59.000000000 +0100
--- gcc/tree-vrp.c 2010-03-08 16:11:47.000000000 +0100
*************** check_array_ref (location_t location, tr
*** 4981,5003 ****
{
value_range_t* vr = NULL;
tree low_sub, up_sub;
! tree low_bound, up_bound = array_ref_up_bound (ref);
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)
return;
low_bound = array_ref_low_bound (ref);
if (TREE_CODE (low_sub) == SSA_NAME)
{
--- 4981,5026 ----
{
value_range_t* vr = NULL;
tree low_sub, up_sub;
! tree low_bound, up_bound, up_bound_p1;
! tree base;
!
! 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)
{
*************** check_array_ref (location_t location, tr
*** 5022,5035 ****
}
}
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)))
{
warning_at (location, OPT_Warray_bounds,
"array subscript is above array bounds");
--- 5045,5055 ----
}
}
else if (TREE_CODE (up_sub) == INTEGER_CST
! && (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");
Index: gcc/testsuite/g++.dg/warn/Warray-bounds-4.C
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/g++.dg/warn/Warray-bounds-4.C 2010-03-08 16:12:00.000000000 +0100
***************
*** 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;
+ }
Index: gcc/tree-ssa-sccvn.h
===================================================================
*** gcc/tree-ssa-sccvn.h.orig 2010-03-08 15:10:59.000000000 +0100
--- gcc/tree-ssa-sccvn.h 2010-03-08 15:11:08.000000000 +0100
*************** unsigned int get_next_value_id (void);
*** 204,207 ****
--- 204,208 ----
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 */
Index: gcc/tree-ssa-pre.c
===================================================================
*** gcc/tree-ssa-pre.c.orig 2010-03-08 15:10:59.000000000 +0100
--- gcc/tree-ssa-pre.c 2010-03-08 15:11:08.000000000 +0100
*************** do_unary:
*** 1231,1279 ****
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;
! }
default:
return e;
}
--- 1231,1241 ----
case REFERENCE:
{
vn_reference_t ref = PRE_EXPR_REFERENCE (e);
! tree folded;
! if ((folded = fully_constant_vn_reference_p (ref)))
! return get_or_alloc_expr_for_constant (folded);
! return e;
! }
default:
return e;
}
Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c.orig 2010-03-08 15:10:59.000000000 +0100
--- gcc/tree-ssa-sccvn.c 2010-03-08 16:08:09.000000000 +0100
*************** vn_reference_lookup_pieces (tree vuse, a
*** 1234,1239 ****
--- 1234,1305 ----
return NULL_TREE;
}
+ 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;
+ }
+
/* Lookup OP in the current hash table, and return the resulting value
number if it exists in the hash table. Return NULL_TREE if it does
not exist in the hash table or if the result field of the structure
*************** vn_reference_lookup (tree op, tree vuse,
*** 1246,1251 ****
--- 1312,1318 ----
{
VEC (vn_reference_op_s, heap) *operands;
struct vn_reference_s vr1;
+ tree cst;
if (vnresult)
*vnresult = NULL;
*************** vn_reference_lookup (tree op, tree vuse,
*** 1255,1260 ****
--- 1322,1329 ----
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)
Index: gcc/testsuite/gcc.dg/Warray-bounds-7.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/Warray-bounds-7.c 2010-03-08 15:11:08.000000000 +0100
***************
*** 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;
+ }
Index: gcc/Makefile.in
===================================================================
*** gcc/Makefile.in.orig 2010-03-08 15:10:59.000000000 +0100
--- gcc/Makefile.in 2010-03-08 15:11:08.000000000 +0100
*************** GCC_WARN_CXXFLAGS = $(LOOSE_WARN) $($(@D
*** 183,188 ****
--- 183,189 ----
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
More information about the Gcc-patches
mailing list