aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2010-04-07 12:31:32 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2010-04-07 12:31:32 +0000
commit12bd5a1e9f42026f7ead1bad788f9cade67f88b7 (patch)
tree92208bc8d4ba4a670add9a969acc3e87e362914a
parenta775239672d98c299f0bdde4e7465529388af8eb (diff)
downloadgcc-12bd5a1e9f42026f7ead1bad788f9cade67f88b7.zip
gcc-12bd5a1e9f42026f7ead1bad788f9cade67f88b7.tar.gz
gcc-12bd5a1e9f42026f7ead1bad788f9cade67f88b7.tar.bz2
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
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/Makefile.in1
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-4.C37
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-7.c13
-rw-r--r--gcc/tree-ssa-pre.c50
-rw-r--r--gcc/tree-ssa-sccvn.c78
-rw-r--r--gcc/tree-ssa-sccvn.h1
-rw-r--r--gcc/tree-vrp.c58
9 files changed, 194 insertions, 64 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3121c99..ca2b7f6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index a1ad1d4a..20529d0 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5f8db2c..a2faaf5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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...
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-4.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-4.C
new file mode 100644
index 0000000..319038a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-4.C
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-7.c b/gcc/testsuite/gcc.dg/Warray-bounds-7.c
new file mode 100644
index 0000000..fdd9578
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-7.c
@@ -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;
+}
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 24172f7..2331e7b 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -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))
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 5282978..f965c51 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -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)
diff --git a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
index c60c28a..8f93b0b 100644
--- a/gcc/tree-ssa-sccvn.h
+++ b/gcc/tree-ssa-sccvn.h
@@ -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 */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index c84004e..3b22948 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -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;
+
+ if (TREE_NO_WARNING (ref))
+ return;
low_sub = up_sub = TREE_OPERAND (ref, 1);
+ up_bound = array_ref_up_bound (ref);
- 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)
+ /* 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");