diff options
Diffstat (limited to 'gnu/egcs/gcc/cp/search.c')
-rw-r--r-- | gnu/egcs/gcc/cp/search.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/gnu/egcs/gcc/cp/search.c b/gnu/egcs/gcc/cp/search.c index 8760c6aff7d..fb99f8f8eef 100644 --- a/gnu/egcs/gcc/cp/search.c +++ b/gnu/egcs/gcc/cp/search.c @@ -151,6 +151,9 @@ static int protected_accessible_p PROTO ((tree, tree, tree, tree)); 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 expand_direct_vtbls_init_thunks PROTO((tree, tree, int)); +static void expand_indirect_vtbls_init_thunks PROTO((tree, tree, tree)); + /* Allocate a level of searching. */ @@ -2626,6 +2629,117 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori } } +/* Emit initialization of vfields of BASE, where the complete object + is pointed to by decl_ptr. DO_SELF indicates we have to do our own + vfield, otherwise only proceed to our own direct non-virtual bases. */ + +static void +expand_direct_vtbls_init_thunks (base, decl_ptr, do_self) + tree base, decl_ptr; + int do_self; +{ + tree addr, expr; + tree type = BINFO_TYPE (base); + tree binfos = BINFO_BASETYPES (base); + int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; + tree vlist = lookup_name (vlist_identifier, 0); + int in_dtor = DECL_DESTRUCTOR_FOR_PVBASE_P (current_function_decl); + + my_friendly_assert (vlist != NULL_TREE, 990320); + + if (in_dtor) + /* In the destructor, we find the vfield pointers for the bases in + reverse order, before we find our own vfield pointer. */ + for (i = n_baselinks - 1; i >= 0; i--) + { + tree base_binfo = TREE_VEC_ELT (binfos, i); + int is_not_base_vtable + = i != CLASSTYPE_VFIELD_PARENT (type); + if (! TREE_VIA_VIRTUAL (base_binfo)) + expand_direct_vtbls_init_thunks (base_binfo, decl_ptr, + is_not_base_vtable); + } + + if (do_self && CLASSTYPE_VFIELDS (type)) + { + addr = build_vbase_path (PLUS_EXPR, build_pointer_type (type), + decl_ptr, base, 1); + addr = build_indirect_ref (addr, "vptr"); + addr = build_vfield_ref (addr, type); + + /* In a destructor, we decrease the vlist before we retrieve the + value. In a constructor, we increase the vlist after we + retrieve the value. */ + if (in_dtor) + { + expr = build_binary_op (MINUS_EXPR, vlist, integer_one_node); + expr = build_modify_expr (vlist, NOP_EXPR, expr); + expand_expr_stmt (expr); + } + + /* Store the next vptr into the vbase's vptr. */ + expr = build_indirect_ref (vlist, "__vlist"); + expr = convert_force (TREE_TYPE (addr), expr, 0); + expr = build_modify_expr (addr, NOP_EXPR, expr); + expand_expr_stmt (expr); + + /* Advance the vlist. */ + if (!in_dtor) + { + expr = build_binary_op (PLUS_EXPR, vlist, integer_one_node); + expr = build_modify_expr (vlist, NOP_EXPR, expr); + expand_expr_stmt (expr); + } + } + + if (!in_dtor) + for (i = 0; i < n_baselinks; i++) + { + tree base_binfo = TREE_VEC_ELT (binfos, i); + int is_not_base_vtable = i != CLASSTYPE_VFIELD_PARENT (type); + if (! TREE_VIA_VIRTUAL (base_binfo)) + expand_direct_vtbls_init_thunks (base_binfo, decl_ptr, + is_not_base_vtable); + } +} + +/* Like expand_indirect_vtbls_init below, but based on the vtable list + passed to the constructor. */ + +static void +expand_indirect_vtbls_init_thunks (binfo, true_exp, decl_ptr) + tree binfo; + tree true_exp, decl_ptr; +{ + tree type = BINFO_TYPE (binfo); + tree vbases = CLASSTYPE_VBASECLASSES (type); + struct vbase_info vi; + + vi.decl_ptr = (true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) + : decl_ptr); + vi.vbase_types = vbases; + + dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep, &vi); + + /* Initialized with vtables of type TYPE. */ + for (; vbases; vbases = TREE_CHAIN (vbases)) + { + tree addr; + + if (!CLASSTYPE_VFIELD (BINFO_TYPE (vbases))) + /* This vbase doesn't have a vptr of its own. */ + /* FIXME: check */ + continue; + + addr = convert_pointer_to_vbase (TREE_TYPE (vbases), decl_ptr); + expand_direct_vtbls_init_thunks (TYPE_BINFO (BINFO_TYPE (vbases)), + addr, 1); + + } + + dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0); +} + /* 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 @@ -2657,6 +2771,12 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr) mark_all_temps_used(); + if (TYPE_USES_PVBASES (type)) + { + expand_indirect_vtbls_init_thunks (binfo, true_exp, decl_ptr); + return; + } + if (TYPE_USES_VIRTUAL_BASECLASSES (type)) { rtx fixup_insns = NULL_RTX; |