aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>1999-12-21 20:42:21 +0000
committerMark Mitchell <mark@codesourcery.com>1999-12-21 20:42:21 +0000
commitafabc93719cf1c33c914468a4918a6f7a3b9cbb9 (patch)
tree28f4f613976d8eaf7eddadd396f88dfb083cda6c
parent6156f3df235bc064644681b8b3e295302c189c5a (diff)
* class.c (create_vtable_ptr): Put the vtable at the beginning ofnew-abi-branch
the class, not the end, in the new ABI. * decl2.c (flag_new_ab): Initialize it to one. * tree.c (propagate_binfo_offsets): Do the right thing for the new ABI. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/new-abi-branch@31060 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/class.c17
-rw-r--r--gcc/cp/decl2.c2
-rw-r--r--gcc/cp/tree.c95
4 files changed, 95 insertions, 27 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 9fa42692d0d..31ea8258329 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+1999-12-21 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.
+ * decl2.c (flag_new_ab): Initialize it to one.
+ * tree.c (propagate_binfo_offsets): Do the right thing for the new
+ ABI.
+
1999-12-20 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (CLASSTYPE_VFIELD_PARENT): Update comments.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 14c67af4a77..94869e8c7e9 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4105,7 +4105,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
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 58cbf3cf074..5cc3da59488 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -439,7 +439,7 @@ int flag_weak = 1;
/* Nonzero to enable experimental ABI changes. */
-int flag_new_abi;
+int flag_new_abi = 1;
/* Nonzero to use __cxa_atexit, rather than atexit, to register
destructors for local statics and global objects. */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 39447eee1c7..52532646cb9 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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 not 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);
+ }
}
}
}