From 3956244c58acceebf1ef2cf9a63e99f0f82abcb7 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Mon, 18 May 2020 15:07:48 -0600 Subject: [PATCH] PR middle-end/94940 - spurious -Warray-bounds for a zero length array member of union gcc/testsuite/ChangeLog: PR middle-end/94940 * gcc.dg/Warray-bounds-61.c: New test. gcc/ChangeLog: 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. --- gcc/ChangeLog | 9 ++ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.dg/Warray-bounds-61.c | 190 ++++++++++++++++++++++++ gcc/tree-vrp.c | 44 ++---- gcc/tree.c | 28 ++-- 5 files changed, 237 insertions(+), 39 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-61.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7f484da04f0d..135ebca56c41 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2020-05-18 Martin Sebor + + 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 * aclocal.m4: Add ax_cxx_compile_stdcxx.m4. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index facaf4436655..8b86b7a15450 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-05-18 Martin Sebor + + PR middle-end/94940 + * gcc.dg/Warray-bounds-61.c: New test. + 2020-05-18 Marek Polacek DR 1512 diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-61.c b/gcc/testsuite/gcc.dg/Warray-bounds-61.c new file mode 100644 index 000000000000..5b66cdc0aab1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-61.c @@ -0,0 +1,190 @@ +/* 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" } +} diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 4b5df543c00e..67c76db8fb1f 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -4009,15 +4009,11 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref, 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 { @@ -4050,27 +4046,17 @@ array_bounds_checker::check_mem_ref (location_t location, tree ref, 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; diff --git a/gcc/tree.c b/gcc/tree.c index 1aabffeea433..54e471acc890 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -13600,6 +13600,10 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */) 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); @@ -13611,7 +13615,7 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */) 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; @@ -13630,9 +13634,14 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */) 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 @@ -13647,28 +13656,27 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */) 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; @@ -13684,7 +13692,7 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */) 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. */ -- 2.39.5