+ {
+ b = BINFO_BASETYPE (binfo, i);
+ if (!TREE_VIA_VIRTUAL (b))
+ inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t,
+ /*virtuals_vtts_p=*/0,
+ inits, index);
+ }
+
+ /* Add secondary virtual pointers for all subobjects of BINFO with
+ either virtual bases or virtual functions overridden along a
+ virtual path between the declaration and D, except subobjects
+ that are non-virtual primary bases. */
+ secondary_vptrs = tree_cons (t, NULL_TREE, BINFO_TYPE (binfo));
+ TREE_TYPE (secondary_vptrs) = *index;
+ dfs_walk_real (binfo,
+ dfs_build_secondary_vptr_vtt_inits,
+ NULL,
+ dfs_unmarked_real_bases_queue_p,
+ secondary_vptrs);
+ dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
+ *index = TREE_TYPE (secondary_vptrs);
+
+ /* The secondary vptrs come back in reverse order. After we reverse
+ them, and add the INITS, the last init will be the first element
+ of the chain. */
+ secondary_vptrs = TREE_VALUE (secondary_vptrs);
+ if (secondary_vptrs)
+ {
+ *inits = nreverse (secondary_vptrs);
+ inits = &TREE_CHAIN (secondary_vptrs);
+ my_friendly_assert (*inits == NULL_TREE, 20000517);
+ }
+
+ /* Add the secondary VTTs for virtual bases. */
+ if (virtual_vtts_p)
+ for (b = TYPE_BINFO (BINFO_TYPE (binfo)); b; b = TREE_CHAIN (b))
+ {
+ tree vbase;
+
+ if (!TREE_VIA_VIRTUAL (b))
+ continue;
+
+ vbase = binfo_for_vbase (BINFO_TYPE (b), t);
+ inits = build_vtt_inits (vbase, t, /*virtual_vtts_p=*/0,
+ inits, index);
+ }
+
+ dfs_walk (binfo, dfs_fixup_binfo_vtbls,
+ dfs_unmarked_real_bases_queue_p,
+ build_tree_list (t, binfo));
+
+ return inits;
+}
+
+/* Called from build_vtt_inits via dfs_walk. */
+
+static tree
+dfs_build_secondary_vptr_vtt_inits (binfo, data)
+ tree binfo;
+ void *data;
+{
+ tree l;
+ tree t;
+ tree init;
+ tree index;
+
+ l = (tree) data;
+ t = TREE_CHAIN (l);
+
+ SET_BINFO_MARKED (binfo);
+
+ /* We don't care about bases that don't have vtables. */
+ if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
+ return NULL_TREE;
+
+ /* We're only interested in proper subobjects of T. */
+ if (same_type_p (BINFO_TYPE (binfo), t))
+ return NULL_TREE;
+
+ /* We're not interested in non-virtual primary bases. */
+ if (!TREE_VIA_VIRTUAL (binfo) && BINFO_PRIMARY_MARKED_P (binfo))
+ return NULL_TREE;
+
+ /* If BINFO doesn't have virtual bases, then we have to look to see
+ whether or not any virtual functions were overidden along a
+ virtual path. The point is that given:
+
+ struct V { virtual void f(); int i; };
+ struct C : public virtual V { void f (); };
+
+ when we constrct C we need a secondary vptr for V-in-C because we
+ don't know what the vcall offset for `f' should be. If `V' ends
+ up in a different place in the complete object, then we'll need a
+ different vcall offset than that present in the normal V-in-C
+ vtable. */
+ if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
+ && !BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P (get_matching_base (binfo, t)))
+ return NULL_TREE;
+
+ /* Record the index where this secondary vptr can be found. */
+ index = TREE_TYPE (l);
+ BINFO_VPTR_INDEX (binfo) = index;
+ TREE_TYPE (l) = size_binop (PLUS_EXPR, index,
+ TYPE_SIZE_UNIT (ptr_type_node));
+
+ /* Add the initializer for the secondary vptr itself. */
+ init = BINFO_VTABLE (binfo);
+ if (TREE_CODE (init) == TREE_LIST)
+ init = TREE_VALUE (init);
+ TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l));
+
+ return NULL_TREE;
+}
+
+/* Called from build_vtt_inits via dfs_walk. */
+
+static tree
+dfs_fixup_binfo_vtbls (binfo, data)
+ tree binfo;
+ void *data;
+{
+ CLEAR_BINFO_MARKED (binfo);
+
+ /* We don't care about bases that don't have vtables. */
+ if (!TYPE_VFIELD (BINFO_TYPE (binfo)))
+ return NULL_TREE;
+
+ /* If we scribbled the construction vtable vptr into BINFO, clear it
+ out now. */
+ if (TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST
+ && (TREE_PURPOSE (BINFO_VTABLE (binfo))
+ == TREE_VALUE ((tree) data)))
+ BINFO_VTABLE (binfo) = TREE_CHAIN (BINFO_VTABLE (binfo));
+
+ return NULL_TREE;
+}
+
+/* Build the construction vtable group for BINFO which is in the
+ hierarchy dominated by T. */
+
+static void
+build_ctor_vtbl_group (binfo, t)
+ tree binfo;
+ tree t;
+{
+ tree list;
+ tree type;
+ tree vtbl;
+ tree inits;
+ tree id;
+ tree vbase;
+
+ /* See if we've already create this construction vtable group. */
+ if (flag_new_abi)
+ id = mangle_ctor_vtbl_for_type (t, binfo);
+ else
+ id = get_ctor_vtbl_name (t, binfo);
+ if (IDENTIFIER_GLOBAL_VALUE (id))
+ return;
+
+ /* Build a version of VTBL (with the wrong type) for use in
+ constructing the addresses of secondary vtables in the
+ construction vtable group. */
+ vtbl = build_vtable (t, id, ptr_type_node);
+ list = build_tree_list (vtbl, NULL_TREE);
+ accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),
+ binfo, t, list);
+ for (vbase = TYPE_BINFO (TREE_TYPE (binfo));
+ vbase;
+ vbase = TREE_CHAIN (vbase))
+ {
+ tree b;
+
+ if (!TREE_VIA_VIRTUAL (vbase))
+ continue;
+
+ b = binfo_for_vbase (BINFO_TYPE (vbase), t);
+ accumulate_vtbl_inits (b, vbase, binfo, t, list);
+ }
+
+ inits = TREE_VALUE (list);
+
+ /* Figure out the type of the construction vtable. */
+ type = build_index_type (size_int (list_length (inits)));
+ type = build_cplus_array_type (vtable_entry_type, type);
+ TREE_TYPE (vtbl) = type;
+
+ /* Initialize the construction vtable. */
+ pushdecl_top_level (vtbl);
+ initialize_array (vtbl, inits);
+}
+
+/* Add the vtbl initializers for BINFO (and its non-primary,
+ non-virtual bases) to the list of INITS. BINFO is in the hierarchy
+ dominated by T. ORIG_BINFO must have the same type as BINFO, but
+ may be different from BINFO if we are building a construction
+ vtable. RTTI_BINFO gives the object that should be used as the
+ complete object for BINFO. */
+
+static void
+accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, inits)
+ tree binfo;
+ tree orig_binfo;
+ tree rtti_binfo;
+ tree t;
+ tree inits;
+{
+ int i;
+ int ctor_vtbl_p;
+
+ my_friendly_assert (same_type_p (BINFO_TYPE (binfo),
+ BINFO_TYPE (orig_binfo)),
+ 20000517);
+
+ /* This is a construction vtable if the RTTI type is not the most
+ derived type in the hierarchy. */
+ ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
+
+ /* If we're building a construction vtable, we're not interested in
+ subobjects that don't require construction vtables. */
+ if (ctor_vtbl_p
+ && !TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))
+ && !(BINFO_OVERRIDE_ALONG_VIRTUAL_PATH_P
+ (get_matching_base (binfo, BINFO_TYPE (rtti_binfo)))))
+ return;
+
+ /* Build the initializers for the BINFO-in-T vtable. */
+ TREE_VALUE (inits)
+ = chainon (TREE_VALUE (inits),
+ dfs_accumulate_vtbl_inits (binfo, orig_binfo,
+ rtti_binfo, t, inits));
+
+ /* Walk the BINFO and its bases. We walk in preorder so that as we
+ initialize each vtable we can figure out at what offset the
+ secondary vtable lies from the primary vtable. We can't use
+ dfs_walk here because we need to iterate through bases of BINFO
+ and RTTI_BINFO simultaneously. */
+ for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+ {
+ tree base_binfo;
+
+ base_binfo = BINFO_BASETYPE (binfo, i);
+ /* Skip virtual bases. */
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ continue;
+ accumulate_vtbl_inits (base_binfo,
+ BINFO_BASETYPE (orig_binfo, i),
+ rtti_binfo,
+ t,
+ inits);
+ }
+}
+
+/* Called from finish_vtbls via dfs_walk when using the new ABI.
+ Accumulates the vtable initializers for all of the vtables into
+ TREE_VALUE (DATA). Returns the initializers for the BINFO vtable. */
+
+static tree
+dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
+ tree binfo;
+ tree orig_binfo;
+ tree rtti_binfo;
+ tree t;
+ tree l;
+{
+ tree inits = NULL_TREE;
+
+ if (BINFO_NEW_VTABLE_MARKED (orig_binfo, t))
+ {
+ tree vtbl;
+ tree index;
+ int non_fn_entries;
+
+ /* Compute the initializer for this vtable. */
+ inits = build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo,
+ &non_fn_entries);
+
+ /* Figure out the position to which the VPTR should point. */
+ vtbl = TREE_PURPOSE (l);
+ vtbl = build1 (ADDR_EXPR,
+ vtbl_ptr_type_node,
+ vtbl);
+ index = size_binop (PLUS_EXPR,
+ size_int (non_fn_entries),
+ size_int (list_length (TREE_VALUE (l))));
+ index = size_binop (MULT_EXPR,
+ TYPE_SIZE_UNIT (vtable_entry_type),
+ index);
+ vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, index);
+ TREE_CONSTANT (vtbl) = 1;
+
+ /* For an ordinary vtable, set BINFO_VTABLE. */
+ if (same_type_p (BINFO_TYPE (rtti_binfo), t))
+ BINFO_VTABLE (binfo) = vtbl;
+ /* For a construction vtable, we can't overwrite BINFO_VTABLE.
+ So, we make a TREE_LIST. Later, dfs_fixup_binfo_vtbls will
+ straighten this out. */
+ else
+ BINFO_VTABLE (binfo) =
+ tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
+ }
+
+ return inits;
+}
+
+/* Construct the initializer for BINFOs virtual function table. BINFO
+ is part of the hierarchy dominated by T. If we're building a
+ construction vtable, the ORIG_BINFO is the binfo we should use to
+ find the actual function pointers to put in the vtable. Otherwise,
+ ORIG_BINFO should be the same as BINFO. The RTTI_BINFO is the
+ BINFO that should be indicated by the RTTI information in the
+ vtable; it will be a base class of T, rather than T itself, if we
+ are building a construction vtable.
+
+ The value returned is a TREE_LIST suitable for wrapping in a
+ CONSTRUCTOR to use as the DECL_INITIAL for a vtable. If
+ NON_FN_ENTRIES_P is not NULL, *NON_FN_ENTRIES_P is set to the
+ number of non-function entries in the vtable.
+
+ It might seem that this function should never be called with a
+ BINFO for which BINFO_PRIMARY_MARKED_P holds, the vtable for such a
+ base is always subsumed by a derived class vtable. However, when
+ we are building construction vtables we do build vtables for
+ primary bases; we need these while the primary base is being
+ constructed. */
+
+static tree
+build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
+ tree binfo;
+ tree orig_binfo;
+ tree t;
+ tree rtti_binfo;
+ int *non_fn_entries_p;
+{
+ tree v;
+ tree vfun_inits;
+ tree vbase;
+ vtbl_init_data vid;
+
+ /* Initialize VID. */
+ bzero (&vid, sizeof (vid));
+ vid.binfo = binfo;
+ vid.derived = t;
+ vid.last_init = &vid.inits;
+ vid.primary_vtbl_p = (binfo == TYPE_BINFO (t));
+ vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
+ /* The first vbase or vcall offset is at index -3 in the vtable. */
+ vid.index = ssize_int (-3);
+
+ /* Add entries to the vtable for RTTI. */
+ build_rtti_vtbl_entries (binfo, rtti_binfo, &vid);
+
+ /* Create an array for keeping track of the functions we've
+ processed. When we see multiple functions with the same
+ signature, we share the vcall offsets. */
+ VARRAY_TREE_INIT (vid.fns, 32, "fns");
+ /* Add the vcall and vbase offset entries. */
+ build_vcall_and_vbase_vtbl_entries (binfo, &vid);
+ /* Clean up. */
+ VARRAY_FREE (vid.fns);
+ /* Clear BINFO_VTABLE_PAATH_MARKED; it's set by
+ build_vbase_offset_vtbl_entries. */
+ for (vbase = CLASSTYPE_VBASECLASSES (t);
+ vbase;
+ vbase = TREE_CHAIN (vbase))
+ CLEAR_BINFO_VTABLE_PATH_MARKED (TREE_VALUE (vbase));
+
+ if (non_fn_entries_p)
+ *non_fn_entries_p = list_length (vid.inits);
+
+ /* Go through all the ordinary virtual functions, building up
+ initializers. */
+ vfun_inits = NULL_TREE;
+ for (v = BINFO_VIRTUALS (orig_binfo); v; v = TREE_CHAIN (v))
+ {
+ tree delta;
+ tree vcall_index;
+ tree fn;
+ tree pfn;
+ tree init;
+
+ /* Pull the offset for `this', and the function to call, out of
+ the list. */
+ delta = BV_DELTA (v);
+
+ if (BV_USE_VCALL_INDEX_P (v))
+ {
+ vcall_index = BV_VCALL_INDEX (v);
+ my_friendly_assert (vcall_index != NULL_TREE, 20000621);
+ }
+ else
+ vcall_index = NULL_TREE;
+
+ fn = BV_FN (v);
+ my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
+ my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
+
+ /* You can't call an abstract virtual function; it's abstract.
+ So, we replace these functions with __pure_virtual. */
+ if (DECL_PURE_VIRTUAL_P (fn))
+ fn = abort_fndecl;
+
+ /* Take the address of the function, considering it to be of an
+ appropriate generic type. */
+ pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
+ /* The address of a function can't change. */
+ TREE_CONSTANT (pfn) = 1;
+ /* Enter it in the vtable. */
+ init = build_vtable_entry (delta, vcall_index, pfn,
+ BV_GENERATE_THUNK_WITH_VTABLE_P (v));
+ /* And add it to the chain of initializers. */
+ vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
+ }
+
+ /* The initializers for virtual functions were built up in reverse
+ order; straighten them out now. */
+ vfun_inits = nreverse (vfun_inits);
+
+ /* The negative offset initializers are also in reverse order. */
+ vid.inits = nreverse (vid.inits);
+
+ /* Chain the two together. */
+ return chainon (vid.inits, vfun_inits);
+}
+
+/* Sets vid->inits to be the initializers for the vbase and vcall
+ offsets in BINFO, which is in the hierarchy dominated by T. */
+
+static void
+build_vcall_and_vbase_vtbl_entries (binfo, vid)
+ tree binfo;
+ vtbl_init_data *vid;
+{
+ tree b;
+
+ /* If this is a derived class, we must first create entries
+ corresponding to the primary base class. */
+ b = get_primary_binfo (binfo);
+ if (b)
+ build_vcall_and_vbase_vtbl_entries (b, vid);
+
+ /* Add the vbase entries for this base. */
+ build_vbase_offset_vtbl_entries (binfo, vid);
+ /* Add the vcall entries for this base. */
+ build_vcall_offset_vtbl_entries (binfo, vid);
+}
+
+/* Returns the initializers for the vbase offset entries in the vtable
+ for BINFO (which is part of the class hierarchy dominated by T), in
+ reverse order. VBASE_OFFSET_INDEX gives the vtable index
+ where the next vbase offset will go. */
+
+static void
+build_vbase_offset_vtbl_entries (binfo, vid)
+ tree binfo;
+ vtbl_init_data *vid;
+{
+ tree vbase;
+ tree t;
+
+ /* Under the old ABI, pointers to virtual bases are stored in each
+ object. */
+ if (!vbase_offsets_in_vtable_p ())
+ return;
+
+ /* If there are no virtual baseclasses, then there is nothing to
+ do. */
+ if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
+ return;
+
+ t = vid->derived;
+
+ /* Go through the virtual bases, adding the offsets. */
+ for (vbase = TYPE_BINFO (BINFO_TYPE (binfo));
+ vbase;
+ vbase = TREE_CHAIN (vbase))
+ {
+ tree b;
+ tree delta;
+
+ if (!TREE_VIA_VIRTUAL (vbase))
+ continue;
+
+ /* Find the instance of this virtual base in the complete
+ object. */
+ b = binfo_for_vbase (BINFO_TYPE (vbase), t);
+
+ /* If we've already got an offset for this virtual base, we
+ don't need another one. */
+ if (BINFO_VTABLE_PATH_MARKED (b))
+ continue;
+ SET_BINFO_VTABLE_PATH_MARKED (b);
+
+ /* Figure out where we can find this vbase offset. */
+ delta = size_binop (MULT_EXPR,
+ vid->index,
+ convert (ssizetype,
+ TYPE_SIZE_UNIT (vtable_entry_type)));
+ if (vid->primary_vtbl_p)
+ BINFO_VPTR_FIELD (b) = delta;
+
+ if (binfo != TYPE_BINFO (t))
+ {
+ tree orig_vbase;
+
+ /* Find the instance of this virtual base in the type of BINFO. */
+ orig_vbase = binfo_for_vbase (BINFO_TYPE (vbase),
+ BINFO_TYPE (binfo));
+
+ /* The vbase offset had better be the same. */
+ if (!tree_int_cst_equal (delta,
+ BINFO_VPTR_FIELD (orig_vbase)))
+ my_friendly_abort (20000403);
+ }
+
+ /* The next vbase will come at a more negative offset. */
+ vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
+
+ /* The initializer is the delta from BINFO to this virtual base.
+ The vbase offsets go in reverse inheritance-graph order, and
+ we are walking in inheritance graph order so these end up in
+ the right order. */
+ delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo));
+ *vid->last_init
+ = build_tree_list (NULL_TREE,
+ fold (build1 (NOP_EXPR,
+ vtable_entry_type,
+ delta)));
+ vid->last_init = &TREE_CHAIN (*vid->last_init);
+ }
+}
+
+/* Adds the initializers for the vcall offset entries in the vtable
+ for BINFO (which is part of the class hierarchy dominated by T) to
+ VID->INITS. */
+
+static void
+build_vcall_offset_vtbl_entries (binfo, vid)
+ tree binfo;
+ vtbl_init_data *vid;
+{
+ /* Under the old ABI, the adjustments to the `this' pointer were made
+ elsewhere. */
+ if (!vcall_offsets_in_vtable_p ())
+ return;
+
+ /* We only need these entries if this base is a virtual base. */
+ if (!TREE_VIA_VIRTUAL (binfo))
+ return;
+
+ /* We need a vcall offset for each of the virtual functions in this
+ vtable. For example:
+
+ class A { virtual void f (); };
+ class B : virtual public A { };
+ class C: virtual public A, public B {};
+
+ Now imagine:
+
+ B* b = new C;
+ b->f();
+
+ The location of `A' is not at a fixed offset relative to `B'; the
+ offset depends on the complete object derived from `B'. So,
+ `B' vtable contains an entry for `f' that indicates by what
+ amount the `this' pointer for `B' needs to be adjusted to arrive
+ at `A'.
+
+ We need entries for all the functions in our primary vtable and
+ in our non-virtual bases vtables. */
+ vid->vbase = binfo;
+ /* Now, walk through the non-virtual bases, adding vcall offsets. */
+ add_vcall_offset_vtbl_entries_r (binfo, vid);
+}
+
+/* Build vcall offsets, starting with those for BINFO. */
+
+static void
+add_vcall_offset_vtbl_entries_r (binfo, vid)
+ tree binfo;
+ vtbl_init_data *vid;
+{
+ int i;
+ tree primary_binfo;
+
+ /* Don't walk into virtual bases -- except, of course, for the
+ virtual base for which we are building vcall offsets. */
+ if (TREE_VIA_VIRTUAL (binfo) && vid->vbase != binfo)
+ return;
+
+ /* If BINFO has a primary base, process it first. */
+ primary_binfo = get_primary_binfo (binfo);
+ if (primary_binfo)
+ add_vcall_offset_vtbl_entries_r (primary_binfo, vid);
+
+ /* Add BINFO itself to the list. */
+ add_vcall_offset_vtbl_entries_1 (binfo, vid);
+
+ /* Scan the non-primary bases of BINFO. */
+ for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+ {
+ tree base_binfo;
+
+ base_binfo = BINFO_BASETYPE (binfo, i);
+ if (base_binfo != primary_binfo)
+ add_vcall_offset_vtbl_entries_r (base_binfo, vid);
+ }
+}
+
+/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
+
+static void
+add_vcall_offset_vtbl_entries_1 (binfo, vid)
+ tree binfo;
+ vtbl_init_data* vid;
+{
+ tree derived_virtuals;
+ tree base_virtuals;
+ tree orig_virtuals;
+ tree binfo_inits;
+ /* If BINFO is a primary base, this is the least derived class of
+ BINFO that is not a primary base. */
+ tree non_primary_binfo;
+
+ binfo_inits = NULL_TREE;
+
+ /* We might be a primary base class. Go up the inheritance
+ hierarchy until we find the class of which we are a primary base:
+ it is the BINFO_VIRTUALS there that we need to consider. */
+ non_primary_binfo = binfo;
+ while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
+ {
+ tree b;
+
+ /* If we have reached a virtual base, then it must be the
+ virtual base for which we are building vcall offsets. In
+ turn, the virtual base must be a (possibly indirect) primary
+ base of the class that we are initializing, or we wouldn't
+ care about its vtable offsets. */
+ if (TREE_VIA_VIRTUAL (non_primary_binfo))
+ {
+ non_primary_binfo = vid->binfo;
+ break;
+ }
+
+ b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+ if (get_primary_binfo (b) != non_primary_binfo)
+ break;
+ non_primary_binfo = b;
+ }
+
+ /* Make entries for the rest of the virtuals. */
+ for (base_virtuals = BINFO_VIRTUALS (binfo),
+ derived_virtuals = BINFO_VIRTUALS (non_primary_binfo),
+ orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
+ base_virtuals;
+ base_virtuals = TREE_CHAIN (base_virtuals),
+ derived_virtuals = TREE_CHAIN (derived_virtuals),
+ orig_virtuals = TREE_CHAIN (orig_virtuals))
+ {
+ tree orig_fn;
+ tree fn;
+ tree base;
+ tree base_binfo;
+ size_t i;
+
+ /* Find the declaration that originally caused this function to
+ be present. */
+ orig_fn = BV_FN (orig_virtuals);
+
+ /* We do not need an entry if this function is declared in a
+ virtual base (or one of its virtual bases), and not
+ overridden in the section of the hierarchy dominated by the
+ virtual base for which we are building vcall offsets. */
+ if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo)))
+ continue;
+
+ /* Find the overriding function. */
+ fn = BV_FN (derived_virtuals);
+
+ /* If there is already an entry for a function with the same
+ signature as FN, then we do not need a second vcall offset.
+ Check the list of functions already present in the derived
+ class vtable. */
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i)
+ {
+ tree derived_entry;
+
+ derived_entry = VARRAY_TREE (vid->fns, i);
+ if (same_signature_p (BV_FN (derived_entry), fn))
+ {
+ BV_VCALL_INDEX (derived_virtuals)
+ = BV_VCALL_INDEX (derived_entry);
+ break;
+ }
+ }
+ if (i != VARRAY_ACTIVE_SIZE (vid->fns))
+ continue;
+
+ /* The FN comes from BASE. So, we must caculate the adjustment
+ from the virtual base that derived from BINFO to BASE. */
+ base = DECL_CONTEXT (fn);
+ base_binfo = get_binfo (base, vid->derived, /*protect=*/0);
+
+ /* Compute the vcall offset. */
+ *vid->last_init
+ = (build_tree_list
+ (NULL_TREE,
+ fold (build1 (NOP_EXPR, vtable_entry_type,
+ size_diffop (BINFO_OFFSET (base_binfo),
+ BINFO_OFFSET (vid->vbase))))));
+ vid->last_init = &TREE_CHAIN (*vid->last_init);
+
+ /* Keep track of the vtable index where this vcall offset can be
+ found. For a construction vtable, we already made this
+ annotation when we build the original vtable. */
+ if (!vid->ctor_vtbl_p)
+ BV_VCALL_INDEX (derived_virtuals) = vid->index;
+
+ /* The next vcall offset will be found at a more negative
+ offset. */
+ vid->index = size_binop (MINUS_EXPR, vid->index, ssize_int (1));
+
+ /* Keep track of this function. */
+ VARRAY_PUSH_TREE (vid->fns, derived_virtuals);
+ }
+}
+
+/* Return vtbl initializers for the RTTI entries coresponding to the
+ BINFO's vtable. The RTTI entries should indicate the object given
+ by RTTI_BINFO. */
+
+static void
+build_rtti_vtbl_entries (binfo, rtti_binfo, vid)
+ tree binfo;
+ tree rtti_binfo;
+ vtbl_init_data *vid;
+{
+ tree b;
+ tree t;
+ tree basetype;
+ tree offset;
+ tree decl;
+ tree init;
+
+ basetype = BINFO_TYPE (binfo);
+ t = BINFO_TYPE (rtti_binfo);
+
+ /* For a COM object there is no RTTI entry. */
+ if (CLASSTYPE_COM_INTERFACE (basetype))
+ return;
+
+ /* To find the complete object, we will first convert to our most
+ primary base, and then add the offset in the vtbl to that value. */
+ b = binfo;
+ while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b)))
+ {
+ tree primary_base;
+
+ primary_base = get_primary_binfo (b);
+ if (!BINFO_PRIMARY_MARKED_P (primary_base))
+ break;
+ b = primary_base;
+ }
+ offset = size_diffop (BINFO_OFFSET (rtti_binfo), BINFO_OFFSET (b));
+
+ /* The second entry is, in the case of the new ABI, the address of
+ the typeinfo object, or, in the case of the old ABI, a function
+ which returns a typeinfo object. */
+ if (new_abi_rtti_p ())
+ {
+ if (flag_rtti)
+ decl = build_unary_op (ADDR_EXPR, get_tinfo_decl (t), 0);
+ else
+ decl = integer_zero_node;
+
+ /* Convert the declaration to a type that can be stored in the
+ vtable. */
+ init = build1 (NOP_EXPR, vfunc_ptr_type_node, decl);
+ TREE_CONSTANT (init) = 1;
+ }
+ else
+ {
+ if (flag_rtti)
+ decl = get_tinfo_decl (t);
+ else
+ decl = abort_fndecl;
+
+ /* Convert the declaration to a type that can be stored in the
+ vtable. */
+ init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl);
+ TREE_CONSTANT (init) = 1;
+ init = build_vtable_entry (offset, NULL_TREE, init,
+ /*generate_with_vtable_p=*/0);
+ }
+ *vid->last_init = build_tree_list (NULL_TREE, init);
+ vid->last_init = &TREE_CHAIN (*vid->last_init);
+
+ /* Add the offset-to-top entry. It comes earlier in the vtable that
+ the the typeinfo entry. */
+ if (flag_vtable_thunks)
+ {
+ /* Convert the offset to look like a function pointer, so that
+ we can put it in the vtable. */
+ init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
+ TREE_CONSTANT (init) = 1;
+ *vid->last_init = build_tree_list (NULL_TREE, init);
+ vid->last_init = &TREE_CHAIN (*vid->last_init);
+ }
+}
+
+/* Build an entry in the virtual function table. DELTA is the offset
+ for the `this' pointer. VCALL_INDEX is the vtable index containing
+ the vcall offset; zero if none. ENTRY is the virtual function
+ table entry itself. It's TREE_TYPE must be VFUNC_PTR_TYPE_NODE,
+ but it may not actually be a virtual function table pointer. (For
+ example, it might be the address of the RTTI object, under the new
+ ABI.) */
+
+static tree
+build_vtable_entry (delta, vcall_index, entry, generate_with_vtable_p)
+ tree delta;
+ tree vcall_index;
+ tree entry;
+ int generate_with_vtable_p;
+{
+ if (flag_vtable_thunks)
+ {
+ tree fn;
+
+ fn = TREE_OPERAND (entry, 0);
+ if ((!integer_zerop (delta) || vcall_index != NULL_TREE)
+ && fn != abort_fndecl
+ && !DECL_TINFO_FN_P (fn))
+ {
+ entry = make_thunk (entry, delta, vcall_index,
+ generate_with_vtable_p);
+ entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
+ TREE_READONLY (entry) = 1;
+ TREE_CONSTANT (entry) = 1;
+ }
+#ifdef GATHER_STATISTICS
+ n_vtable_entries += 1;
+#endif
+ return entry;
+ }
+ else
+ {
+ tree elems = tree_cons (NULL_TREE, delta,
+ tree_cons (NULL_TREE, integer_zero_node,
+ build_tree_list (NULL_TREE, entry)));
+ tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
+
+ /* We don't use vcall offsets when not using vtable thunks. */
+ my_friendly_assert (vcall_index == NULL_TREE, 20000125);
+
+ /* DELTA used to be constructed by `size_int' and/or size_binop,
+ which caused overflow problems when it was negative. That should
+ be fixed now. */
+
+ if (! int_fits_type_p (delta, delta_type_node))
+ {
+ if (flag_huge_objects)
+ sorry ("object size exceeds built-in limit for virtual function table implementation");
+ else
+ sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
+ }
+
+ TREE_CONSTANT (entry) = 1;
+ TREE_STATIC (entry) = 1;
+ TREE_READONLY (entry) = 1;
+
+#ifdef GATHER_STATISTICS
+ n_vtable_entries += 1;
+#endif
+
+ return entry;
+ }