class.c (contains_empty_class_p): New method.
authorMark Mitchell <mark@codesourcery.com>
Wed, 25 Sep 2002 19:07:35 +0000 (19:07 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Wed, 25 Sep 2002 19:07:35 +0000 (19:07 +0000)
* cp/class.c (contains_empty_class_p): New method.
(walk_subobject_offsets): Correct computation of field offset.
(layout_empty_base): Correct placement of emtpy base classes.
(layout_class_type): Warn about ABI changes.

* doc/invoke.texi: Add more -Wabi examples.

* gcc/testsuite/g++.dg/abi/empty5.C: New test.
* gcc/testsuite/g++.dg/abi/empty6.C: New test.
* gcc/testsuite/g++.dg/abi/vbase12.C: New test.

From-SVN: r57508

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/empty5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/abi/empty6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/abi/vbase12.C [new file with mode: 0644]

index 41e393b..4d85a2f 100644 (file)
@@ -1,3 +1,7 @@
+2002-09-25  Mark Mitchell  <mark@codesourcery.com>
+
+       * doc/invoke.texi: Add more -Wabi examples.
+
 2002-09-25  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.h (TARGET_MIPS4100): Add missing bracket.
index a25c6aa..c9f7523 100644 (file)
@@ -1,3 +1,10 @@
+2002-09-25  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp/class.c (contains_empty_class_p): New method.
+       (walk_subobject_offsets): Correct computation of field offset.
+       (layout_empty_base): Correct placement of emtpy base classes.
+       (layout_class_type): Warn about ABI changes.
+
 2002-09-23  Mark Mitchell  <mark@codesourcery.com>
 
        * cp/class.c (layout_virtual_bases): Do not round the size of the
index 316bc63..7532c5d 100644 (file)
@@ -210,6 +210,7 @@ static int splay_tree_compare_integer_csts PARAMS ((splay_tree_key k1,
                                                    splay_tree_key k2));
 static void warn_about_ambiguous_direct_bases PARAMS ((tree));
 static bool type_requires_array_cookie PARAMS ((tree));
+static bool contains_empty_class_p (tree);
 
 /* Macros for dfs walking during vtt construction. See
    dfs_ctor_vtable_bases_queue_p, dfs_build_secondary_vptr_vtt_inits
@@ -3544,11 +3545,19 @@ walk_subobject_offsets (type, f, offset, offsets, max_offset, vbases_p)
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
        if (TREE_CODE (field) == FIELD_DECL)
          {
+           tree field_offset;
+
+           if (abi_version_at_least (2))
+             field_offset = byte_position (field);
+           else
+             /* In G++ 3.2, DECL_FIELD_OFFSET was used.  */
+             field_offset = DECL_FIELD_OFFSET (field);
+
            r = walk_subobject_offsets (TREE_TYPE (field),
                                        f,
                                        size_binop (PLUS_EXPR,
                                                    offset,
-                                                   DECL_FIELD_OFFSET (field)),
+                                                   field_offset),
                                        offsets,
                                        max_offset,
                                        /*vbases_p=*/1);
@@ -3720,10 +3729,17 @@ layout_empty_base (binfo, eoc, offsets, t)
   tree alignment;
   tree basetype = BINFO_TYPE (binfo);
   bool atend = false;
-  
+
   /* This routine should only be used for empty classes.  */
   my_friendly_assert (is_empty_class (basetype), 20000321);
   alignment = ssize_int (CLASSTYPE_ALIGN_UNIT (basetype));
+  
+  if (abi_version_at_least (2))
+    BINFO_OFFSET (binfo) = size_zero_node;
+  if (warn_abi && !integer_zerop (BINFO_OFFSET (binfo)))
+    warning ("offset of empty base `%T' may not be ABI-compliant and may"
+            "change in a future version of GCC",
+            BINFO_TYPE (binfo));
 
   /* This is an empty base class.  We first try to put it at offset
      zero.  */
@@ -4915,6 +4931,17 @@ layout_class_type (t, empty_p, vfuns_p, virtuals_p)
        cp_warning_at ("offset of `%D' is not ABI-compliant and may change in a future version of GCC", 
                       field);
 
