PR middle-end/84095 - false-positive -Wrestrict warnings for memcpy within array
gcc/ChangeLog: PR middle-end/84095 * gimple-ssa-warn-restrict.c (builtin_memref::extend_offset_range): New. (builtin_memref::set_base_and_offset): Same. Handle inner references. (builtin_memref::builtin_memref): Factor out parts into set_base_and_offset and call it. gcc/testsuite/ChangeLog: PR middle-end/84095 * c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings. * c-c++-common/Wrestrict.c: Same. * gcc.dg/Wrestrict-6.c: Same. * gcc.dg/Warray-bounds-27.c: New test. * gcc.dg/Wrestrict-8.c: New test. * gcc.dg/Wrestrict-9.c: New test. * gcc.dg/pr84095.c: New test. From-SVN: r257860
This commit is contained in:
parent
75b81dcdad
commit
5e27f0d5d5
10 changed files with 726 additions and 168 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2018-02-20 Martin Sebor <msebor@redhat.com>
|
||||||
|
|
||||||
|
PR middle-end/84095
|
||||||
|
* gimple-ssa-warn-restrict.c (builtin_memref::extend_offset_range): New.
|
||||||
|
(builtin_memref::set_base_and_offset): Same. Handle inner references.
|
||||||
|
(builtin_memref::builtin_memref): Factor out parts into
|
||||||
|
set_base_and_offset and call it.
|
||||||
|
|
||||||
2018-02-20 Richard Sandiford <richard.sandiford@linaro.org>
|
2018-02-20 Richard Sandiford <richard.sandiford@linaro.org>
|
||||||
|
|
||||||
PR middle-end/84406
|
PR middle-end/84406
|
||||||
|
|
|
@ -158,6 +158,14 @@ struct builtin_memref
|
||||||
builtin_memref (tree, tree);
|
builtin_memref (tree, tree);
|
||||||
|
|
||||||
tree offset_out_of_bounds (int, offset_int[2]) const;
|
tree offset_out_of_bounds (int, offset_int[2]) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* Ctor helper to set or extend OFFRANGE based on argument. */
|
||||||
|
void extend_offset_range (tree);
|
||||||
|
|
||||||
|
/* Ctor helper to determine BASE and OFFRANGE from argument. */
|
||||||
|
void set_base_and_offset (tree);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Description of a memory access by a raw memory or string built-in
|
/* Description of a memory access by a raw memory or string built-in
|
||||||
|
@ -235,153 +243,9 @@ builtin_memref::builtin_memref (tree expr, tree size)
|
||||||
|
|
||||||
const offset_int maxobjsize = tree_to_shwi (max_object_size ());
|
const offset_int maxobjsize = tree_to_shwi (max_object_size ());
|
||||||
|
|
||||||
if (TREE_CODE (expr) == SSA_NAME)
|
/* Find the BASE object or pointer referenced by EXPR and set
|
||||||
{
|
the offset range OFFRANGE in the process. */
|
||||||
/* Try to tease the offset out of the pointer. */
|
set_base_and_offset (expr);
|
||||||
gimple *stmt = SSA_NAME_DEF_STMT (expr);
|
|
||||||
if (gimple_assign_single_p (stmt)
|
|
||||||
&& gimple_assign_rhs_code (stmt) == ADDR_EXPR)
|
|
||||||
expr = gimple_assign_rhs1 (stmt);
|
|
||||||
else if (is_gimple_assign (stmt))
|
|
||||||
{
|
|
||||||
tree_code code = gimple_assign_rhs_code (stmt);
|
|
||||||
if (code == NOP_EXPR)
|
|
||||||
{
|
|
||||||
tree rhs = gimple_assign_rhs1 (stmt);
|
|
||||||
if (POINTER_TYPE_P (TREE_TYPE (rhs)))
|
|
||||||
expr = gimple_assign_rhs1 (stmt);
|
|
||||||
}
|
|
||||||
else if (code == POINTER_PLUS_EXPR)
|
|
||||||
{
|
|
||||||
expr = gimple_assign_rhs1 (stmt);
|
|
||||||
|
|
||||||
tree offset = gimple_assign_rhs2 (stmt);
|
|
||||||
if (TREE_CODE (offset) == INTEGER_CST)
|
|
||||||
{
|
|
||||||
offset_int off = int_cst_value (offset);
|
|
||||||
offrange[0] = off;
|
|
||||||
offrange[1] = off;
|
|
||||||
|
|
||||||
if (TREE_CODE (expr) == SSA_NAME)
|
|
||||||
{
|
|
||||||
gimple *stmt = SSA_NAME_DEF_STMT (expr);
|
|
||||||
if (gimple_assign_single_p (stmt)
|
|
||||||
&& gimple_assign_rhs_code (stmt) == ADDR_EXPR)
|
|
||||||
expr = gimple_assign_rhs1 (stmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (TREE_CODE (offset) == SSA_NAME)
|
|
||||||
{
|
|
||||||
wide_int min, max;
|
|
||||||
value_range_type rng = get_range_info (offset, &min, &max);
|
|
||||||
if (rng == VR_RANGE)
|
|
||||||
{
|
|
||||||
offrange[0] = offset_int::from (min, SIGNED);
|
|
||||||
offrange[1] = offset_int::from (max, SIGNED);
|
|
||||||
}
|
|
||||||
else if (rng == VR_ANTI_RANGE)
|
|
||||||
{
|
|
||||||
offrange[0] = offset_int::from (max + 1, SIGNED);
|
|
||||||
offrange[1] = offset_int::from (min - 1, SIGNED);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gimple *stmt = SSA_NAME_DEF_STMT (offset);
|
|
||||||
tree type;
|
|
||||||
if (is_gimple_assign (stmt)
|
|
||||||
&& gimple_assign_rhs_code (stmt) == NOP_EXPR
|
|
||||||
&& (type = TREE_TYPE (gimple_assign_rhs1 (stmt)))
|
|
||||||
&& INTEGRAL_TYPE_P (type))
|
|
||||||
{
|
|
||||||
/* Use the bounds of the type of the NOP_EXPR operand
|
|
||||||
even if it's signed. The result doesn't trigger
|
|
||||||
warnings but makes their output more readable. */
|
|
||||||
offrange[0] = wi::to_offset (TYPE_MIN_VALUE (type));
|
|
||||||
offrange[1] = wi::to_offset (TYPE_MAX_VALUE (type));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
offrange[1] = maxobjsize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
offrange[1] = maxobjsize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TREE_CODE (expr) == ADDR_EXPR)
|
|
||||||
{
|
|
||||||
poly_int64 off;
|
|
||||||
tree op = TREE_OPERAND (expr, 0);
|
|
||||||
|
|
||||||
/* Determine the base object or pointer of the reference
|
|
||||||
and its constant offset from the beginning of the base. */
|
|
||||||
base = get_addr_base_and_unit_offset (op, &off);
|
|
||||||
|
|
||||||
HOST_WIDE_INT const_off;
|
|
||||||
if (base && off.is_constant (&const_off))
|
|
||||||
{
|
|
||||||
offrange[0] += const_off;
|
|
||||||
offrange[1] += const_off;
|
|
||||||
|
|
||||||
/* Stash the reference for offset validation. */
|
|
||||||
ref = op;
|
|
||||||
|
|
||||||
/* Also stash the constant offset for offset validation. */
|
|
||||||
if (TREE_CODE (op) == COMPONENT_REF)
|
|
||||||
refoff = const_off;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size = NULL_TREE;
|
|
||||||
base = get_base_address (TREE_OPERAND (expr, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!base)
|
|
||||||
base = build2 (MEM_REF, char_type_node, expr, null_pointer_node);
|
|
||||||
|
|
||||||
if (TREE_CODE (base) == MEM_REF)
|
|
||||||
{
|
|
||||||
offset_int off;
|
|
||||||
if (mem_ref_offset (base).is_constant (&off))
|
|
||||||
{
|
|
||||||
refoff += off;
|
|
||||||
offrange[0] += off;
|
|
||||||
offrange[1] += off;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
size = NULL_TREE;
|
|
||||||
base = TREE_OPERAND (base, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TREE_CODE (base) == SSA_NAME)
|
|
||||||
if (gimple *stmt = SSA_NAME_DEF_STMT (base))
|
|
||||||
{
|
|
||||||
enum gimple_code code = gimple_code (stmt);
|
|
||||||
if (code == GIMPLE_ASSIGN)
|
|
||||||
if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
|
|
||||||
{
|
|
||||||
base = gimple_assign_rhs1 (stmt);
|
|
||||||
|
|
||||||
tree offset = gimple_assign_rhs2 (stmt);
|
|
||||||
if (TREE_CODE (offset) == INTEGER_CST)
|
|
||||||
{
|
|
||||||
offset_int off = int_cst_value (offset);
|
|
||||||
refoff += off;
|
|
||||||
offrange[0] += off;
|
|
||||||
offrange[1] += off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DECL_P (base) && TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE)
|
|
||||||
{
|
|
||||||
/* For array objects, where a negative offset wouldn't make
|
|
||||||
sense, use zero instead if the upper bound is positive. */
|
|
||||||
if (offrange[0] < 0 && offrange[1] > 0)
|
|
||||||
offrange[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size)
|
if (size)
|
||||||
{
|
{
|
||||||
|
@ -398,6 +262,193 @@ builtin_memref::builtin_memref (tree expr, tree size)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sizrange[1] = maxobjsize;
|
sizrange[1] = maxobjsize;
|
||||||
|
|
||||||
|
tree basetype = TREE_TYPE (base);
|
||||||
|
if (DECL_P (base) && TREE_CODE (basetype) == ARRAY_TYPE)
|
||||||
|
{
|
||||||
|
/* If the offset could be in range of the referenced object
|
||||||
|
constrain its bounds so neither exceeds those of the object. */
|
||||||
|
if (offrange[0] < 0 && offrange[1] > 0)
|
||||||
|
offrange[0] = 0;
|
||||||
|
|
||||||
|
offset_int maxoff = maxobjsize;
|
||||||
|
if (ref && array_at_struct_end_p (ref))
|
||||||
|
; /* Use the maximum possible offset for last member arrays. */
|
||||||
|
else if (tree basesize = TYPE_SIZE_UNIT (basetype))
|
||||||
|
maxoff = wi::to_offset (basesize);
|
||||||
|
|
||||||
|
if (offrange[0] >= 0)
|
||||||
|
{
|
||||||
|
if (offrange[1] < 0)
|
||||||
|
offrange[1] = offrange[0] <= maxoff ? maxoff : maxobjsize;
|
||||||
|
else if (offrange[0] <= maxoff && offrange[1] > maxoff)
|
||||||
|
offrange[1] = maxoff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ctor helper to set or extend OFFRANGE based on the OFFSET argument. */
|
||||||
|
|
||||||
|
void
|
||||||
|
builtin_memref::extend_offset_range (tree offset)
|
||||||
|
{
|
||||||
|
const offset_int maxobjsize = tree_to_shwi (max_object_size ());
|
||||||
|
|
||||||
|
if (TREE_CODE (offset) == INTEGER_CST)
|
||||||
|
{
|
||||||
|
offset_int off = int_cst_value (offset);
|
||||||
|
if (off != 0)
|
||||||
|
{
|
||||||
|
offrange[0] += off;
|
||||||
|
offrange[1] += off;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TREE_CODE (offset) == SSA_NAME)
|
||||||
|
{
|
||||||
|
wide_int min, max;
|
||||||
|
value_range_type rng = get_range_info (offset, &min, &max);
|
||||||
|
if (rng == VR_RANGE)
|
||||||
|
{
|
||||||
|
offrange[0] += offset_int::from (min, SIGNED);
|
||||||
|
offrange[1] += offset_int::from (max, SIGNED);
|
||||||
|
}
|
||||||
|
else if (rng == VR_ANTI_RANGE)
|
||||||
|
{
|
||||||
|
offrange[0] += offset_int::from (max + 1, SIGNED);
|
||||||
|
offrange[1] += offset_int::from (min - 1, SIGNED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gimple *stmt = SSA_NAME_DEF_STMT (offset);
|
||||||
|
tree type;
|
||||||
|
if (is_gimple_assign (stmt)
|
||||||
|
&& gimple_assign_rhs_code (stmt) == NOP_EXPR
|
||||||
|
&& (type = TREE_TYPE (gimple_assign_rhs1 (stmt)))
|
||||||
|
&& INTEGRAL_TYPE_P (type))
|
||||||
|
{
|
||||||
|
/* Use the bounds of the type of the NOP_EXPR operand
|
||||||
|
even if it's signed. The result doesn't trigger
|
||||||
|
warnings but makes their output more readable. */
|
||||||
|
offrange[0] += wi::to_offset (TYPE_MIN_VALUE (type));
|
||||||
|
offrange[1] += wi::to_offset (TYPE_MAX_VALUE (type));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
offrange[1] += maxobjsize;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offrange[1] += maxobjsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determines the base object or pointer of the reference EXPR
|
||||||
|
and the offset range from the beginning of the base. */
|
||||||
|
|
||||||
|
void
|
||||||
|
builtin_memref::set_base_and_offset (tree expr)
|
||||||
|
{
|
||||||
|
const offset_int maxobjsize = tree_to_shwi (max_object_size ());
|
||||||
|
|
||||||
|
if (TREE_CODE (expr) == SSA_NAME)
|
||||||
|
{
|
||||||
|
/* Try to tease the offset out of the pointer. */
|
||||||
|
gimple *stmt = SSA_NAME_DEF_STMT (expr);
|
||||||
|
if (!base
|
||||||
|
&& gimple_assign_single_p (stmt)
|
||||||
|
&& gimple_assign_rhs_code (stmt) == ADDR_EXPR)
|
||||||
|
expr = gimple_assign_rhs1 (stmt);
|
||||||
|
else if (is_gimple_assign (stmt))
|
||||||
|
{
|
||||||
|
tree_code code = gimple_assign_rhs_code (stmt);
|
||||||
|
if (code == NOP_EXPR)
|
||||||
|
{
|
||||||
|
tree rhs = gimple_assign_rhs1 (stmt);
|
||||||
|
if (POINTER_TYPE_P (TREE_TYPE (rhs)))
|
||||||
|
expr = gimple_assign_rhs1 (stmt);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base = expr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (code == POINTER_PLUS_EXPR)
|
||||||
|
{
|
||||||
|
expr = gimple_assign_rhs1 (stmt);
|
||||||
|
|
||||||
|
tree offset = gimple_assign_rhs2 (stmt);
|
||||||
|
extend_offset_range (offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base = expr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base = expr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TREE_CODE (expr) == ADDR_EXPR)
|
||||||
|
expr = TREE_OPERAND (expr, 0);
|
||||||
|
|
||||||
|
poly_int64 bitsize, bitpos;
|
||||||
|
tree var_off;
|
||||||
|
machine_mode mode;
|
||||||
|
int sign, reverse, vol;
|
||||||
|
|
||||||
|
/* Determine the base object or pointer of the reference and
|
||||||
|
the constant bit offset from the beginning of the base.
|
||||||
|
If the offset has a non-constant component, it will be in
|
||||||
|
VAR_OFF. MODE, SIGN, REVERSE, and VOL are write only and
|
||||||
|
unused here. */
|
||||||
|
base = get_inner_reference (expr, &bitsize, &bitpos, &var_off,
|
||||||
|
&mode, &sign, &reverse, &vol);
|
||||||
|
|
||||||
|
poly_int64 bytepos = exact_div (bitpos, BITS_PER_UNIT);
|
||||||
|
|
||||||
|
HOST_WIDE_INT const_off;
|
||||||
|
if (!base || !bytepos.is_constant (&const_off))
|
||||||
|
{
|
||||||
|
base = get_base_address (TREE_OPERAND (expr, 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offrange[0] += const_off;
|
||||||
|
offrange[1] += const_off;
|
||||||
|
|
||||||
|
if (var_off)
|
||||||
|
{
|
||||||
|
if (TREE_CODE (var_off) == INTEGER_CST)
|
||||||
|
{
|
||||||
|
offset_int cstoff = wi::to_offset (var_off);
|
||||||
|
offrange[0] += cstoff;
|
||||||
|
offrange[1] += cstoff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
offrange[1] += maxobjsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stash the reference for offset validation. */
|
||||||
|
ref = expr;
|
||||||
|
|
||||||
|
/* Also stash the constant offset for offset validation. */
|
||||||
|
if (TREE_CODE (expr) == COMPONENT_REF)
|
||||||
|
refoff = const_off;
|
||||||
|
|
||||||
|
if (TREE_CODE (base) == MEM_REF)
|
||||||
|
{
|
||||||
|
tree memrefoff = TREE_OPERAND (base, 1);
|
||||||
|
extend_offset_range (memrefoff);
|
||||||
|
base = TREE_OPERAND (base, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TREE_CODE (base) == SSA_NAME)
|
||||||
|
set_base_and_offset (base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return error_mark_node if the signed offset exceeds the bounds
|
/* Return error_mark_node if the signed offset exceeds the bounds
|
||||||
|
@ -864,11 +915,19 @@ builtin_access::generic_overlap ()
|
||||||
the other. */
|
the other. */
|
||||||
bool depends_p = detect_overlap != &builtin_access::generic_overlap;
|
bool depends_p = detect_overlap != &builtin_access::generic_overlap;
|
||||||
|
|
||||||
if (!overlap_certain
|
if (!overlap_certain)
|
||||||
&& !dstref->strbounded_p
|
{
|
||||||
&& !depends_p)
|
if (!dstref->strbounded_p && !depends_p)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* There's no way to distinguish an access to the same member
|
||||||
|
of a structure from one to two distinct members of the same
|
||||||
|
structure. Give up to avoid excessive false positives. */
|
||||||
|
tree basetype = TREE_TYPE (TREE_TYPE (dstref->base));
|
||||||
|
if (RECORD_OR_UNION_TYPE_P (basetype))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* True for stpcpy and strcpy. */
|
/* True for stpcpy and strcpy. */
|
||||||
bool stxcpy_p = (!dstref->strbounded_p
|
bool stxcpy_p = (!dstref->strbounded_p
|
||||||
&& detect_overlap == &builtin_access::strcpy_overlap);
|
&& detect_overlap == &builtin_access::strcpy_overlap);
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
|
2018-02-20 Martin Sebor <msebor@redhat.com>
|
||||||
|
|
||||||
|
PR middle-end/84095
|
||||||
|
* c-c++-common/Warray-bounds-3.c: Adjust text of expected warnings.
|
||||||
|
* c-c++-common/Wrestrict.c: Same.
|
||||||
|
* gcc.dg/Wrestrict-6.c: Same.
|
||||||
|
* gcc.dg/Warray-bounds-27.c: New test.
|
||||||
|
* gcc.dg/Wrestrict-8.c: New test.
|
||||||
|
* gcc.dg/Wrestrict-9.c: New test.
|
||||||
|
* gcc.dg/pr84095.c: New test.
|
||||||
|
|
||||||
2018-02-20 Thomas Koenig <tkoenig@gcc.gnu.org>
|
2018-02-20 Thomas Koenig <tkoenig@gcc.gnu.org>
|
||||||
|
|
||||||
* gfortran.dg/structure_constructor_14.f90: Adjust STOP number.
|
* gfortran.dg/structure_constructor_14.f90: Adjust STOP number.
|
||||||
|
|
|
@ -61,7 +61,7 @@ void test_memcpy_bounds (char *d, const char *s, size_t n)
|
||||||
they appear as large positive in the source. It would be nice
|
they appear as large positive in the source. It would be nice
|
||||||
if they retained their type but unfortunately that's not how
|
if they retained their type but unfortunately that's not how
|
||||||
it works so be prepared for both in case it even gets fixed. */
|
it works so be prepared for both in case it even gets fixed. */
|
||||||
T (char, 1, a + UR (3, SIZE_MAX - 1), s, n); /* { dg-warning "offset \\\[3, -2] is out of the bounds \\\[0, 1] of object" "memcpy" } */
|
T (char, 1, a + UR (3, SIZE_MAX - 1), s, n); /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object" "memcpy" } */
|
||||||
|
|
||||||
/* Verify that invalid offsets into an array of unknown size are
|
/* Verify that invalid offsets into an array of unknown size are
|
||||||
detected. */
|
detected. */
|
||||||
|
@ -226,7 +226,7 @@ T (char, 1, a + SR (-2, -1), s, n); /* { dg-warning "offset \\\[-2, -1] is o
|
||||||
they appear as large positive in the source. It would be nice
|
they appear as large positive in the source. It would be nice
|
||||||
if they retained their type but unfortunately that's not how
|
if they retained their type but unfortunately that's not how
|
||||||
it works so be prepared for both in case it ever gets fixed. */
|
it works so be prepared for both in case it ever gets fixed. */
|
||||||
T (char, 1, a + UR (3, SIZE_MAX), s, n); /* { dg-warning "offset \\\[3, -1] is out of the bounds \\\[0, 1] of object " "mempcpy" } */
|
T (char, 1, a + UR (3, SIZE_MAX), s, n); /* { dg-warning "offset \\\[3, -?\[0-9\]+] is out of the bounds \\\[0, 1] of object " "mempcpy" } */
|
||||||
|
|
||||||
/* Verify that invalid offsets into an array of unknown size are
|
/* Verify that invalid offsets into an array of unknown size are
|
||||||
detected. */
|
detected. */
|
||||||
|
|
|
@ -223,7 +223,7 @@ void test_memcpy_range (char *d, size_t sz)
|
||||||
|
|
||||||
/* Because the size is constant and a power of 2 the following is
|
/* Because the size is constant and a power of 2 the following is
|
||||||
folded too early to detect the overlap. */
|
folded too early to detect the overlap. */
|
||||||
T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 2 byte at offset 2" "" { xfail *-*-* } } */
|
T (d + ir, d, 4); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 3] and 0 overlaps 2 byte at offset 2" "memcpy" { xfail *-*-* } } */
|
||||||
T (d + ir, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */
|
T (d + ir, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 3] and 0 overlaps between 2 and 3 bytes at offset \\\[2, 3]" "memcpy" } */
|
||||||
|
|
||||||
/* Exercise the full range of size_t. */
|
/* Exercise the full range of size_t. */
|
||||||
|
@ -325,11 +325,11 @@ void test_memcpy_anti_range (char *d, const char *s)
|
||||||
T (d, d + SAR (0, 3), 1);
|
T (d, d + SAR (0, 3), 1);
|
||||||
T (d, d + SAR (0, 3), 2);
|
T (d, d + SAR (0, 3), 2);
|
||||||
T (d, d + SAR (0, 3), 3);
|
T (d, d + SAR (0, 3), 3);
|
||||||
T (d, d + SAR (0, 3), DIFF_MAX - 2); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 2" } */
|
T (d, d + SAR (0, 3), DIFF_MAX - 2); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 2" "memcpy" } */
|
||||||
T (d, d + SAR (0, 3), DIFF_MAX - 1); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 1" } */
|
T (d, d + SAR (0, 3), DIFF_MAX - 1); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 1" "memcpy" } */
|
||||||
T (d, d + SAR (0, 3), DIFF_MAX); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 0" } */
|
T (d, d + SAR (0, 3), DIFF_MAX); /* { dg-warning "overlaps \[0-9\]+ bytes at offset 0" "memcpy" } */
|
||||||
|
|
||||||
T (d, d + SAR (0, 3), UR (DIFF_MAX - 2, DIFF_MAX)); /* { dg-warning "accessing \[0-9\]+ or more bytes at offsets 0 and \\\[-?\[0-9\]+, -?\[0-9\]+] overlaps \[0-9\]+ bytes at offset 2" } */
|
T (d, d + SAR (0, 3), UR (DIFF_MAX - 2, DIFF_MAX)); /* { dg-warning "accessing \[0-9\]+ or more bytes at offsets 0 and \\\[-?\[0-9\]+, -?\[0-9\]+] overlaps \[0-9\]+ bytes at offset 2" "memcpy" } */
|
||||||
|
|
||||||
/* Verify that a size in an anti-range ~[0, N] where N >= PTRDIFF_MAX
|
/* Verify that a size in an anti-range ~[0, N] where N >= PTRDIFF_MAX
|
||||||
doesn't trigger a warning. */
|
doesn't trigger a warning. */
|
||||||
|
@ -399,7 +399,7 @@ void test_memcpy_range_exceed (char *d, const char *s)
|
||||||
T (d + i, s, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[9223372036854775805, 9223372036854775807] and 0 overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */
|
T (d + i, s, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[9223372036854775805, 9223372036854775807] and 0 overlaps 3 bytes at offset 9223372036854775802" "LP64" { target lp64 } } */
|
||||||
#elif __SIZEOF_SIZE_T__ == 4
|
#elif __SIZEOF_SIZE_T__ == 4
|
||||||
T (d, d + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
|
T (d, d + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
|
||||||
T (d + i, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32} } */
|
T (d + i, d, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
|
||||||
|
|
||||||
T (d, s + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
|
T (d, s + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2147483645, 2147483647] overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32 } } */
|
||||||
T (d + i, s, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32} } */
|
T (d + i, s, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[2147483645, 2147483647] and 0 overlaps 3 bytes at offset 2147483642" "ILP32" { target ilp32} } */
|
||||||
|
@ -523,7 +523,7 @@ void test_memcpy_memarrray (struct MemArrays *p)
|
||||||
T (p->a8, p->a8 + 2, 2);
|
T (p->a8, p->a8 + 2, 2);
|
||||||
T (p->a8, p->a8 + 8, 1);
|
T (p->a8, p->a8 + 8, 1);
|
||||||
|
|
||||||
T (p->a8, p->a8 + 2, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and 2 overlaps 1 byte at offset 2" } */
|
T (p->a8, p->a8 + 2, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and 2 overlaps 1 byte at offset 2" "memcpy" } */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exercise the absence of warnings with memmove. */
|
/* Exercise the absence of warnings with memmove. */
|
||||||
|
@ -768,13 +768,13 @@ void test_strcpy_range (void)
|
||||||
|
|
||||||
/* The overlap in the cases below isn't inevitable but it is diagnosed
|
/* The overlap in the cases below isn't inevitable but it is diagnosed
|
||||||
because it is possible and so the code is considered unsafe. */
|
because it is possible and so the code is considered unsafe. */
|
||||||
T (8, "", a, a + r); /* { dg-warning "accessing 1 byte may overlap 1 byte" "strcpy" } */
|
T (8, "", a, a + r); /* { dg-warning "accessing 1 byte at offsets 0 and \\\[0, 8] may overlap 1 byte" "strcpy" } */
|
||||||
T (8, "0", a + r, a); /* { dg-warning "accessing 2 bytes may overlap up to 2 bytes" "strcpy" } */
|
T (8, "0", a + r, a); /* { dg-warning "accessing 2 bytes at offsets \\\[0, 8] and 0 may overlap up to 2 bytes" "strcpy" } */
|
||||||
T (8, "012", a + r, a); /* { dg-warning "accessing 4 bytes may overlap up to 4 bytes" "strcpy" } */
|
T (8, "012", a + r, a); /* { dg-warning "accessing 4 bytes at offsets \\\[0, 8] and 0 may overlap up to 4 bytes" "strcpy" } */
|
||||||
|
|
||||||
T (8, "", a, a + r); /* { dg-warning "accessing 1 byte may overlap" "strcpy" } */
|
T (8, "", a, a + r); /* { dg-warning "accessing 1 byte at offsets 0 and \\\[0, 8] may overlap" "strcpy" } */
|
||||||
T (8, "0", a, a + r); /* { dg-warning "accessing between 0 and 2 bytes may overlap up to 2 bytes" "strcpy" } */
|
T (8, "0", a, a + r); /* { dg-warning "accessing between 0 and 2 bytes at offsets 0 and \\\[0, 8] may overlap up to 2 bytes" "strcpy" } */
|
||||||
T (8, "012", a, a + r); /* { dg-warning "accessing between 0 and 4 bytes may overlap up to 4 bytes" "strcpy" } */
|
T (8, "012", a, a + r); /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[0, 8] may overlap up to 4 bytes" "strcpy" } */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exercise strcpy with destination and/or source of unknown lengthu. */
|
/* Exercise strcpy with destination and/or source of unknown lengthu. */
|
||||||
|
|
35
gcc/testsuite/gcc.dg/Warray-bounds-27.c
Normal file
35
gcc/testsuite/gcc.dg/Warray-bounds-27.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* { dg-do compile }
|
||||||
|
{ dg-options "-O2 -Wall -Wextra -Warray-bounds -Wrestrict" } */
|
||||||
|
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
|
||||||
|
extern void* memcpy (void* restrict, const void* restrict, size_t);
|
||||||
|
|
||||||
|
extern void sink (void*, ...);
|
||||||
|
|
||||||
|
struct Data {
|
||||||
|
size_t n;
|
||||||
|
void *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
void test_copy (void)
|
||||||
|
{
|
||||||
|
struct Data d;
|
||||||
|
sink (&d);
|
||||||
|
|
||||||
|
char dp1[sizeof d + 1];
|
||||||
|
char d2x[2 * sizeof d];
|
||||||
|
char d2xp1[2 * sizeof d + 1];
|
||||||
|
|
||||||
|
/* During development the following would incorrectly trigger:
|
||||||
|
warning: 'memcpy' forming offset [17, 25] is out of the bounds [0, 16]
|
||||||
|
of object ‘d’ with type 'struct Data' [-Warray-bounds]
|
||||||
|
that wasn't caught by the test suite. Make sure it is. */
|
||||||
|
memcpy (&dp1, d.p, sizeof dp1); /* { dg-bogus "\\\[-Warray-bounds" } */
|
||||||
|
|
||||||
|
/* Likewise. */
|
||||||
|
memcpy (&d2x, d.p, sizeof d2x); /* { dg-bogus "\\\[-Warray-bounds" } */
|
||||||
|
memcpy (&d2xp1, d.p, sizeof d2xp1); /* { dg-bogus "\\\[-Warray-bounds" } */
|
||||||
|
|
||||||
|
sink (&d, &dp1, &d2x, &d2xp1);
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ void warn_2_smax_p2 (void)
|
||||||
|
|
||||||
ptrdiff_t i = UR (2, DIFF_MAX + (size_t)2);
|
ptrdiff_t i = UR (2, DIFF_MAX + (size_t)2);
|
||||||
|
|
||||||
strcpy (d, d + i); /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, -\[0-9\]+] may overlap up to 2 bytes at offset 2" } */
|
strcpy (d, d + i); /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset 2" } */
|
||||||
|
|
||||||
sink (d);
|
sink (d);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ void warn_2u_smax_p2 (void)
|
||||||
|
|
||||||
size_t i = UR (2, DIFF_MAX + (size_t)2);
|
size_t i = UR (2, DIFF_MAX + (size_t)2);
|
||||||
|
|
||||||
strcpy (d, d + i); /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, -\[0-9\]+] may overlap up to 2 bytes at offset 2" } */
|
strcpy (d, d + i); /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset 2" } */
|
||||||
|
|
||||||
sink (d);
|
sink (d);
|
||||||
}
|
}
|
||||||
|
|
116
gcc/testsuite/gcc.dg/Wrestrict-8.c
Normal file
116
gcc/testsuite/gcc.dg/Wrestrict-8.c
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/* PR tree-optimization/84095 - false-positive -Wrestrict warnings for
|
||||||
|
memcpy within array
|
||||||
|
{ dg-do compile }
|
||||||
|
{ dg-options "-O2 -Wrestrict -ftrack-macro-expansion=0" } */
|
||||||
|
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
|
||||||
|
extern void* memcpy (void* restrict, const void* restrict, size_t);
|
||||||
|
|
||||||
|
#define T(d, s, n) memcpy (d, s, n)
|
||||||
|
|
||||||
|
struct S1 { char c; } a8_1[8];
|
||||||
|
|
||||||
|
void test_1_dim_var (int i, int j)
|
||||||
|
{
|
||||||
|
/* Variable destination index and constant source index. */
|
||||||
|
T (&a8_1[i], &a8_1[0], 1);
|
||||||
|
T (&a8_1[i], &a8_1[0], 2);
|
||||||
|
T (&a8_1[i], &a8_1[0], 3);
|
||||||
|
T (&a8_1[i], &a8_1[0], 4);
|
||||||
|
|
||||||
|
T (&a8_1[i], &a8_1[0], 5); /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
|
||||||
|
T (&a8_1[i], &a8_1[0], 6); /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and 0 overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
|
||||||
|
T (&a8_1[i], &a8_1[0], 7); /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and 0 overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
|
||||||
|
T (&a8_1[i], &a8_1[0], 8); /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
|
||||||
|
|
||||||
|
/* The following is diagnosed by -Warray-bounds when it's enabled
|
||||||
|
rather than by -Wrestrict. */
|
||||||
|
T (&a8_1[i], &a8_1[0], 9); /* { dg-warning "accessing 9 bytes at offsets \\\[0, 8] and 0 overlaps 9 bytes at offset 0" } */
|
||||||
|
|
||||||
|
/* Same as above but with constant destination index and variable
|
||||||
|
source index. */
|
||||||
|
T (&a8_1[0], &a8_1[i], 1);
|
||||||
|
T (&a8_1[0], &a8_1[i], 2);
|
||||||
|
T (&a8_1[0], &a8_1[i], 3);
|
||||||
|
T (&a8_1[0], &a8_1[i], 4);
|
||||||
|
|
||||||
|
T (&a8_1[0], &a8_1[i], 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
|
||||||
|
T (&a8_1[0], &a8_1[i], 6); /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[0, 8] overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
|
||||||
|
T (&a8_1[0], &a8_1[i], 7); /* { dg-warning "accessing 7 bytes at offsets 0 and \\\[0, 8] overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
|
||||||
|
T (&a8_1[0], &a8_1[i], 8); /* { dg-warning "accessing 8 bytes at offsets 0 and \\\[0, 8] overlaps 8 bytes at offset 0" } */
|
||||||
|
T (&a8_1[0], &a8_1[i], 9); /* { dg-warning "accessing 9 bytes at offsets 0 and \\\[0, 8] overlaps 9 bytes at offset 0" } */
|
||||||
|
|
||||||
|
|
||||||
|
/* Variable destination and source indices. */
|
||||||
|
T (&a8_1[i], &a8_1[j], 1);
|
||||||
|
T (&a8_1[i], &a8_1[j], 2);
|
||||||
|
T (&a8_1[i], &a8_1[j], 3);
|
||||||
|
T (&a8_1[i], &a8_1[j], 4);
|
||||||
|
|
||||||
|
T (&a8_1[i], &a8_1[j], 5); /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3\\\]" } */
|
||||||
|
T (&a8_1[i], &a8_1[j], 6); /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 4 and 6 bytes at offset \\\[0, 2\\\]" } */
|
||||||
|
T (&a8_1[i], &a8_1[j], 7); /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 6 and 7 bytes at offset \\\[0, 1\\\]" } */
|
||||||
|
T (&a8_1[i], &a8_1[j], 8); /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
|
||||||
|
|
||||||
|
/* The following is diagnosed by -Warray-bounds when it's enabled
|
||||||
|
rather than by -Wrestrict. */
|
||||||
|
T (&a8_1[i], &a8_1[j], 9); /* { dg-warning "accessing 9 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 9 bytes at offset 0" } */
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S4 { char a4[4]; } a2_4[2];
|
||||||
|
|
||||||
|
void test_2_dim (int i, int j)
|
||||||
|
{
|
||||||
|
T (&a2_4[i], &a2_4[0], 1);
|
||||||
|
T (&a2_4[i], &a2_4[0], 4);
|
||||||
|
|
||||||
|
T (&a2_4[i], &a2_4[0], 5); /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
|
||||||
|
T (&a2_4[i], &a2_4[0], 6); /* { dg-warning "accessing 6 bytes at offsets \\\[0, 8] and 0 overlaps between 4 and 6 bytes at offset \\\[0, 2]" } */
|
||||||
|
T (&a2_4[i], &a2_4[0], 7); /* { dg-warning "accessing 7 bytes at offsets \\\[0, 8] and 0 overlaps between 6 and 7 bytes at offset \\\[0, 1]" } */
|
||||||
|
T (&a2_4[i], &a2_4[0], 8); /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
|
||||||
|
|
||||||
|
T (a2_4[i].a4, a2_4[0].a4, 1);
|
||||||
|
T (a2_4[i].a4, a2_4[0].a4, 4);
|
||||||
|
|
||||||
|
T (a2_4[i].a4, a2_4[0].a4, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and 0 overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
|
||||||
|
T (a2_4[i].a4, a2_4[0].a4, 8); /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and 0 overlaps 8 bytes at offset 0" } */
|
||||||
|
|
||||||
|
T (a2_4[i].a4, a2_4[j].a4, 1);
|
||||||
|
T (a2_4[i].a4, a2_4[j].a4, 4);
|
||||||
|
|
||||||
|
/* The destination and source offsets printed below ignore the size
|
||||||
|
of the copy and only indicate the values that are valid for each
|
||||||
|
of the destination and source arguments on its own, without
|
||||||
|
considering the size of the overlapping access. */
|
||||||
|
T (a2_4[i].a4, a2_4[j].a4, 5); /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
|
||||||
|
T (a2_4[i].a4, a2_4[j].a4, 8); /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
|
||||||
|
|
||||||
|
/* Same as above but referencing the first elements of each array. */
|
||||||
|
T (&a2_4[i].a4[0], &a2_4[j].a4[0], 1);
|
||||||
|
T (&a2_4[i].a4[0], &a2_4[j].a4[0], 4);
|
||||||
|
|
||||||
|
T (&a2_4[i].a4[0], &a2_4[j].a4[0], 5); /* { dg-warning "accessing 5 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps between 2 and 5 bytes at offset \\\[0, 3]" } */
|
||||||
|
T (&a2_4[i].a4[0], &a2_4[j].a4[0], 8); /* { dg-warning "accessing 8 bytes at offsets \\\[0, 8] and \\\[0, 8] overlaps 8 bytes at offset 0" } */
|
||||||
|
|
||||||
|
T (&a2_4[i].a4[0], &a2_4[j].a4[1], 3);
|
||||||
|
T (&a2_4[i].a4[0], &a2_4[j].a4[2], 2);
|
||||||
|
T (&a2_4[i].a4[0], &a2_4[j].a4[3], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct { int i; } a2[2][8];
|
||||||
|
|
||||||
|
void test_single_2_dim_major (int i)
|
||||||
|
{
|
||||||
|
memcpy (&a2[i], &a2[0], sizeof *a2); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_single_2_dim_minor (int i)
|
||||||
|
{
|
||||||
|
memcpy (&a2[i][0], &a2[0][0], sizeof a2[0][0]); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_single_2_dim_major_minor (int i, int j)
|
||||||
|
{
|
||||||
|
memcpy (&a2[i][j], &a2[0][0], sizeof a2[0][0]); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
}
|
315
gcc/testsuite/gcc.dg/Wrestrict-9.c
Normal file
315
gcc/testsuite/gcc.dg/Wrestrict-9.c
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
/* PR tree-optimization/84095 - false-positive -Wrestrict warnings for
|
||||||
|
strcpy within array
|
||||||
|
{ dg-do compile }
|
||||||
|
{ dg-options "-O2 -Wrestrict -ftrack-macro-expansion=0" } */
|
||||||
|
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
|
||||||
|
extern void* memcpy (void* restrict, const void* restrict, size_t);
|
||||||
|
extern char* strcpy (char* restrict, const char* restrict);
|
||||||
|
|
||||||
|
#define T(d, s) strcpy (d, s)
|
||||||
|
|
||||||
|
struct MemArrays {
|
||||||
|
char pad[8];
|
||||||
|
char a2[3][9];
|
||||||
|
char a3[3][4][9];
|
||||||
|
} a[2];
|
||||||
|
|
||||||
|
struct NestedMemArrays {
|
||||||
|
struct MemArrays ma;
|
||||||
|
struct MemArrays ma1[2];
|
||||||
|
} nma[2];
|
||||||
|
|
||||||
|
/* Use a variable as the source of a copy to verify that VAR_DECL
|
||||||
|
is handled correctly when it's the source of GIMPLE assignment. */
|
||||||
|
const char *str = "1234567";
|
||||||
|
|
||||||
|
void test_obj_2_dim_const (void)
|
||||||
|
{
|
||||||
|
const char *s = strcpy (a[0].a2[0], "1234567");
|
||||||
|
|
||||||
|
T (a[0].a2[1], s);
|
||||||
|
T (a[0].a2[2], s);
|
||||||
|
|
||||||
|
/* Ideally, the offsets in the warning below would be relative to
|
||||||
|
the beginning of the accessed array member. Unfortunately, when
|
||||||
|
the offset is represented as
|
||||||
|
MEM_REF (char[9], A, offsetof (struct MemArrays, A[0].A2[0]) + 1)
|
||||||
|
as it is in this instance it's difficult to determine the member
|
||||||
|
that is being accessed and tease out from the MEM_REF the offset
|
||||||
|
as it appears in the source. As a result, the warning mentions
|
||||||
|
the offset from the beginning of A instead. This is suboptimal
|
||||||
|
and should be fixed, either by printing the correct offsets or
|
||||||
|
by mentioning the base object that the offset is relative to. */
|
||||||
|
T (a[0].a2[0] + 1, s); /* { dg-warning "accessing 8 bytes at offsets \(1|9\) and \(0|8\) overlaps 7 bytes at offset \(1|9\)." } */
|
||||||
|
T (a[0].a2[1] + 2, s);
|
||||||
|
T (a[0].a2[2] + 3, s);
|
||||||
|
|
||||||
|
T (a[1].a2[0], s);
|
||||||
|
T (a[1].a2[1], s);
|
||||||
|
T (a[1].a2[2], s);
|
||||||
|
|
||||||
|
T (a[1].a2[0] + 1, s);
|
||||||
|
T (a[1].a2[1] + 2, s);
|
||||||
|
T (a[1].a2[2] + 3, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_obj_nested_2_dim_const (void)
|
||||||
|
{
|
||||||
|
const char *s = strcpy (nma[0].ma.a2[0], str);
|
||||||
|
|
||||||
|
T (nma[0].ma.a2[1], s);
|
||||||
|
T (nma[0].ma.a2[2], s);
|
||||||
|
|
||||||
|
T (nma[0].ma.a2[0] + 1, s); /* { dg-warning "accessing 8 bytes at offsets 1 and 0 overlaps 7 bytes at offset 1" "bug " { xfail *-*-* } } */
|
||||||
|
T (nma[0].ma.a2[1] + 2, s);
|
||||||
|
T (nma[0].ma.a2[2] + 3, s);
|
||||||
|
|
||||||
|
T (nma[1].ma.a2[1], s);
|
||||||
|
T (nma[1].ma.a2[2], s);
|
||||||
|
|
||||||
|
T (nma[1].ma.a2[0] + 1, s);
|
||||||
|
T (nma[1].ma.a2[1] + 2, s);
|
||||||
|
T (nma[1].ma.a2[2] + 3, s);
|
||||||
|
|
||||||
|
|
||||||
|
T (nma[0].ma1[0].a2[1], s);
|
||||||
|
T (nma[0].ma1[0].a2[2], s);
|
||||||
|
|
||||||
|
T (nma[0].ma1[0].a2[0] + 1, s);
|
||||||
|
T (nma[0].ma1[0].a2[1] + 2, s);
|
||||||
|
T (nma[0].ma1[0].a2[2] + 3, s);
|
||||||
|
|
||||||
|
T (nma[1].ma1[0].a2[1], s);
|
||||||
|
T (nma[1].ma1[0].a2[2], s);
|
||||||
|
|
||||||
|
T (nma[1].ma1[0].a2[0] + 1, s);
|
||||||
|
T (nma[1].ma1[0].a2[1] + 2, s);
|
||||||
|
T (nma[1].ma1[0].a2[2] + 3, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_obj_2_dim_var (int i, int j)
|
||||||
|
{
|
||||||
|
const char *s = memcpy (a[0].a2[0], "1234567", 8);
|
||||||
|
|
||||||
|
T (a[i].a2[0], s); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
T (a[i].a2[1], s);
|
||||||
|
T (a[i].a2[2], s);
|
||||||
|
|
||||||
|
T (a[i].a2[0] + 1, s);
|
||||||
|
T (a[i].a2[1] + 1, s);
|
||||||
|
T (a[i].a2[2] + 1, s);
|
||||||
|
|
||||||
|
T (a[0].a2[i], s); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
T (a[1].a2[i], s);
|
||||||
|
|
||||||
|
T (a[i].a2[0] + j, s);
|
||||||
|
T (a[i].a2[1] + j, s);
|
||||||
|
T (a[i].a2[2] + j, s);
|
||||||
|
|
||||||
|
T (a[0].a2[i] + 1, s);
|
||||||
|
T (a[1].a2[i] + 1, s);
|
||||||
|
|
||||||
|
T (a[0].a2[i] + j, s);
|
||||||
|
T (a[1].a2[i] + j, s);
|
||||||
|
|
||||||
|
if (i < 0 || 1 < i)
|
||||||
|
i = 1;
|
||||||
|
|
||||||
|
T (a[i].a2[0], s);
|
||||||
|
T (a[i].a2[1], s);
|
||||||
|
T (a[i].a2[2], s);
|
||||||
|
|
||||||
|
T (a[i].a2[0] + 1, s);
|
||||||
|
T (a[i].a2[1] + 1, s);
|
||||||
|
T (a[i].a2[2] + 1, s);
|
||||||
|
|
||||||
|
T (a[0].a2[i], s);
|
||||||
|
T (a[1].a2[i], s);
|
||||||
|
|
||||||
|
T (a[i].a2[0] + j, s);
|
||||||
|
T (a[i].a2[1] + j, s);
|
||||||
|
T (a[i].a2[2] + j, s);
|
||||||
|
|
||||||
|
T (a[0].a2[i] + 1, s);
|
||||||
|
T (a[1].a2[i] + 1, s);
|
||||||
|
|
||||||
|
T (a[0].a2[i] + j, s);
|
||||||
|
T (a[1].a2[i] + j, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_obj_nested_2_dim_var (int i, int j)
|
||||||
|
{
|
||||||
|
const char *s = strcpy (nma[0].ma.a2[0], "1234567");
|
||||||
|
|
||||||
|
T (nma[i].ma.a2[0], s); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
T (nma[i].ma.a2[1], s);
|
||||||
|
T (nma[i].ma.a2[2], s);
|
||||||
|
|
||||||
|
T (nma[i].ma.a2[0] + 1, s);
|
||||||
|
T (nma[i].ma.a2[1] + 1, s);
|
||||||
|
T (nma[i].ma.a2[2] + 1, s);
|
||||||
|
|
||||||
|
T (nma[0].ma.a2[i], s); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
T (nma[1].ma.a2[i], s);
|
||||||
|
|
||||||
|
T (nma[i].ma.a2[0] + j, s);
|
||||||
|
T (nma[i].ma.a2[1] + j, s);
|
||||||
|
T (nma[i].ma.a2[2] + j, s);
|
||||||
|
|
||||||
|
T (nma[0].ma.a2[i] + 1, s);
|
||||||
|
T (nma[1].ma.a2[i] + 1, s);
|
||||||
|
|
||||||
|
T (nma[0].ma.a2[i] + j, s);
|
||||||
|
T (nma[1].ma.a2[i] + j, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_ref_2_dim_const (struct MemArrays *p)
|
||||||
|
{
|
||||||
|
strcpy (p[0].a2[0], "1234567");
|
||||||
|
const char *s = p[0].a2[0];
|
||||||
|
|
||||||
|
T (p[0].a2[1], s);
|
||||||
|
T (p[0].a2[2], s);
|
||||||
|
|
||||||
|
T (p[1].a2[0], s);
|
||||||
|
T (p[1].a2[1], s);
|
||||||
|
T (p[1].a2[2], s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_ref_2_dim_var (struct MemArrays *p, int i, int j)
|
||||||
|
{
|
||||||
|
strcpy (p[0].a2[0], "1234567");
|
||||||
|
const char *s = p[0].a2[0];
|
||||||
|
|
||||||
|
T (p[i].a2[0], s); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
T (p[i].a2[1], s);
|
||||||
|
T (p[i].a2[2], s);
|
||||||
|
|
||||||
|
T (p[0].a2[i], s);
|
||||||
|
T (p[1].a2[i], s);
|
||||||
|
|
||||||
|
T (p[i].a2[0] + j, s);
|
||||||
|
T (p[i].a2[1] + j, s);
|
||||||
|
T (p[i].a2[2] + j, s);
|
||||||
|
|
||||||
|
T (p[0].a2[i] + j, s);
|
||||||
|
T (p[1].a2[i] + j, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_obj_3_dim_var (int i, int j)
|
||||||
|
{
|
||||||
|
strcpy (a[0].a3[0][0], "1234567");
|
||||||
|
const char *s = a[0].a3[0][0];
|
||||||
|
|
||||||
|
T (a[0].a3[0][i], s);
|
||||||
|
T (a[0].a3[1][i], s);
|
||||||
|
T (a[0].a3[2][i], s);
|
||||||
|
|
||||||
|
T (a[1].a3[0][i], s);
|
||||||
|
T (a[1].a3[1][i], s);
|
||||||
|
T (a[1].a3[2][i], s);
|
||||||
|
|
||||||
|
T (a[0].a3[i][0], s); /* { dg-bogus "\\\[-Wrestrict\]" } */
|
||||||
|
T (a[0].a3[i][1], s);
|
||||||
|
T (a[0].a3[i][2], s);
|
||||||
|
|
||||||
|
T (a[1].a3[i][0], s);
|
||||||
|
T (a[1].a3[i][1], s);
|
||||||
|
T (a[1].a3[i][2], s);
|
||||||
|
|
||||||
|
T (a[i].a3[0][0], s); /* { dg-bogus "\\\[-Wrestrict\]" } */
|
||||||
|
T (a[i].a3[0][1], s);
|
||||||
|
T (a[i].a3[0][2], s);
|
||||||
|
|
||||||
|
T (a[i].a3[1][0], s);
|
||||||
|
T (a[i].a3[1][1], s);
|
||||||
|
T (a[i].a3[1][2], s);
|
||||||
|
|
||||||
|
T (a[i].a3[2][0], s);
|
||||||
|
T (a[i].a3[2][1], s);
|
||||||
|
T (a[i].a3[2][2], s);
|
||||||
|
|
||||||
|
|
||||||
|
T (a[0].a3[0][i] + 1, s);
|
||||||
|
T (a[0].a3[1][i] + 1, s);
|
||||||
|
T (a[0].a3[2][i] + 1, s);
|
||||||
|
|
||||||
|
T (a[1].a3[0][i] + 1, s);
|
||||||
|
T (a[1].a3[1][i] + 1, s);
|
||||||
|
T (a[1].a3[2][i] + 1, s);
|
||||||
|
|
||||||
|
|
||||||
|
T (a[0].a3[0][i] + j, s);
|
||||||
|
T (a[0].a3[1][i] + j, s);
|
||||||
|
T (a[0].a3[2][i] + j, s);
|
||||||
|
|
||||||
|
T (a[1].a3[0][i] + j, s);
|
||||||
|
T (a[1].a3[1][i] + j, s);
|
||||||
|
T (a[1].a3[2][i] + j, s);
|
||||||
|
|
||||||
|
T (a[0].a3[i][0] + j, s);
|
||||||
|
T (a[0].a3[i][1] + j, s);
|
||||||
|
T (a[0].a3[i][2] + j, s);
|
||||||
|
|
||||||
|
T (a[1].a3[i][0] + j, s);
|
||||||
|
T (a[1].a3[i][1] + j, s);
|
||||||
|
T (a[1].a3[i][2] + j, s);
|
||||||
|
|
||||||
|
T (a[i].a3[0][0] + j, s);
|
||||||
|
T (a[i].a3[0][1] + j, s);
|
||||||
|
T (a[i].a3[0][2] + j, s);
|
||||||
|
|
||||||
|
T (a[i].a3[1][0] + j, s);
|
||||||
|
T (a[i].a3[1][1] + j, s);
|
||||||
|
T (a[i].a3[1][2] + j, s);
|
||||||
|
|
||||||
|
T (a[i].a3[2][0] + j, s);
|
||||||
|
T (a[i].a3[2][1] + j, s);
|
||||||
|
T (a[i].a3[2][2] + j, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_obj_3_dim_const (struct MemArrays *p)
|
||||||
|
{
|
||||||
|
strcpy (p[0].a3[0][0], "1234567");
|
||||||
|
const char *s = p[0].a3[0][0];
|
||||||
|
|
||||||
|
T (p[0].a3[0][1], s);
|
||||||
|
T (p[0].a3[0][2], s);
|
||||||
|
T (p[0].a3[0][3], s);
|
||||||
|
|
||||||
|
T (p[0].a3[0][1] + 1, s);
|
||||||
|
T (p[0].a3[0][2] + 1, s);
|
||||||
|
T (p[0].a3[0][3] + 1, s);
|
||||||
|
|
||||||
|
T (p[0].a3[1][0], s);
|
||||||
|
T (p[0].a3[1][1], s);
|
||||||
|
T (p[0].a3[1][2], s);
|
||||||
|
T (p[0].a3[1][3], s);
|
||||||
|
|
||||||
|
T (p[0].a3[1][0] + 1, s);
|
||||||
|
T (p[0].a3[1][1] + 1, s);
|
||||||
|
T (p[0].a3[1][2] + 1, s);
|
||||||
|
T (p[0].a3[1][3] + 1, s);
|
||||||
|
|
||||||
|
T (p[0].a3[2][0], s);
|
||||||
|
T (p[0].a3[2][1], s);
|
||||||
|
T (p[0].a3[2][2], s);
|
||||||
|
T (p[0].a3[2][3], s);
|
||||||
|
|
||||||
|
T (p[1].a3[0][0], s);
|
||||||
|
T (p[1].a3[0][1], s);
|
||||||
|
T (p[1].a3[0][2], s);
|
||||||
|
T (p[1].a3[0][3], s);
|
||||||
|
|
||||||
|
T (p[1].a3[1][0], s);
|
||||||
|
T (p[1].a3[1][1], s);
|
||||||
|
T (p[1].a3[1][2], s);
|
||||||
|
T (p[1].a3[1][3], s);
|
||||||
|
|
||||||
|
T (p[1].a3[2][0], s);
|
||||||
|
T (p[1].a3[2][1], s);
|
||||||
|
T (p[1].a3[2][2], s);
|
||||||
|
T (p[1].a3[2][3], s);
|
||||||
|
}
|
14
gcc/testsuite/gcc.dg/pr84095.c
Normal file
14
gcc/testsuite/gcc.dg/pr84095.c
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/* PR tree-optimization/84095 - false-positive -Wrestrict warnings for
|
||||||
|
memcpy within array
|
||||||
|
{ dg-do compile }
|
||||||
|
{ dg-options "-O2 -Wrestrict" } */
|
||||||
|
|
||||||
|
struct { int i; } a[8];
|
||||||
|
|
||||||
|
void f (void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < 8; i++)
|
||||||
|
__builtin_memcpy (&a[i], &a[0], sizeof(a[0])); /* { dg-bogus "\\\[-Wrestrict]" } */
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue