PR middle-end/97595 - bogus -Wstringop-overflow due to DECL_SIZE_UNIT underreporting...
authorMartin Sebor <msebor@redhat.com>
Tue, 1 Dec 2020 22:10:30 +0000 (15:10 -0700)
committerMartin Sebor <msebor@redhat.com>
Tue, 1 Dec 2020 22:11:23 +0000 (15:11 -0700)
gcc/ChangeLog:

PR middle-end/97595
* tree.c (component_ref_size): Fail when DECL_SIZE != TYPE_SIZE.
* tree.h (DECL_SIZE, TYPE_SIZE): Update comment.

gcc/testsuite/ChangeLog:

PR middle-end/97595
* g++.dg/warn/Warray-bounds-14.C: New test.
* g++.dg/warn/Wstringop-overflow-6.C: New test.

gcc/testsuite/g++.dg/warn/Warray-bounds-14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wstringop-overflow-6.C [new file with mode: 0644]
gcc/tree.c
gcc/tree.h

diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-14.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-14.C
new file mode 100644 (file)
index 0000000..0812f83
--- /dev/null
@@ -0,0 +1,25 @@
+/* PR middle-end/97595 - bogus -Wstringop-overflow due to DECL_SIZE_UNIT
+   underreporting field size
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+struct A { char a[32]; };
+struct B: virtual A { };
+struct C: B { };
+
+struct D
+{
+  B &b;
+  D (B&);
+};
+
+D::D (B &b): b (b) { }        // { dg-bogus "-Warray-bounds" }
+
+void f (void*);
+
+void g ()
+{
+  C c;
+  D d (c);
+  f (&d);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-6.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-6.C
new file mode 100644 (file)
index 0000000..8173e60
--- /dev/null
@@ -0,0 +1,8 @@
+/* PR middle-end/97595 - bogus -Wstringop-overflow due to DECL_SIZE_UNIT
+   underreporting field size
+   { dg-do compile { target c++11 } }
+   { dg-options "-O2 -Wall -Wsystem-headers" } */
+
+#include <iostream>
+
+template void std::basic_iostream<char>::swap (basic_iostream&);
index d6ba55319bfc3102b2541532089ac83c80499d56..52a145dd01819e4263c76de7b6c5b6e95d4c7273 100644 (file)
@@ -13740,9 +13740,9 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
 {
   gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
 
-  special_array_member arkbuf;
+  special_array_member sambuf;
   if (!sam)
-    sam = &arkbuf;
+    sam = &sambuf;
   *sam = special_array_member::none;
 
   /* The object/argument referenced by the COMPONENT_REF and its type.  */
@@ -13756,7 +13756,13 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
     {
       tree memtype = TREE_TYPE (member);
       if (TREE_CODE (memtype) != ARRAY_TYPE)
-       return memsize;
+       /* DECL_SIZE may be less than TYPE_SIZE in C++ when referring
+          to the type of a class with a virtual base which doesn't
+          reflect the size of the virtual's members (see pr97595).
+          If that's the case fail for now and implement something
+          more robust in the future.  */
+       return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
+               ? memsize : NULL_TREE);
 
       bool trailing = array_at_struct_end_p (ref);
       bool zero_length = integer_zerop (memsize);
index 078919bce5deaaa1cb10b2774f78bd672b024499..ecdb11efcd1d6fcefb4a43dc2e2c234a3afa53f1 100644 (file)
@@ -1987,8 +1987,10 @@ class auto_suppress_location_wrappers
    so they must be checked as well.  */
 
 #define TYPE_UID(NODE) (TYPE_CHECK (NODE)->type_common.uid)
-/* Type size in bits as a tree expression.  Need not be constant
-   and may be null.  */
+/* Type size in bits as a tree expression.  Need not be constant and may
+   be greater than TYPE_SIZE for a C++ FIELD_DECL representing a base
+   class subobject with its own virtual base classes (which are laid out
+   separately).  */
 #define TYPE_SIZE(NODE) (TYPE_CHECK (NODE)->type_common.size)
 /* Likewise, type size in bytes.  */
 #define TYPE_SIZE_UNIT(NODE) (TYPE_CHECK (NODE)->type_common.size_unit)
@@ -2521,7 +2523,9 @@ extern tree vector_element_bits_tree (const_tree);
 #define DECL_INITIAL(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.initial)
 
 /* Holds the size of the datum, in bits, as a tree expression.
-   Need not be constant and may be null.  */
+   Need not be constant and may be null.  May be less than TYPE_SIZE
+   for a C++ FIELD_DECL representing a base class subobject with its
+   own virtual base classes (which are laid out separately).  */
 #define DECL_SIZE(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.size)
 /* Likewise for the size in bytes.  */
 #define DECL_SIZE_UNIT(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.size_unit)