PR middle-end/94940 - spurious -Warray-bounds for a zero length array member of union
authorMartin Sebor <msebor@redhat.com>
Mon, 18 May 2020 21:07:48 +0000 (15:07 -0600)
committerMartin Sebor <msebor@redhat.com>
Mon, 18 May 2020 21:07:48 +0000 (15:07 -0600)
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
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Warray-bounds-61.c [new file with mode: 0644]
gcc/tree-vrp.c
gcc/tree.c

index 7f484da04f0d60156ac9ccc24ec499b365116fda..135ebca56c41af297ce1400ba3ee538e7a819bf5 100644 (file)
@@ -1,3 +1,12 @@
+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.
index facaf4436655d3b7758b67ef6edf1089a3ac077f..8b86b7a15450dca3dcccf1fb57e76857188177a6 100644 (file)
@@ -1,3 +1,8 @@
+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
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-61.c b/gcc/testsuite/gcc.dg/Warray-bounds-61.c
new file mode 100644 (file)
index 0000000..5b66cdc
--- /dev/null
@@ -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" }
+}
index 4b5df543c00ebaa845a3e0a864dc96c01eb026d1..67c76db8fb1f85005e5abd228e789275588d203a 100644 (file)
@@ -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;
index 1aabffeea433fc690c2610f9ba7978912b840c17..54e471acc8906b63d1bff5def6c6b600616f0caa 100644 (file)
@@ -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.  */