+2020-05-18 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/94940
+ * tree-vrp.c (vrp_prop::check_mem_ref): Remove unreachable code.
+ * tree.c (component_ref_size): Correct the handling or array members
+ of unions.
+ Drop a pointless test.
+ Rename a local variable.
+
2020-05-18 Jason Merrill <jason@redhat.com>
* aclocal.m4: Add ax_cxx_compile_stdcxx.m4.
+2020-05-18 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/94940
+ * gcc.dg/Warray-bounds-61.c: New test.
+
2020-05-18 Marek Polacek <polacek@redhat.com>
DR 1512
--- /dev/null
+/* PR middle-end/94940 - spurious -Warray-bounds for a zero length array
+ member of union
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+extern int n;
+
+extern union Ua3_a0 {
+ int a3[3];
+ int a2[2]; // can only alias a3[0 - 2]
+ int a1[1]; // can alias all of the union
+ int a0[0]; // ditto
+} ua3_a0;
+
+void test_ua3_ua0_a0 (int i)
+{
+ ua3_a0.a0[0] = 0; // { dg-bogus "\\\[-Warray-bounds" }
+ ua3_a0.a0[1] = 0; // { dg-bogus "\\\[-Warray-bounds" }
+ ua3_a0.a0[2] = 0; // { dg-bogus "\\\[-Warray-bounds" }
+ ua3_a0.a0[3] = 0; // { dg-warning "\\\[-Warray-bounds" }
+ ua3_a0.a0[4] = 0; // { dg-warning "\\\[-Warray-bounds" }
+ ua3_a0.a0[i] = 0; // { dg-bogus "\\\[-Warray-bounds" }
+
+ if (i < __LINE__)
+ i = 5;
+ ua3_a0.a0[i] = 0; // { dg-warning "\\\[-Warray-bounds" }
+
+ if (i > -1)
+ i = -1;
+ ua3_a0.a0[i] = 0; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void test_ua3_ua0_a1 (int i)
+{
+ /* Abusing one-element array members the same way as those of
+ length zero is discouraged but so far acceted without warnings.
+ This should change at some point. */
+
+ ua3_a0.a1[0] = 0;
+ ua3_a0.a1[1] = 0;
+ ua3_a0.a1[2] = 0;
+ ua3_a0.a1[3] = 0; // { dg-warning "\\\[-Warray-bounds" }
+ ua3_a0.a1[i] = 0;
+
+ if (i > -1)
+ i = -1;
+ ua3_a0.a1[i] = 0; // { dg-warning "\\\[-Warray-bounds" }
+
+ if (i < 7)
+ i = 7;
+ ua3_a0.a1[i] = 0; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void test_ua3_ua0_a2 (int i)
+{
+ ua3_a0.a2[0] = 0;
+ ua3_a0.a2[1] = 0;
+ ua3_a0.a2[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
+ ua3_a0.a2[i] = 0;
+
+ if (i < __LINE__)
+ i = __LINE__;
+ ua3_a0.a2[i] = 0; // { dg-warning "\\\[-Warray-bounds" }
+
+ if (i > -1)
+ i = -1;
+ ua3_a0.a2[i] = 0; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+
+extern union Ua2_a3 {
+ int a2[2]; // can only alias a3[0 - 1]
+ int a3[3];
+} ua2_a3;
+
+void test_ua2_ua3 (int i)
+{
+ ua2_a3.a2[0] = 0; // { dg-bogus "\\\[-Warray-bounds" }
+ ua2_a3.a2[1] = 0; // { dg-bogus "\\\[-Warray-bounds" }
+ ua2_a3.a2[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
+ ua2_a3.a2[i] = 0;
+
+ if (i < __LINE__)
+ i = __LINE__;
+ ua2_a3.a2[i] = 0; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+
+extern struct SUa2_a0 {
+ union Ua2_a0 {
+ int a2[2];
+ int a0[0];
+ } u;
+} sua2_a0;
+
+void test_sua2_sua0 (int i)
+{
+ n += sua2_a0.u.a0[0];
+ n += sua2_a0.u.a0[1];
+ n += sua2_a0.u.a0[2]; // { dg-warning "\\\[-Warray-bounds" }
+ n += sua2_a0.u.a0[i];
+
+ if (i < __LINE__)
+ i = __LINE__;
+ n += sua2_a0.u.a0[i]; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void test_sua2_sua0_ptr (int i)
+{
+ union Ua2_a0 *p = &sua2_a0.u;
+
+ n += p->a0[0];
+ n += p->a0[1];
+ n += p->a0[2]; // { dg-warning "\\\[-Warray-bounds" }
+ n += p->a0[i];
+}
+
+
+extern struct SUSa3_a0 {
+ union USa3_a0 {
+ struct {
+ int a3[3];
+ } s;
+ int a2[2]; // can alias s.a3[0 - 2]
+ int a1[1]; // can alias s.a3[0 - 2]
+ int a0[0]; // can alias s.a3[0]
+ } u;
+} susa3_ua0;
+
+void test_susa3_sua0 (int i, int j)
+{
+ n += susa3_ua0.u.a0[0];
+ n += susa3_ua0.u.a0[1];
+ n += susa3_ua0.u.a0[2];
+ n += susa3_ua0.u.a0[3]; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void test_susa3_sua0_ptr (int i, int j)
+{
+ union USa3_a0 *p = &susa3_ua0.u;
+ n += p->a0[0];
+ n += p->a0[1];
+ n += p->a0[2];
+ n += p->a0[3]; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void test_susa3_sua1 (int i)
+{
+ n += susa3_ua0.u.a1[0];
+ n += susa3_ua0.u.a1[1];
+ n += susa3_ua0.u.a1[2];
+ n += susa3_ua0.u.a1[3]; // { dg-warning "\\\[-Warray-bounds" }
+
+ if (i < __LINE__)
+ i = __LINE__;
+ n += susa3_ua0.u.a1[i]; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+void test_susa3_sua2 (void)
+{
+ n += susa3_ua0.u.a2[0];
+ n += susa3_ua0.u.a2[1];
+ n += susa3_ua0.u.a2[2]; // { dg-warning "\\\[-Warray-bounds" }
+ n += susa3_ua0.u.a2[3]; // { dg-warning "\\\[-Warray-bounds" }
+}
+
+
+extern struct {
+ union {
+ struct {
+ int a3[3];
+ } s1;
+ struct {
+ int a0[0];
+ } s2;
+ } u;
+} susa3_usa0;
+
+void test_susi3_susi0 (int i)
+{
+ n += susa3_usa0.u.s2.a0[0];
+ n += susa3_usa0.u.s2.a0[1];
+ n += susa3_usa0.u.s2.a0[2];
+ n += susa3_usa0.u.s2.a0[3]; // { dg-warning "\\\[-Warray-bounds" }
+ n += susa3_usa0.u.s2.a0[i];
+
+ if (i < __LINE__)
+ i = __LINE__;
+ n += susa3_usa0.u.s2.a0[i]; // { dg-warning "\\\[-Warray-bounds" }
+}
else
arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
- if (TREE_CODE (ref) == MEM_REF)
- {
- /* For MEM_REF determine a tighter bound of the non-array
- element type. */
- tree eltype = TREE_TYPE (reftype);
- while (TREE_CODE (eltype) == ARRAY_TYPE)
- eltype = TREE_TYPE (eltype);
- eltsize = wi::to_offset (TYPE_SIZE_UNIT (eltype));
- }
+ /* Determine a tighter bound of the non-array element type. */
+ tree eltype = TREE_TYPE (reftype);
+ while (TREE_CODE (eltype) == ARRAY_TYPE)
+ eltype = TREE_TYPE (eltype);
+ eltsize = wi::to_offset (TYPE_SIZE_UNIT (eltype));
}
else
{
if (TREE_CODE (reftype) != ARRAY_TYPE)
reftype = build_array_type_nelts (reftype, 1);
- if (TREE_CODE (ref) == MEM_REF)
- {
- /* Extract the element type out of MEM_REF and use its size
- to compute the index to print in the diagnostic; arrays
- in MEM_REF don't mean anything. A type with no size like
- void is as good as having a size of 1. */
- tree type = TREE_TYPE (ref);
- while (TREE_CODE (type) == ARRAY_TYPE)
- type = TREE_TYPE (type);
- if (tree size = TYPE_SIZE_UNIT (type))
- {
- offrange[0] = offrange[0] / wi::to_offset (size);
- offrange[1] = offrange[1] / wi::to_offset (size);
- }
- }
- else
+ /* Extract the element type out of MEM_REF and use its size
+ to compute the index to print in the diagnostic; arrays
+ in MEM_REF don't mean anything. A type with no size like
+ void is as good as having a size of 1. */
+ tree type = TREE_TYPE (ref);
+ while (TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+ if (tree size = TYPE_SIZE_UNIT (type))
{
- /* For anything other than MEM_REF, compute the index to
- print in the diagnostic as the offset over element size. */
- offrange[0] = offrange[0] / eltsize;
- offrange[1] = offrange[1] / eltsize;
+ offrange[0] = offrange[0] / wi::to_offset (size);
+ offrange[1] = offrange[1] / wi::to_offset (size);
}
bool warned;
if (!interior_zero_length)
interior_zero_length = &int_0_len;
+ /* The object/argument referenced by the COMPONENT_REF and its type. */
+ tree arg = TREE_OPERAND (ref, 0);
+ tree argtype = TREE_TYPE (arg);
+ /* The referenced member. */
tree member = TREE_OPERAND (ref, 1);
tree memsize = DECL_SIZE_UNIT (member);
bool trailing = array_at_struct_end_p (ref);
bool zero_length = integer_zerop (memsize);
- if (!trailing && (!interior_zero_length || !zero_length))
+ if (!trailing && !zero_length)
/* MEMBER is either an interior array or is an array with
more than one element. */
return memsize;
offset_int minidx = wi::to_offset (min);
offset_int maxidx = wi::to_offset (max);
if (maxidx - minidx > 0)
- /* MEMBER is an array with more than 1 element. */
+ /* MEMBER is an array with more than one element. */
return memsize;
}
+
+ /* For a refernce to a zero- or one-element array member of a union
+ use the size of the union instead of the size of the member. */
+ if (TREE_CODE (argtype) == UNION_TYPE)
+ memsize = TYPE_SIZE_UNIT (argtype);
}
/* MEMBER is either a bona fide flexible array member, or a zero-length
if (!*interior_zero_length)
return NULL_TREE;
- if (TREE_CODE (TREE_OPERAND (ref, 0)) != COMPONENT_REF)
+ if (TREE_CODE (arg) != COMPONENT_REF)
return NULL_TREE;
- base = TREE_OPERAND (ref, 0);
+ base = arg;
while (TREE_CODE (base) == COMPONENT_REF)
base = TREE_OPERAND (base, 0);
baseoff = tree_to_poly_int64 (byte_position (TREE_OPERAND (ref, 1)));
}
/* BASE is the declared object of which MEMBER is either a member
- or that is cast to REFTYPE (e.g., a char buffer used to store
- a REFTYPE object). */
- tree reftype = TREE_TYPE (TREE_OPERAND (ref, 0));
+ or that is cast to ARGTYPE (e.g., a char buffer used to store
+ an ARGTYPE object). */
tree basetype = TREE_TYPE (base);
/* Determine the base type of the referenced object. If it's
- the same as REFTYPE and MEMBER has a known size, return it. */
+ the same as ARGTYPE and MEMBER has a known size, return it. */
tree bt = basetype;
if (!*interior_zero_length)
while (TREE_CODE (bt) == ARRAY_TYPE)
bt = TREE_TYPE (bt);
- bool typematch = useless_type_conversion_p (reftype, bt);
+ bool typematch = useless_type_conversion_p (argtype, bt);
if (memsize && typematch)
return memsize;
if (init)
{
memsize = TYPE_SIZE_UNIT (TREE_TYPE (init));
- if (tree refsize = TYPE_SIZE_UNIT (reftype))
+ if (tree refsize = TYPE_SIZE_UNIT (argtype))
{
/* Use the larger of the initializer size and the tail
padding in the enclosing struct. */