+      /* G++ used to use DECL_FIELD_OFFSET as if it were the byte
+        offset of the field.  */
+      if (warn_abi 
+         && !tree_int_cst_equal (DECL_FIELD_OFFSET (field),
+                                 byte_position (field))
+         && contains_empty_class_p (TREE_TYPE (field)))
+       cp_warning_at ("`%D' contains empty classes which may cause base "
+                      "classes to be placed at different locations in a "
+                      "future version of GCC",
+                      field);
+
       /* If we needed additional padding after this field, add it
         now.  */
       if (padding)
@@ -6371,6 +6398,30 @@ is_empty_class (type)
   return integer_zerop (CLASSTYPE_SIZE (type));
 }
 
+/* Returns true if TYPE contains an empty class.  */
+
+static bool
+contains_empty_class_p (tree type)
+{
+  if (is_empty_class (type))
+    return true;
+  if (CLASS_TYPE_P (type))
+    {
+      tree field;
+      int i;
+
+      for (i = 0; i < CLASSTYPE_N_BASECLASSES (type); ++i)
+       if (contains_empty_class_p (TYPE_BINFO_BASETYPE (type, i)))
+         return true;
+      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+       if (contains_empty_class_p (TREE_TYPE (field)))
+         return true;
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    return contains_empty_class_p (TREE_TYPE (type));
+  return false;
+}
+
 /* Find the enclosing class of the given NODE.  NODE can be a *_DECL or
    a *_TYPE node.  NODE can also be a local class.  */
 
index 386c174..9a8fa2a 100644 (file)
@@ -1546,6 +1546,25 @@ union U @{ int i : 4096; @};
 Assuming that an @code{int} does not have 4096 bits, G++ will make the
 union too small by the number of bits in an @code{int}.
 
+@item
+Empty classes can be placed at incorrect offsets.  For example:
+@smallexample
+struct A @{@};
+
+struct B @{
+  A a;
+  virtual void f ();
+@};
+
+struct C : public B, public A @{@};
+@end smallexample
+
+@noindent
+G++ will place the @code{A} base class of @code{C} at a non-zero offset;
+it should be placed at offset zero.  G++ mistakenly believes that the
+@code{A} data member of @code{B} is already at offset zero.
+
 @end itemize
 
 @item -Wctor-dtor-privacy @r{(C++ only)}
index b4021bc..c7b67c6 100644 (file)
@@ -1,3 +1,9 @@
+2002-09-25  Mark Mitchell  <mark@codesourcery.com>
+
+       * gcc/testsuite/g++.dg/abi/empty5.C: New test.
+       * gcc/testsuite/g++.dg/abi/empty6.C: New test.
+       * gcc/testsuite/g++.dg/abi/vbase12.C: New test.
+
 2002-09-25  Richard Henderson  <rth@redhat.com>
 
        * gcc.c-torture/execute/ieee/20010226-1.c: Early exit for
diff --git a/gcc/testsuite/g++.dg/abi/empty5.C b/gcc/testsuite/g++.dg/abi/empty5.C
new file mode 100644 (file)
index 0000000..c371772
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-options "-fabi-version=0" }
+
+struct A {};
+
+struct B {
+  A a;
+  virtual void f () {}
+};
+
+struct C : public B, public A {};
+
+C c;
+
+int main () {
+  if ((void*) (A*) &c != &c)
+    return 1;
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty6.C b/gcc/testsuite/g++.dg/abi/empty6.C
new file mode 100644 (file)
index 0000000..aa27273
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-options "-Wabi" }
+
+struct A {};
+
+struct B {
+  A a; // { dg-warning "empty" }
+  virtual void f () {}
+};
diff --git a/gcc/testsuite/g++.dg/abi/vbase12.C b/gcc/testsuite/g++.dg/abi/vbase12.C
new file mode 100644 (file)
index 0000000..98b9054
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do run }
+// { dg-options "-fabi-version=0" }
+
+struct A {};
+struct B { A a; virtual void f () {} };
+struct C : public B, virtual public A {};
+struct D : public C, virtual public A {};
+
+D d;
+
+int main () {
+  if (((char*)(A*)&d - (char*)&d) != 0)
+    return 1;
+}