* class.c (create_vtable_ptr): Put the vtable at the beginning of
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 29 Dec 1999 20:05:41 +0000 (20:05 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 29 Dec 1999 20:05:41 +0000 (20:05 +0000)
the class, not the end, in the new ABI.
* tree.c (propagate_binfo_offsets): Do the right thing for the new
ABI.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@31120 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/tree.c

index e6df5ba..7506b73 100644 (file)
@@ -1,5 +1,12 @@
 1999-12-29  Mark Mitchell  <mark@codesourcery.com>
 
+       * class.c (create_vtable_ptr): Put the vtable at the beginning of
+       the class, not the end, in the new ABI.
+       * tree.c (propagate_binfo_offsets): Do the right thing for the new
+       ABI.
+
+1999-12-29  Mark Mitchell  <mark@codesourcery.com>
+
        * cp-tree.h (lang_type): Add nearly_empty_p.  Adjust dummy.
        (CLASSTYPE_NEARLY_EMPTY_P): New macro.
        * class.c (check_bases): Update CLASSTYPE_NEARLY_EMPTY_P.
index 88b566e..8f1a1a2 100644 (file)
@@ -4136,7 +4136,22 @@ create_vtable_ptr (t, empty_p, has_virtual_p, max_has_virtual_p,
                                     empty_p);
 
       /* Add the new field to the list of fields in this class.  */
-      TYPE_FIELDS (t) = chainon (TYPE_FIELDS (t), TYPE_VFIELD (t));
+      if (!flag_new_abi)
+       /* In the old ABI, the vtable pointer goes at the end of the
+          class.  */
+       TYPE_FIELDS (t) = chainon (TYPE_FIELDS (t), TYPE_VFIELD (t));
+      else
+       {
+         /* But in the new ABI, the vtable pointer is the first thing
+            in the class.  */
+         TYPE_FIELDS (t) = chainon (TYPE_VFIELD (t), TYPE_FIELDS (t));
+         /* If there were any baseclasses, they can't possibly be at
+            offset zero any more, because that's where the vtable
+            pointer is.  So, converting to a base class is going to
+            take work.  */
+         if (CLASSTYPE_N_BASECLASSES (t))
+           TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (t) = 1;
+       }
 
       /* We can't yet add this new field to the list of all virtual
         function table pointers in this class.  The
index 39447ee..ce26ec9 100644 (file)
@@ -671,36 +671,81 @@ propagate_binfo_offsets (binfo, offset)
   tree binfos = BINFO_BASETYPES (binfo);
   int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
 
-  for (i = 0; i < n_baselinks; /* note increment is done in the loop.  */)
+  if (flag_new_abi)
     {
-      tree base_binfo = TREE_VEC_ELT (binfos, i);
-
-      if (TREE_VIA_VIRTUAL (base_binfo))
-       i += 1;
-      else
+      for (i = 0; i < n_baselinks; ++i)
        {
-         int j;
-         tree delta = NULL_TREE;
-
-         for (j = i+1; j < n_baselinks; j++)
-           if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j)))
-             {
-               /* The next basetype offset must take into account the space
-                  between the classes, not just the size of each class.  */
-               delta = size_binop (MINUS_EXPR,
-                                   BINFO_OFFSET (TREE_VEC_ELT (binfos, j)),
-                                   BINFO_OFFSET (base_binfo));
-               break;
-             }
-
-         BINFO_OFFSET (base_binfo) = offset;
+         tree base_binfo;
+
+         /* Figure out which base we're looking at.  */
+         base_binfo = TREE_VEC_ELT (binfos, i);
+
+         /* Skip virtual bases.  Their BINFO_OFFSET doesn't matter
+            since they are always reached by using offsets looked up
+            at run-time.  */
+         if (TREE_VIA_VIRTUAL (base_binfo))
+           continue;
+
+         /* Whatever offset this class used to have in its immediate
+            derived class, it is now at OFFSET more bytes in its
+            final derived class, since the immediate derived class is
+            already at the indicated OFFSET.  */
+         BINFO_OFFSET (base_binfo)
+           = size_binop (PLUS_EXPR, BINFO_OFFSET (base_binfo), offset);
 
          propagate_binfo_offsets (base_binfo, offset);
+       }
+    }
+  else
+    {
+      /* This algorithm, used for the old ABI, is neither simple, nor
+        general.  For example, it mishandles the case of:
+       
+           struct A;
+          struct B : public A;
+          struct C : public B;
+          
+        if B is at offset zero in C, but A is not in offset zero in
+        B.  In that case, it sets the BINFO_OFFSET for A to zero.
+        (This sitution arises in the new ABI if B has virtual
+        functions, but A does not.)  Rather than change this
+        algorithm, and risking breaking the old ABI, it is preserved
+        here.  */
+      for (i = 0; i < n_baselinks; /* note increment is done in the
+                                     loop.  */)
+       {
+         tree base_binfo = TREE_VEC_ELT (binfos, i);
 
-         /* Go to our next class that counts for offset propagation.  */
-         i = j;
-         if (i < n_baselinks)
-           offset = size_binop (PLUS_EXPR, offset, delta);
+         if (TREE_VIA_VIRTUAL (base_binfo))
+           i += 1;
+         else
+           {
+             int j;
+             tree delta = NULL_TREE;
+
+             for (j = i+1; j < n_baselinks; j++)
+               if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j)))
+                 {
+                   /* The next basetype offset must take into account
+                      the space between the classes, not just the
+                      size of each class.  */
+                   delta = size_binop (MINUS_EXPR,
+                                       BINFO_OFFSET (TREE_VEC_ELT (binfos, 
+                                                                   j)),
+                                       BINFO_OFFSET (base_binfo));
+                   break;
+                 }
+
+             BINFO_OFFSET (base_binfo) = offset;
+
+             propagate_binfo_offsets (base_binfo, offset);
+
+             /* Go to our next class that counts for offset
+                 propagation.  */
+             i = j;
+             if (i < n_baselinks)
+               offset = size_binop (PLUS_EXPR, offset, delta);
+           }
        }
     }
 }