PR tree-optimization/91457 - inconsistent warning for writing past the end of an array member

gcc/ChangeLog:

	PR tree-optimization/91457
	* builtins.c (component_size): New function.
	(compute_objsize): Add argument. Handle ARRAY_REF and COMPONENT_REF.
	* builtins.h (compute_objsize): Add argument.
	* tree-ssa-strlen.c (handle_store): Handle no-warning bit.
	* tree-vrp.c (vrp_prop::check_array_ref): Return warning result.
	(vrp_prop::check_mem_ref): Same.
	(vrp_prop::search_for_addr_array): Set no-warning bit.
	(check_array_bounds): Same.

gcc/testsuite/ChangeLog:

	PR tree-optimization/91457
	* c-c++-common/Wstringop-overflow-2.c: New test.
	* g++.dg/warn/Warray-bounds-8.C: New test.
	* g++.dg/warn/Wstringop-overflow-3.C: New test.
	* gcc.dg/Wstringop-overflow-15.c: New test.

From-SVN: r274997
This commit is contained in:
Martin Sebor 2019-08-28 16:43:56 +00:00 committed by Martin Sebor
parent e2eee23981
commit 464969eb9b
10 changed files with 1364 additions and 44 deletions

View File

@ -1,3 +1,15 @@
2019-08-28 Martin Sebor <msebor@redhat.com>
PR tree-optimization/91457
* builtins.c (component_size): New function.
(compute_objsize): Add argument. Handle ARRAY_REF and COMPONENT_REF.
* builtins.h (compute_objsize): Add argument.
* tree-ssa-strlen.c (handle_store): Handle no-warning bit.
* tree-vrp.c (vrp_prop::check_array_ref): Return warning result.
(vrp_prop::check_mem_ref): Same.
(vrp_prop::search_for_addr_array): Set no-warning bit.
(check_array_bounds): Same.
2019-08-28 Martin Sebor <msebor@redhat.com>
PR driver/80545

View File

