This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for vtable initialization
- To: gcc-patches at gcc dot gnu dot org
- Subject: C++ PATCH for vtable initialization
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Tue, 05 Oct 1999 09:28:04 -0700
- Organization: CodeSourcery, LLC
I missed a spot where we were still generating RTL during semantic
analysis; this showed up on targets that don't use vtable thunks.
With this patch, there are now no regressions in the C++ testsuite on
IRIX6, relative to 2.95.
I also found a bug whereby implicitly generated destructors could
cause calls to the wrong virtual function; see the attached test-case.
This bug looks to have been around for ages; it predates the 1.0.x
series.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
1999-10-05 Mark Mitchell <mark@codesourcery.com>
* method.c (synthesize_method): Call setup_vtbl_ptr for destructors.
* decl.c (start_function): Set current_in_charge_parm for
constructors, too, where appropriate.
* search.c (fixup_all_virtual_upcast_offsets): New function.
(expand_indirect_vtbls_init): Use it.
Index: testsuite/g++.old-deja/g++.other/dtor5.C
===================================================================
RCS file: dtor5.C
diff -N dtor5.C
*** /dev/null Sat Dec 5 20:30:03 1998
--- dtor5.C Tue Oct 5 09:14:45 1999
***************
*** 0 ****
--- 1,36 ----
+ // Origin: Mark Mitchell <mark@codesourcery.com>
+
+ extern "C" void abort ();
+
+ struct B;
+
+ struct S
+ {
+ S (B*);
+ ~S ();
+
+ B* b_;
+ };
+
+ struct B
+ {
+ B () : s (this) { }
+
+ virtual void f () { }
+
+ S s;
+ };
+
+ S::S (B* b) : b_ (b) { }
+
+ S::~S () { b_->f (); }
+
+ struct D : public B
+ {
+ virtual void f () { abort (); }
+ };
+
+ int main ()
+ {
+ D d;
+ }
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.478
diff -c -p -r1.478 decl.c
*** decl.c 1999/10/04 09:15:14 1.478
--- decl.c 1999/10/05 16:14:57
*************** start_function (declspecs, declarator, a
*** 12971,12977 ****
--- 12971,12985 ----
= build_indirect_ref (t, NULL_PTR);
cp_function_chain->x_current_class_ptr = t;
+ /* Constructors and destructors need to know whether they're "in
+ charge" of initializing virtual base classes. */
if (DECL_DESTRUCTOR_P (decl1))
+ current_in_charge_parm = TREE_CHAIN (t);
+ else if (DECL_CONSTRUCTOR_P (decl1)
+ && TREE_CHAIN (t)
+ && DECL_ARTIFICIAL (TREE_CHAIN (t))
+ && (DECL_NAME (TREE_CHAIN (t))
+ == in_charge_identifier))
current_in_charge_parm = TREE_CHAIN (t);
}
Index: cp/method.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/method.c,v
retrieving revision 1.122
diff -c -p -r1.122 method.c
*** method.c 1999/10/04 09:33:30 1.122
--- method.c 1999/10/05 16:14:58
*************** synthesize_method (fndecl)
*** 2384,2390 ****
need_body = 0;
}
else if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
! ;
else
{
tree arg_chain = FUNCTION_ARG_CHAIN (fndecl);
--- 2384,2390 ----
need_body = 0;
}
else if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
! setup_vtbl_ptr ();
else
{
tree arg_chain = FUNCTION_ARG_CHAIN (fndecl);
Index: cp/search.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/search.c,v
retrieving revision 1.127
diff -c -p -r1.127 search.c
*** search.c 1999/10/04 09:15:16 1.127
--- search.c 1999/10/05 16:15:06
*************** static int protected_accessible_p PROTO
*** 149,154 ****
--- 149,155 ----
static int friend_accessible_p PROTO ((tree, tree, tree, tree));
static void setup_class_bindings PROTO ((tree, int));
static int template_self_reference_p PROTO ((tree, tree));
+ static void fixup_all_virtual_upcast_offsets PROTO ((tree, tree));
/* Allocate a level of searching. */
*************** fixup_virtual_upcast_offsets (real_binfo
*** 2774,2792 ****
}
}
! /* Build a COMPOUND_EXPR which when expanded will generate the code
! needed to initialize all the virtual function table slots of all
! the virtual baseclasses. MAIN_BINFO is the binfo which determines
! the virtual baseclasses to use; TYPE is the type of the object to
! which the initialization applies. TRUE_EXP is the true object we
! are initializing, and DECL_PTR is the pointer to the sub-object we
! are initializing.
!
! When USE_COMPUTED_OFFSETS is non-zero, we can assume that the
! object was laid out by a top-level constructor and the computed
! offsets are valid to store vtables. When zero, we must store new
! vtables through virtual baseclass pointers. */
void
expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
tree binfo;
--- 2775,2837 ----
}
}
! /* Fixup all the virtual upcast offsets for TYPE. DECL_PTR is the
! address of the sub-object being initialized. */
+ static void
+ fixup_all_virtual_upcast_offsets (type, decl_ptr)
+ tree type;
+ tree decl_ptr;
+ {
+ tree if_stmt;
+ tree in_charge_node;
+ tree vbases;
+
+ /* Only tweak the vtables if we're in charge. */
+ in_charge_node = current_in_charge_parm;
+ if (!in_charge_node)
+ /* There's no need for any fixups in this case. */
+ return;
+ in_charge_node = build_binary_op (EQ_EXPR,
+ in_charge_node, integer_zero_node);
+ if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (in_charge_node, if_stmt);
+
+ /* Iterate through the virtual bases, fixing up the upcast offset
+ for each one. */
+ for (vbases = CLASSTYPE_VBASECLASSES (type);
+ vbases;
+ vbases = TREE_CHAIN (vbases))
+ {
+ if (flag_vtable_thunks)
+ /* We don't have dynamic thunks yet! So for now, just fail
+ silently. */
+ ;
+ else
+ {
+ tree vbase_offsets;
+ tree addr;
+
+ vbase_offsets = NULL_TREE;
+ addr = convert_pointer_to_vbase (TREE_TYPE (vbases), decl_ptr);
+ fixup_virtual_upcast_offsets (vbases,
+ TYPE_BINFO (BINFO_TYPE (vbases)),
+ 1, 0, addr, decl_ptr,
+ type, vbases, &vbase_offsets);
+ }
+ }
+
+ /* Close out the if-statement. */
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
+ }
+
+ /* Generate the code needed to initialize all the virtual function
+ table slots of all the virtual baseclasses. BINFO is the binfo
+ which determines the virtual baseclasses to use. TRUE_EXP is the
+ true object we are initializing, and DECL_PTR is the pointer to the
+ sub-object we are initializing. */
+
void
expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
tree binfo;
*************** expand_indirect_vtbls_init (binfo, true_
*** 2807,2813 ****
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
- rtx fixup_insns = NULL_RTX;
tree vbases = CLASSTYPE_VBASECLASSES (type);
struct vbase_info vi;
vi.decl_ptr = (true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0)
--- 2852,2857 ----
*************** expand_indirect_vtbls_init (binfo, true_
*** 2828,2871 ****
binfos. (in the CLASSTYPE_VFIELD_PARENT sense) */
expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr);
-
- /* Now we adjust the offsets for virtual functions that
- cross virtual boundaries on an implicit upcast on vf call
- so that the layout of the most complete type is used,
- instead of assuming the layout of the virtual bases from
- our current type. */
-
- if (flag_vtable_thunks)
- {
- /* We don't have dynamic thunks yet!
- So for now, just fail silently. */
- }
- else
- {
- tree vbase_offsets = NULL_TREE;
- push_to_sequence (fixup_insns);
- fixup_virtual_upcast_offsets (vbases,
- TYPE_BINFO (BINFO_TYPE (vbases)),
- 1, 0, addr, vi.decl_ptr,
- type, vbases, &vbase_offsets);
- fixup_insns = get_insns ();
- end_sequence ();
- }
}
! if (fixup_insns)
! {
! tree in_charge_node = current_in_charge_parm;
! if (! in_charge_node)
! {
! warning ("recoverable internal compiler error, nobody's in charge!");
! in_charge_node = integer_zero_node;
! }
! in_charge_node = build_binary_op (EQ_EXPR, in_charge_node, integer_zero_node);
! expand_start_cond (in_charge_node, 0);
! emit_insns (fixup_insns);
! expand_end_cond ();
! }
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
}
--- 2872,2881 ----
binfos. (in the CLASSTYPE_VFIELD_PARENT sense) */
expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr);
}
! fixup_all_virtual_upcast_offsets (type,
! vi.decl_ptr);
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
}