@ -72,6 +72,7 @@ along with GCC; see the file COPYING3. If not see
#include "file-prefix-map.h" /* remap_macro_filename() */
#include "gomp-constants.h"
#include "omp-general.h"
#include "tree-dfa.h"
struct target_builtins default_target_builtins;
#if SWITCHABLE_TARGET
@ -3561,6 +3562,54 @@ check_access (tree exp, tree, tree, tree dstwrite,
return true;
}
/* Determines the size of the member referenced by the COMPONENT_REF
REF, using its initializer expression if necessary in order to
determine the size of an initialized flexible array member.
Returns the size (which might be zero for an object with
an uninitialized flexible array member) or null if the size
cannot be determined. */
static tree
component_size (tree ref)
{
gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
tree member = TREE_OPERAND (ref, 1);
/* If the member is not last or has a size greater than one, return
it. Otherwise it's either a flexible array member or a zero-length
array member, or an array of length one treated as such. */
tree size = DECL_SIZE_UNIT (member);
if (size
&& (!array_at_struct_end_p (ref)
|| (!integer_zerop (size)
&& !integer_onep (size))))
return size;
/* If the reference is to a declared object and the member a true
flexible array, try to determine its size from its initializer. */
poly_int64 off = 0;
tree base = get_addr_base_and_unit_offset (ref, &off);
if (!base || !VAR_P (base))
return NULL_TREE;
/* The size of any member of a declared object other than a flexible
array member is that obtained above. */
if (size)
return size;
if (tree init = DECL_INITIAL (base))
if (TREE_CODE (init) == CONSTRUCTOR)
{
off <<= LOG2_BITS_PER_UNIT;
init = fold_ctor_reference (NULL_TREE, init, off, 0, base);
if (init)
return TYPE_SIZE_UNIT (TREE_TYPE (init));
}
return DECL_EXTERNAL (base) ? NULL_TREE : integer_zero_node;
}
/* Helper to compute the size of the object referenced by the DEST
expression which must have pointer type, using Object Size type
OSTYPE (only the least significant 2 bits are used). Return
@ -3568,12 +3617,18 @@ check_access (tree exp, tree, tree, tree dstwrite,
the size cannot be determined. When the referenced object involves
a non-constant offset in some range the returned value represents
the largest size given the smallest non-negative offset in the
range. The function is intended for diagnostics and should not
be used to influence code generation or optimization. */
range. If nonnull, set *PDECL to the decl of the referenced
subobject if it can be determined, or to null otherwise.
The function is intended for diagnostics and should not be used
to influence code generation or optimization. */
tree
compute_objsize (tree dest, int ostype)
compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */)
{
tree dummy = NULL_TREE;
if (!pdecl)
pdecl = &dummy;
unsigned HOST_WIDE_INT size;
/* Only the two least significant bits are meaningful. */
@ -3600,7 +3655,7 @@ compute_objsize (tree dest, int ostype)
tree off = gimple_assign_rhs2 (stmt);
if (TREE_CODE (off) == INTEGER_CST)
{
if (tree size = compute_objsize (dest, ostype))
if (tree size = compute_objsize (dest, ostype, pdecl))
{
wide_int wioff = wi::to_wide (off);
wide_int wisiz = wi::to_wide (size);
@ -3625,7 +3680,7 @@ compute_objsize (tree dest, int ostype)
if (rng == VR_RANGE)
{
if (tree size = compute_objsize (dest, ostype))
if (tree size = compute_objsize (dest, ostype, pdecl))
{
wide_int wisiz = wi::to_wide (size);
@ -3653,12 +3708,31 @@ compute_objsize (tree dest, int ostype)
if (!ostype)
return NULL_TREE;
if (TREE_CODE (dest) == MEM_REF)
if (TREE_CODE (dest) == ARRAY_REF
|| TREE_CODE (dest) == MEM_REF)
{
tree ref = TREE_OPERAND (dest, 0);
tree off = TREE_OPERAND (dest, 1);
if (tree size = compute_objsize (ref, ostype))
if (tree size = compute_objsize (ref, ostype, pdecl))
{
/* If the declaration of the destination object is known
to have zero size, return zero. */
if (integer_zerop (size))
return integer_zero_node;
if (TREE_CODE (off) != INTEGER_CST
|| TREE_CODE (size) != INTEGER_CST)
return NULL_TREE;
if (TREE_CODE (dest) == ARRAY_REF)
{
tree eltype = TREE_TYPE (dest);
if (tree tpsize = TYPE_SIZE_UNIT (eltype))
off = fold_build2 (MULT_EXPR, size_type_node, off, tpsize);
else
return NULL_TREE;
}
if (tree_int_cst_lt (off, size))
return fold_build2 (MINUS_EXPR, size_type_node, size, off);
return integer_zero_node;
@ -3667,9 +3741,22 @@ compute_objsize (tree dest, int ostype)
return NULL_TREE;
}
if (TREE_CODE (dest) == COMPONENT_REF)
{
*pdecl = TREE_OPERAND (dest, 1);
return component_size (dest);
}
if (TREE_CODE (dest) != ADDR_EXPR)
return NULL_TREE;
tree ref = TREE_OPERAND (dest, 0);
if (DECL_P (ref))
{
*pdecl = ref;
return DECL_SIZE_UNIT (ref);
}
tree type = TREE_TYPE (dest);
if (TREE_CODE (type) == POINTER_TYPE)
type = TREE_TYPE (type);
@ -3677,14 +3764,10 @@ compute_objsize (tree dest, int ostype)
type = TYPE_MAIN_VARIANT (type);
if (TREE_CODE (type) == ARRAY_TYPE
&& !array_at_struct_end_p (TREE_OPERAND (dest, 0)))
&& !array_at_struct_end_p (ref))
{
/* Return the constant size unless it's zero (that's a zero-length
array likely at the end of a struct). */
tree size = TYPE_SIZE_UNIT (type);
if (size && TREE_CODE (size) == INTEGER_CST
&& !integer_zerop (size))
return size;
if (tree size = TYPE_SIZE_UNIT (type))
return TREE_CODE (size) == INTEGER_CST ? size : NULL_TREE;
}
return NULL_TREE;

View File

@ -134,7 +134,7 @@ extern tree fold_call_stmt (gcall *, bool);
extern void set_builtin_user_assembler_name (tree decl, const char *asmspec);
extern bool is_simple_builtin (tree);
extern bool is_inexpensive_builtin (tree);
extern tree compute_objsize (tree, int);
extern tree compute_objsize (tree, int, tree * = NULL);
extern bool readonly_data_expr (tree exp);
extern bool init_target_chars (void);

View File

@ -1,3 +1,11 @@
2019-08-28 Martin Sebor <msebor@redhat.com>
PR tree-optimization/91457
* c-c++-common/Wstringop-overflow-2.c: New test.
* g++.dg/warn/Warray-bounds-8.C: New test.
* g++.dg/warn/Wstringop-overflow-3.C: New test.
* gcc.dg/Wstringop-overflow-15.c: New test.
2019-08-16 Martin Liska <mliska@suse.cz>
PR c++/90613

View File

@ -0,0 +1,348 @@
/* PR middle-end/91458 - inconsistent warning for writing past the end
of an array member
{ dg-do compile }
{ dg-options "-O2 -Wall -Wno-array-bounds" } */
void sink (void*);
// Exercise flexible array members.
struct Ax
{
char n;
char a[]; // { dg-message "destination object declared here" }
};
// Verify warning for a definition with no initializer.
struct Ax ax_;
void gax_ (void)
{
ax_.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax_.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
ax_.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the flexible array member.
struct Ax ax0 = { 0 };
void gax0 (void)
{
ax0.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax0.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
ax0.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that
// initializes the flexible array member to empty.
struct Ax ax0_ = { 0, { } };
void gax0_ (void)
{
ax0_.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax0_.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
ax0_.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for out-of-bounds accesses to a definition with
// an initializer.
struct Ax ax1 = { 1, { 0 } };
void gax1 (void)
{
ax1.a[0] = 0;
ax1.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
ax1.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
}
struct Ax ax2 = { 2, { 1, 0 } };
void gax2 (void)
{
ax2.a[0] = 0;
ax2.a[1] = 1;
ax2.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify no warning for an unknown struct object.
void gaxp (struct Ax *p)
{
p->a[0] = 0;
p->a[3] = 3;
p->a[9] = 9;
}
// Verify no warning for an extern struct object whose array may be
// initialized to any number of elements.
extern struct Ax axx;
void gaxx (void)
{
axx.a[0] = 0;
axx.a[3] = 3;
axx.a[9] = 9;
}
// Exercise zero-length array members.
struct A0
{
char n;
char a[0]; // { dg-message "destination object declared here" }
};
// Verify warning for a definition with no initializer.
struct A0 a0_;
void ga0_ (void)
{
a0_.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a0_.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a0_.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the flexible array member.
struct A0 a00 = { 0 };
void ga00 (void)
{
a00.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a00.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a00.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that
// initializes the flexible array member to empty.
struct A0 a00_ = { 0, { } };
void ga00_ (void)
{
a00_.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a00_.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a00_.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
}
// The following are rejected with
// error: too many initializers for 'char [0]'
// A0 a01 = { 1, { 0 } };
// A0 a02 = { 2, { 1, 0 } };
// Verify no warning for an unknown struct object.
void ga0p (struct A0 *p)
{
p->a[0] = 0;
p->a[3] = 3;
p->a[9] = 9;
}
// Verify warning for an extern struct object which (unlike a true
// flexible array member) may not be initialized.
extern struct A0 a0x;
void ga0x (void)
{
a0x.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a0x.a[3] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a0x.a[9] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Exercise trailing one-element array members.
struct A1
{
char n;
char a[1]; // { dg-message "destination object declared here" }
};
// Verify warning for a definition with no initializer.
struct A1 a1_;
void ga1_ (void)
{
a1_.a[0] = 0;
a1_.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a1_.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
struct A1 a;
a.a[0] = 0;
a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
sink (&a);
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the one-element array member.
struct A1 a1__ = { 0 };
void ga1__ (void)
{
a1__.a[0] = 0;
a1__.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a1__.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
struct A1 a = { 1 };
a.a[0] = 0;
a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
sink (&a);
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member to empty.
struct A1 a1_0 = { 0, { } };
void ga1_0_ (void)
{
a1_0.a[0] = 0;
a1_0.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a1_0.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
struct A1 a = { 1, { } };
a.a[0] = 0;
a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
sink (&a);
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member.
struct A1 a1_1 = { 0, { 1 } };
void ga1_1 (void)
{
a1_1.a[0] = 0;
a1_1.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a1_1.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
struct A1 a = { 0, { 1 } };
a.a[0] = 0;
a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
sink (&a);
}
// Verify no warning for an unknown struct object.
void ga1p (struct A1 *p)
{
p->a[0] = 0;
p->a[3] = 3;
p->a[9] = 9;
}
// Verify warning for an extern struct object. Similar to the zero-length
// array case, a one-element trailing array can be initialized to at most
// a single element.
extern struct A1 a1x;
void ga1x (void)
{
a1x.a[0] = 0;
a1x.a[3] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
a1x.a[9] = 9; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Exercise interior one-element array members (verify they're not
// treated as trailing.
struct A1i
{
char n;
char a[1]; // { dg-message "destination object declared here" }
char x;
};
// Verify warning for a definition with no initializer.
struct A1i a1i_;
void ga1i_ (void)
{
a1i_.a[0] = 0;
a1i_.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a1i_.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
struct A1i a;
a.a[0] = 1;
a.a[1] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
a.a[2] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
sink (&a);
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the one-element array member.
struct A1i a1i__ = { 0 };
void ga1i__ (void)
{
a1i__.a[0] = 0;
a1i__.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a1i__.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
struct A1i a = { 0 };
a.a[0] = 0;
a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
sink (&a);
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member to empty.
struct A1 a1i_0 = { 0, { } };
void ga1i_0_ (void)
{
a1i_0.a[0] = 0;
a1i_0.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a1i_0.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
struct A1 a = { 0, { } };
a.a[0] = 0;
a.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
sink (&a);
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member.
struct A1 a1i_1 = { 0, { 1 } };
void ga1i_1 (void)
{
a1i_1.a[0] = 0;
a1i_1.a[1] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
a1i_1.a[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
struct A1 a = { 0, { 1 } };
a.a[0] = 1;
a.a[1] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
a.a[2] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
sink (&a);
}
// Verify no warning for an unknown struct object.
void ga1ip (struct A1i *p)
{
p->a[0] = 0;
p->a[3] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
p->a[9] = 9; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify no warning for an extern struct object.
extern struct A1i a1ix;
void ga1ix (void)
{
a1ix.a[0] = 0;
a1ix.a[3] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
a1ix.a[9] = 9; // { dg-warning "\\\[-Wstringop-overflow" }
}

View File

@ -0,0 +1,388 @@
/* PR middle-end/91458 - inconsistent warning for writing past the end
of an array member
See Wstringop-overflow-3.C for the same test that exercises the other
warning.
{ dg-do compile }
{ dg-options "-O2 -Wall -Wno-stringop-overflow" } */
void sink (void*);
// Exercise flexible array members.
struct Ax
{
char n;
char a[]; // { dg-message "while referencing .Ax::a." "pr91463" { xfail *-*-* } }
};
// Verify warning for a definition with no initializer.
Ax ax_;
void gax_ ()
{
ax_.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
ax_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
ax_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the flexible array member.
Ax ax0 = { 0 };
void gax0 ()
{
ax0.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
ax0.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
ax0.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
}
// Verify warning for access to a definition with an initializer that
// initializes the flexible array member to empty.
Ax ax0_ = { 0, { } };
void gax0_ ()
{
ax0_.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
ax0_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
ax0_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
}
// Verify warning for out-of-bounds accesses to a definition with
// an initializer.
Ax ax1 = { 1, { 0 } };
void gax1 ()
{
ax1.a[0] = 0;
ax1.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
ax1.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
}
Ax ax2 = { 2, { 1, 0 } };
void gax2 ()
{
ax2.a[0] = 0;
ax2.a[1] = 0;
ax2.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
}
// Verify no warning for an unknown struct object.
void gaxp (Ax *p)
{
p->a[0] = 0;
p->a[3] = 0;
p->a[9] = 0;
}
// Verify no warning for an extern struct object whose array may be
// initialized to any number of elements.
extern Ax axx;
void gaxx ()
{
axx.a[0] = 0;
axx.a[3] = 0;
axx.a[9] = 0;
}
// Exercise zero-length array members.
struct A0
{
char n;
char a[0]; // { dg-message "while referencing .A0::a." }
};
// Verify warning for a definition with no initializer.
A0 a0_;
void ga0_ ()
{
a0_.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
a0_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a0_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the flexible array member.
A0 a00 = { 0 };
void ga00 ()
{
a00.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
a00.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a00.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify warning for access to a definition with an initializer that
// initializes the flexible array member to empty.
A0 a00_ = { 0, { } };
void ga00_ ()
{
a00_.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
a00_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a00_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// The following are rejected with
// error: too many initializers for 'char [0]'
// A0 a01 = { 1, { 0 } };
// A0 a02 = { 2, { 1, 0 } };
// Verify no warning for an unknown struct object.
void ga0p (A0 *p)
{
p->a[0] = 0;
p->a[3] = 0;
p->a[9] = 0;
}
// Verify warning for an extern struct object which (unlike a true
// flexible array member) may not be initialized.
extern A0 a0x;
void ga0x ()
{
a0x.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
a0x.a[3] = 0; // { dg-warning "\\\[-Warray-bounds" }
a0x.a[9] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Exercise trailing one-element array members.
struct A1
{
char n;
char a[1]; // { dg-message "while referencing .A1::a." }
};
// Verify warning for a definition with no initializer.
A1 a1_;
void ga1_ ()
{
a1_.a[0] = 0;
a1_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the one-element array member.
A1 a1__ = { 0 };
void ga1__ ()
{
a1__.a[0] = 0;
a1__.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1__.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member to empty.
A1 a1_0 = { 0, { } };
void ga1_0_ ()
{
a1_0.a[0] = 0;
a1_0.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1_0.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member.
A1 a1_1 = { 0, { 1 } };
void ga1_1 ()
{
a1_1.a[0] = 0;
a1_1.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1_1.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify no warning for an unknown struct object.
void ga1p (A1 *p)
{
p->a[0] = 0;
p->a[3] = 0;
p->a[9] = 0;
}
// Verify warning for an extern struct object. Similar to the zero-length
// array case, a one-element trailing array can be initialized to at most
// a single element.
extern A1 a1x;
void ga1x ()
{
a1x.a[0] = 0;
a1x.a[3] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1x.a[9] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Exercise interior one-element array members (verify they're not
// treated as trailing.
struct A1i
{
char n;
char a[1]; // { dg-message "while referencing .A1i::a." }
char x;
};
// Verify warning for a definition with no initializer.
A1i a1i_;
void ga1i_ ()
{
a1i_.a[0] = 0;
a1i_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1i_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the one-element array member.
A1i a1i__ = { 0 };
void ga1i__ ()
{
a1i__.a[0] = 0;
a1i__.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1i__.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member to empty.
A1 a1i_0 = { 0, { } };
void ga1i_0_ ()
{
a1i_0.a[0] = 0;
a1i_0.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1i_0.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member.
A1 a1i_1 = { 0, { 1 } };
void ga1i_1 ()
{
a1i_1.a[0] = 0;
a1i_1.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1i_1.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify no warning for an unknown struct object.
void ga1ip (A1i *p)
{
p->a[0] = 0;
p->a[3] = 0; // { dg-warning "\\\[-Warray-bounds" }
p->a[9] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify no warning for an extern struct object.
extern A1i a1ix;
void ga1ix ()
{
a1ix.a[0] = 0;
a1ix.a[3] = 0; // { dg-warning "\\\[-Warray-bounds" }
a1ix.a[9] = 0; // { dg-warning "\\\[-Warray-bounds" }
}
// Verify non-POD classes with flexible array members.
struct Bx
{
char n;
char a[]; // { dg-message "while referencing .Bx::a." "pr91463" { xfail *-*-* } }
// Verify the warning for a constant.
Bx () { a[0] = 0; } // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
// And also for a non-constant. Regardless of the subscript, the array
// of the object in function gxi() below has a zero size.
Bx (int i) { a[i] = 0; } // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
};
void gbx (void)
{
struct Bx bx;
sink (&bx);
}
void gbxi (int i)
{
struct Bx bxi (i);
sink (&bxi);
}
struct B0
{
char n;
char a[0]; // { dg-message "while referencing .B0::a." }
B0 () { a[0] = 0; } // { dg-warning "\\\[-Warray-bounds" }
};
void gb0 (void)
{
struct B0 b0;
sink (&b0);
}
struct B1
{
char n;
char a[1]; // { dg-message "while referencing .B1::a." }
B1 () { a[1] = 0; } // { dg-warning "\\\[-Warray-bounds" }
};
void gb1 (void)
{
struct B1 b1;
sink (&b1);
}
struct B123
{
char a[123]; // { dg-message "while referencing .B123::a." }
B123 () { a[123] = 0; } // { dg-warning "\\\[-Warray-bounds" }
};
void gb123 (void)
{
struct B123 b123;
sink (&b123);
}
struct B234
{
char a[234]; // { dg-message "while referencing .B234::a." }
B234 (int i) { a[i] = 0; } // { dg-warning "\\\[-Warray-bounds" }
};
void g234 (void)
{
struct B234 b234 (234);
sink (&b234);
}

View File

@ -0,0 +1,386 @@
/* PR middle-end/91458 - inconsistent warning for writing past the end
of an array member
{ dg-do compile }
{ dg-options "-O2 -Wall -Wno-array-bounds" } */
void sink (void*);
// Exercise flexible array members.
struct Ax
{
char n;
char a[]; // { dg-message "destination object declared here" }
};
// Verify warning for a definition with no initializer.
Ax ax_;
void gax_ ()
{
ax_.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax_.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax_.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the flexible array member.
Ax ax0 = { 0 };
void gax0 ()
{
ax0.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax0.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax0.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that
// initializes the flexible array member to empty.
Ax ax0_ = { 0, { } };
void gax0_ ()
{
ax0_.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax0_.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax0_.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for out-of-bounds accesses to a definition with
// an initializer.
Ax ax1 = { 1, { 0 } };
void gax1 ()
{
ax1.a[0] = 0;
ax1.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
ax1.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
Ax ax2 = { 2, { 1, 0 } };
void gax2 ()
{
ax2.a[0] = 0;
ax2.a[1] = 0;
ax2.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify no warning for an unknown struct object.
void gaxp (Ax *p)
{
p->a[0] = 0;
p->a[3] = 0;
p->a[9] = 0;
}
// Verify no warning for an extern struct object whose array may be
// initialized to any number of elements.
extern Ax axx;
void gaxx ()
{
axx.a[0] = 0;
axx.a[3] = 0;
axx.a[9] = 0;
}
// Exercise zero-length array members.
struct A0
{
char n;
char a[0]; // { dg-message "destination object declared here" }
};
// Verify warning for a definition with no initializer.
A0 a0_;
void ga0_ ()
{
a0_.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a0_.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a0_.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the flexible array member.
A0 a00 = { 0 };
void ga00 ()
{
a00.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a00.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a00.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that
// initializes the flexible array member to empty.
A0 a00_ = { 0, { } };
void ga00_ ()
{
a00_.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a00_.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a00_.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// The following are rejected with
// error: too many initializers for 'char [0]'
// A0 a01 = { 1, { 0 } };
// A0 a02 = { 2, { 1, 0 } };
// Verify no warning for an unknown struct object.
void ga0p (A0 *p)
{
p->a[0] = 0;
p->a[3] = 0;
p->a[9] = 0;
}
// Verify warning for an extern struct object which (unlike a true
// flexible array member) may not be initialized.
extern A0 a0x;
void ga0x ()
{
a0x.a[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a0x.a[3] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a0x.a[9] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Exercise trailing one-element array members.
struct A1
{
char n;
char a[1]; // { dg-message "destination object declared here" }
};
// Verify warning for a definition with no initializer.
A1 a1_;
void ga1_ ()
{
a1_.a[0] = 0;
a1_.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1_.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the one-element array member.
A1 a1__ = { 0 };
void ga1__ ()
{
a1__.a[0] = 0;
a1__.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1__.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member to empty.
A1 a1_0 = { 0, { } };
void ga1_0_ ()
{
a1_0.a[0] = 0;
a1_0.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1_0.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member.
A1 a1_1 = { 0, { 1 } };
void ga1_1 ()
{
a1_1.a[0] = 0;
a1_1.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1_1.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify no warning for an unknown struct object.
void ga1p (A1 *p)
{
p->a[0] = 0;
p->a[3] = 0;
p->a[9] = 0;
}
// Verify warning for an extern struct object. Similar to the zero-length
// array case, a one-element trailing array can be initialized to at most
// a single element.
extern A1 a1x;
void ga1x ()
{
a1x.a[0] = 0;
a1x.a[3] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1x.a[9] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Exercise interior one-element array members (verify they're not
// treated as trailing.
struct A1i
{
char n;
char a[1]; // { dg-message "destination object declared here" }
char x;
};
// Verify warning for a definition with no initializer.
A1i a1i_;
void ga1i_ ()
{
a1i_.a[0] = 0;
a1i_.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1i_.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that doesn't
// initialize the one-element array member.
A1i a1i__ = { 0 };
void ga1i__ ()
{
a1i__.a[0] = 0;
a1i__.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1i__.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member to empty.
A1 a1i_0 = { 0, { } };
void ga1i_0_ ()
{
a1i_0.a[0] = 0;
a1i_0.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1i_0.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify warning for access to a definition with an initializer that
// initializes the one-element array member.
A1 a1i_1 = { 0, { 1 } };
void ga1i_1 ()
{
a1i_1.a[0] = 0;
a1i_1.a[1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1i_1.a[2] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify no warning for an unknown struct object.
void ga1ip (A1i *p)
{
p->a[0] = 0;
p->a[3] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
p->a[9] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify no warning for an extern struct object.
extern A1i a1ix;
void ga1ix ()
{
a1ix.a[0] = 0;
a1ix.a[3] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
a1ix.a[9] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
}
// Verify non-POD classes with flexible array members.
struct Bx
{
char n;
char a[]; // { dg-message "destination object declared here" }
// Verify the warning for a constant.
Bx () { a[0] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
// And also for a non-constant. Regardless of the subscript, the array
// of the object in function gxi() below has a zero size.
Bx (int i) { a[i] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
};
void gbx (void)
{
struct Bx bx;
sink (&bx);
}
void gbxi (int i)
{
struct Bx bxi (i);
sink (&bxi);
}
struct B0
{
char n;
char a[0]; // { dg-message "destination object declared here" }
B0 () { a[0] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
};
void gb0 (void)
{
struct B0 b0;
sink (&b0);
}
struct B1
{
char n;
char a[1]; // { dg-message "destination object declared here" }
B1 () { a[1] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
};
void gb1 (void)
{
struct B1 b1;
sink (&b1);
}
struct B123
{
char a[123]; // { dg-message "destination object declared here" }
B123 () { a[123] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
};
void gb123 (void)
{
struct B123 b123;
sink (&b123);
}
struct B234
{
char a[234]; // { dg-message "destination object declared here" }
B234 (int i) { a[i] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
};
void g234 (void)
{
struct B234 b234 (234);
sink (&b234);
}

View File

@ -0,0 +1,62 @@
/* PR middle-end/91458 - inconsistent warning for writing past the end
of an array member
Verify that the -Wstringop-overflow detection doesn't cause an ICE
for either kind of VLAs (member and non-member).
Diagnosing the accesses is the subject of pr82608.
{ dg-do compile }
{ dg-options "-O2 -Wall -Wno-array-bounds" } */
void sink (void*);
void vla_unbounded (int n)
{
char a[n];
a[0] = 0;
a[1] = 1;
a[n] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } }
sink (&a);
}
void vla_bounded (int n)
{
if (n > 32)
n = 32;
char a[n];
a[0] = 0;
a[1] = 1;
a[n] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } }
a[69] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } }
sink (&a);
}
void member_vla_unbounded (int n)
{
struct S { char i, a[n]; } s;
s.a[0] = 0;
s.a[1] = 1;
s.a[n] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } }
sink (&s);
}
void member_vla_bounded (int n)
{
if (n > 32)
n = 32;
struct S { char i, a[n]; } s;
s.a[0] = 0;
s.a[1] = 1;
s.a[n] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } }
s.a[69] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } }
sink (&s);
}

View File

@ -4026,16 +4026,30 @@ handle_store (gimple_stmt_iterator *gsi)
rhs_minlen = lenrange[0];
storing_nonzero_p = lenrange[1] > 0;
if (tree dstsize = compute_objsize (lhs, 1))
if (compare_tree_int (dstsize, lenrange[2]) < 0)
{
location_t loc = gimple_nonartificial_location (stmt);
warning_n (loc, OPT_Wstringop_overflow_,
lenrange[2],
"%Gwriting %u byte into a region of size %E",
"%Gwriting %u bytes into a region of size %E",
stmt, lenrange[2], dstsize);
}
/* Avoid issuing multiple warnings for the same LHS or statement.
For example, -Warray-bounds may have already been issued for
an out-of-bounds subscript. */
if (!TREE_NO_WARNING (lhs) && !gimple_no_warning_p (stmt))
{
/* Set to the declaration referenced by LHS (if known). */
tree decl = NULL_TREE;
if (tree dstsize = compute_objsize (lhs, 1, &decl))
if (compare_tree_int (dstsize, lenrange[2]) < 0)
{
location_t loc = gimple_nonartificial_location (stmt);
if (warning_n (loc, OPT_Wstringop_overflow_,
lenrange[2],
"%Gwriting %u byte into a region of size %E",
"%Gwriting %u bytes into a region of size %E",
stmt, lenrange[2], dstsize))
{
if (decl)
inform (DECL_SOURCE_LOCATION (decl),
"destination object declared here");
gimple_set_no_warning (stmt, true);
}
}
}
}
else
{

View File

@ -4388,8 +4388,8 @@ class vrp_prop : public ssa_propagation_engine
void vrp_initialize (void);
void vrp_finalize (bool);
void check_all_array_refs (void);
void check_array_ref (location_t, tree, bool);
void check_mem_ref (location_t, tree, bool);
bool check_array_ref (location_t, tree, bool);
bool check_mem_ref (location_t, tree, bool);
void search_for_addr_array (tree, location_t);
class vr_values vr_values;
@ -4415,9 +4415,10 @@ class vrp_prop : public ssa_propagation_engine
array subscript is a constant, check if it is outside valid
range. If the array subscript is a RANGE, warn if it is
non-overlapping with valid range.
IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. */
IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR.
Returns true if a warning has been issued. */
void
bool
vrp_prop::check_array_ref (location_t location, tree ref,
bool ignore_off_by_one)
{
@ -4426,7 +4427,7 @@ vrp_prop::check_array_ref (location_t location, tree ref,
tree low_bound, up_bound, up_bound_p1;
if (TREE_NO_WARNING (ref))
return;
return false;
low_sub = up_sub = TREE_OPERAND (ref, 1);
up_bound = array_ref_up_bound (ref);
@ -4541,12 +4542,16 @@ vrp_prop::check_array_ref (location_t location, tree ref,
if (warned)
{
ref = TREE_OPERAND (ref, 0);
if (TREE_CODE (ref) == COMPONENT_REF)
ref = TREE_OPERAND (ref, 1);
if (DECL_P (ref))
inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref);
TREE_NO_WARNING (ref) = 1;
}
return warned;
}
/* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds
@ -4556,14 +4561,15 @@ vrp_prop::check_array_ref (location_t location, tree ref,
with valid range.
IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR
(used to allow one-past-the-end indices for code that takes
the address of the just-past-the-end element of an array). */
the address of the just-past-the-end element of an array).
Returns true if a warning has been issued. */
void
bool
vrp_prop::check_mem_ref (location_t location, tree ref,
bool ignore_off_by_one)
{
if (TREE_NO_WARNING (ref))
return;
return false;
tree arg = TREE_OPERAND (ref, 0);
/* The constant and variable offset of the reference. */
@ -4615,7 +4621,7 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
continue;
}
else
return;
return false;
/* VAROFF should always be a SSA_NAME here (and not even
INTEGER_CST) but there's no point in taking chances. */
@ -4677,10 +4683,10 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
arg = TREE_OPERAND (arg, 0);
if (TREE_CODE (arg) != STRING_CST
&& TREE_CODE (arg) != VAR_DECL)
return;
return false;
}
else
return;
return false;
/* The type of the object being referred to. It can be an array,
string literal, or a non-array type when the MEM_REF represents
@ -4695,7 +4701,7 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
|| !COMPLETE_TYPE_P (reftype)
|| TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST
|| RECORD_OR_UNION_TYPE_P (reftype))
return;
return false;
offset_int eltsize;
if (TREE_CODE (reftype) == ARRAY_TYPE)
@ -4797,11 +4803,11 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
if (warned)
TREE_NO_WARNING (ref) = 1;
return;
return warned;
}
if (warn_array_bounds < 2)
return;
return false;
/* At level 2 check also intermediate offsets. */
int i = 0;
@ -4812,8 +4818,13 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
if (warning_at (location, OPT_Warray_bounds,
"intermediate array offset %wi is outside array bounds "
"of %qT", tmpidx, reftype))
TREE_NO_WARNING (ref) = 1;
{
TREE_NO_WARNING (ref) = 1;
return true;
}
}
return false;
}
/* Searches if the expr T, located at LOCATION computes
@ -4825,10 +4836,14 @@ vrp_prop::search_for_addr_array (tree t, location_t location)
/* Check each ARRAY_REF and MEM_REF in the reference chain. */
do
{
bool warned = false;
if (TREE_CODE (t) == ARRAY_REF)
check_array_ref (location, t, true /*ignore_off_by_one*/);
warned = check_array_ref (location, t, true /*ignore_off_by_one*/);
else if (TREE_CODE (t) == MEM_REF)
check_mem_ref (location, t, true /*ignore_off_by_one*/);
warned = check_mem_ref (location, t, true /*ignore_off_by_one*/);
if (warned)
TREE_NO_WARNING (t) = true;
t = TREE_OPERAND (t, 0);
}
@ -4920,16 +4935,20 @@ check_array_bounds (tree *tp, int *walk_subtree, void *data)
*walk_subtree = TRUE;
bool warned = false;
vrp_prop *vrp_prop = (class vrp_prop *)wi->info;
if (TREE_CODE (t) == ARRAY_REF)
vrp_prop->check_array_ref (location, t, false /*ignore_off_by_one*/);
warned = vrp_prop->check_array_ref (location, t, false/*ignore_off_by_one*/);
else if (TREE_CODE (t) == MEM_REF)
vrp_prop->check_mem_ref (location, t, false /*ignore_off_by_one*/);
warned = vrp_prop->check_mem_ref (location, t, false /*ignore_off_by_one*/);
else if (TREE_CODE (t) == ADDR_EXPR)
{
vrp_prop->search_for_addr_array (t, location);
*walk_subtree = FALSE;
}
/* Propagate the no-warning bit to the outer expression. */
if (warned)
TREE_NO_WARNING (t) = true;
return NULL_TREE;
}