/* Breadth-first and depth-first routines for
searching multiple-inheritance lattice for GNU C++.
- Copyright (C) 1987, 89, 92-97, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-97, 1998, 1999, 2000 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
#define search_level stack_level
static struct search_level *search_stack;
-static tree get_abstract_virtuals_1 PROTO((tree, int, tree));
static tree next_baselink PROTO((tree));
static tree get_vbase_1 PROTO((tree, tree, unsigned int *));
-static tree convert_pointer_to_vbase PROTO((tree, tree));
static tree lookup_field_1 PROTO((tree, tree));
static tree convert_pointer_to_single_level PROTO((tree, tree));
static int lookup_fnfields_here PROTO((tree, tree));
static int get_base_distance_recursive
PROTO((tree, int, int, int, int *, tree *, tree,
int, int *, int, int));
+static int dynamic_cast_base_recurse PROTO((tree, tree, int, tree *));
static void expand_upcast_fixups
PROTO((tree, tree, tree, tree, tree, tree, tree *));
static void fixup_virtual_upcast_offsets
PROTO((tree, tree, int, int, tree, tree, tree, tree,
tree *));
-static tree unmarkedp PROTO((tree, void *));
static tree marked_vtable_pathp PROTO((tree, void *));
static tree unmarked_vtable_pathp PROTO((tree, void *));
static tree marked_new_vtablep PROTO((tree, void *));
static tree unmarked_new_vtablep PROTO((tree, void *));
static tree marked_pushdecls_p PROTO((tree, void *));
static tree unmarked_pushdecls_p PROTO((tree, void *));
+#if 0
static tree dfs_debug_unmarkedp PROTO((tree, void *));
static tree dfs_debug_mark PROTO((tree, void *));
+#endif
static tree dfs_find_vbases PROTO((tree, void *));
static tree dfs_clear_vbase_slots PROTO((tree, void *));
static tree dfs_init_vbase_pointers PROTO((tree, void *));
tree (*) (tree, void *),
tree (*) (tree, void *),
void *));
-static tree dfs_bfv_queue_p PROTO ((tree, void *));
-static tree dfs_bfv_helper PROTO ((tree, void *));
static tree get_virtuals_named_this_r PROTO ((tree, void *));
static tree context_for_name_lookup PROTO ((tree));
static tree canonical_binfo PROTO ((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 fixup_all_virtual_upcast_offsets PROTO ((tree, tree));
+static tree dfs_mark_primary_bases PROTO((tree, void *));
+static tree get_shared_vbase_if_not_primary PROTO((tree, tree));
/* Allocate a level of searching. */
EXPR is a non-null POINTER_TYPE to RECORD_TYPE. We also know that
the type of what expr points to has a virtual base of type TYPE. */
-static tree
+tree
convert_pointer_to_vbase (type, expr)
tree type;
tree expr;
tree, deal with it. This happens when we are called from
expand_upcast_fixups. */
if (rval == -1 && TREE_CODE (parent) == TREE_VEC
- && parent == binfo_member (BINFO_TYPE (parent),
- CLASSTYPE_VBASECLASSES (type)))
+ && parent == BINFO_FOR_VBASE (BINFO_TYPE (parent), type))
{
my_friendly_assert (BINFO_INHERITANCE_CHAIN (parent) == binfo, 980827);
new_binfo = parent;
return rval;
}
+/* Worker function for get_dynamic_cast_base_type. */
+
+static int
+dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
+ tree subtype;
+ tree binfo;
+ int via_virtual;
+ tree *offset_ptr;
+{
+ tree binfos;
+ int i, n_baselinks;
+ int worst = -3;
+
+ if (BINFO_TYPE (binfo) == subtype)
+ {
+ if (via_virtual)
+ return -2;
+ else
+ {
+ *offset_ptr = BINFO_OFFSET (binfo);
+ return 0;
+ }
+ }
+
+ binfos = BINFO_BASETYPES (binfo);
+ n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ int rval;
+
+ if (!TREE_VIA_PUBLIC (base_binfo))
+ continue;
+ rval = dynamic_cast_base_recurse
+ (subtype, base_binfo,
+ via_virtual || TREE_VIA_VIRTUAL (base_binfo), offset_ptr);
+ if (worst == -3)
+ worst = rval;
+ else if (rval >= 0)
+ worst = worst >= 0 ? -1 : worst;
+ else if (rval > -3)
+ worst = worst < rval ? worst : rval;
+ }
+ return worst;
+}
+
+/* The dynamic cast runtime needs a hint about how the static SUBTYPE type started
+ from is related to the required TARGET type, in order to optimize the
+ inheritance graph search. This information is independant of the
+ current context, and ignores private paths, hence get_base_distance is
+ inappropriate. Return a TREE specifying the base offset, BOFF.
+ BOFF >= 0, there is only one public non-virtual SUBTYPE base at offset BOFF,
+ and there are no public virtual SUBTYPE bases.
+ BOFF == -1, SUBTYPE occurs as multiple public non-virtual bases.
+ BOFF == -2, SUBTYPE occurs as multiple public virtual or non-virtual bases.
+ BOFF == -3, SUBTYPE is not a public base. */
+
+tree
+get_dynamic_cast_base_type (subtype, target)
+ tree subtype;
+ tree target;
+{
+ tree offset = NULL_TREE;
+ int boff = dynamic_cast_base_recurse (subtype, TYPE_BINFO (target),
+ 0, &offset);
+
+ if (!boff)
+ return offset;
+ return build_int_2 (boff, -1);
+}
+
/* Search for a member with name NAME in a multiple inheritance lattice
specified by TYPE. If it does not exist, return NULL_TREE.
If the member is ambiguously referenced, return `error_mark_node'.
else if (DECL_NAME (fields[i]) < name)
lo = i + 1;
else
- return fields[i];
+ {
+ /* We might have a nested class and a field with the
+ same name; we sorted them appropriately via
+ field_decl_cmp, so just look for the last field with
+ this name. */
+ while (i + 1 < hi
+ && DECL_NAME (fields[i+1]) == name)
+ ++i;
+ return fields[i];
+ }
}
return NULL_TREE;
}
if (name == vptr_identifier)
{
/* Give the user what s/he thinks s/he wants. */
- if (TYPE_VIRTUAL_P (type))
- return CLASSTYPE_VFIELD (type);
+ if (TYPE_POLYMORPHIC_P (type))
+ return TYPE_VFIELD (type);
}
return NULL_TREE;
}
void *data;
{
binfo = canonical_binfo (binfo);
- return markedp (binfo, data) ? binfo : NULL_TREE;
+ return markedp (binfo, data);
}
/* If BINFO is not marked, return a canonical version of BINFO.
void *data;
{
binfo = canonical_binfo (binfo);
- return unmarkedp (binfo, data) ? binfo : NULL_TREE;
+ return unmarkedp (binfo, data);
}
/* Called from access_in_type via dfs_walk. Calculate the access to
return NULL_TREE;
if (TREE_VIA_VIRTUAL (binfo))
- return binfo_member (BINFO_TYPE (binfo),
- CLASSTYPE_VBASECLASSES (lfi->type));
+ return BINFO_FOR_VBASE (BINFO_TYPE (binfo), lfi->type);
else
return binfo;
}
/* This is the first time we noticed an ambiguity. Add
what we previously thought was a reasonable candidate
to the list. */
- lfi->ambiguous = scratch_tree_cons (NULL_TREE, lfi->rval,
- NULL_TREE);
+ lfi->ambiguous = tree_cons (NULL_TREE, lfi->rval, NULL_TREE);
TREE_TYPE (lfi->ambiguous) = error_mark_node;
}
/* Add the new value. */
- lfi->ambiguous = scratch_tree_cons (NULL_TREE, nval,
- lfi->ambiguous);
+ lfi->ambiguous = tree_cons (NULL_TREE, nval, lfi->ambiguous);
TREE_TYPE (lfi->ambiguous) = error_mark_node;
lfi->errstr = "request for member `%D' is ambiguous";
}
if (rval && is_overloaded_fn (rval))
{
- rval = scratch_tree_cons (basetype_path, rval, NULL_TREE);
+ rval = tree_cons (basetype_path, rval, NULL_TREE);
SET_BASELINK_P (rval);
}
idx = lookup_fnfields_here (BINFO_TYPE (binfo), gvnti->name);
if (idx >= 0)
gvnti->fields
- = scratch_tree_cons (binfo,
- TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type),
- idx),
- gvnti->fields);
+ = tree_cons (binfo,
+ TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx),
+ gvnti->fields);
return NULL_TREE;
}
}
}
-/* Return the list of virtual functions which are abstract in type
- TYPE that come from non virtual base classes. See
- expand_direct_vtbls_init for the style of search we do. */
+/* A queue function for dfs_walk that skips any nonprimary virtual
+ bases and any already marked bases. */
+
+tree
+dfs_skip_nonprimary_vbases_unmarkedp (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+ /* This is a non-primary virtual base. SKip it. */
+ return NULL_TREE;
+
+ return unmarkedp (binfo, NULL);
+}
+
+/* A queue function for dfs_walk that skips any nonprimary virtual
+ bases and any unmarked bases. */
+
+tree
+dfs_skip_nonprimary_vbases_markedp (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+ /* This is a non-primary virtual base. SKip it. */
+ return NULL_TREE;
+
+ return markedp (binfo, NULL);
+}
+
+/* Called via dfs_walk from mark_primary_bases. */
static tree
-get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
+dfs_mark_primary_bases (binfo, data)
tree binfo;
- int do_self;
- tree abstract_virtuals;
+ void *data;
{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ int i;
+ tree base_binfo;
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable
- = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
- if (! TREE_VIA_VIRTUAL (base_binfo))
- abstract_virtuals
- = get_abstract_virtuals_1 (base_binfo, is_not_base_vtable,
- abstract_virtuals);
- }
- /* Should we use something besides CLASSTYPE_VFIELDS? */
- if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
+ if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
+ return NULL_TREE;
+
+ i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ base_binfo = BINFO_BASETYPE (binfo, i);
+
+ if (!TREE_VIA_VIRTUAL (base_binfo))
+ /* Non-virtual base classes are easy. */
+ BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
+ else
{
- tree virtuals = BINFO_VIRTUALS (binfo);
+ tree shared_binfo;
- skip_rtti_stuff (&virtuals, BINFO_TYPE (binfo));
+ shared_binfo
+ = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data);
- while (virtuals)
+ /* If this virtual base is not already primary somewhere else in
+ the hiearchy, then we'll be using this copy. */
+ if (!BINFO_VBASE_PRIMARY_P (shared_binfo)
+ && !BINFO_VBASE_MARKED (shared_binfo))
{
- tree base_fndecl = TREE_VALUE (virtuals);
- if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
- abstract_virtuals = tree_cons (NULL_TREE, base_fndecl,
- abstract_virtuals);
- virtuals = TREE_CHAIN (virtuals);
+ BINFO_VBASE_PRIMARY_P (shared_binfo) = 1;
+ BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
}
}
- return abstract_virtuals;
+
+ return NULL_TREE;
+}
+
+/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy
+ dominated by BINFO that are primary bases. */
+
+void
+mark_primary_bases (type)
+ tree type;
+{
+ tree vbase;
+
+ /* Mark the TYPE_BINFO hierarchy. */
+ dfs_walk (TYPE_BINFO (type), dfs_mark_primary_bases,
+ dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+ /* Now go through the virtual base classes. Any that are not
+ already primary will need to be allocated in TYPE, and so we need
+ to mark their primary bases. */
+ for (vbase = CLASSTYPE_VBASECLASSES (type);
+ vbase;
+ vbase = TREE_CHAIN (vbase))
+ {
+ if (BINFO_VBASE_PRIMARY_P (vbase))
+ /* This virtual base was already included in the hierarchy, so
+ there's nothing to do here. */
+ continue;
+
+ /* Temporarily pretend that VBASE is primary so that its bases
+ will be walked; this is the real copy of VBASE. */
+ BINFO_PRIMARY_MARKED_P (vbase) = 1;
+
+ /* Now, walk its bases. */
+ dfs_walk (vbase, dfs_mark_primary_bases,
+ dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+ /* VBASE wasn't really primary. */
+ BINFO_PRIMARY_MARKED_P (vbase) = 0;
+ /* And we don't want to allow it to *become* primary if it is a
+ base of some subsequent base class. */
+ SET_BINFO_VBASE_MARKED (vbase);
+ }
+
+ /* Clear the VBASE_MARKED bits we set above. */
+ for (vbase = CLASSTYPE_VBASECLASSES (type);
+ vbase;
+ vbase = TREE_CHAIN (vbase))
+ CLEAR_BINFO_VBASE_MARKED (vbase);
+}
+
+/* If BINFO is a non-primary virtual baseclass (in the hierarchy
+ dominated by TYPE), and no primary copy appears anywhere in the
+ hierarchy, return the shared copy. If a primary copy appears
+ elsewhere, return NULL_TREE. Otherwise, return BINFO itself; it is
+ either a non-virtual base or a primary virtual base. */
+
+static tree
+get_shared_vbase_if_not_primary (binfo, type)
+ tree binfo;
+ tree type;
+{
+ if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+ {
+ /* This is a non-primary virtual base. If there is no primary
+ version, get the shared version. */
+ binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), type);
+ if (BINFO_VBASE_PRIMARY_P (binfo))
+ return NULL_TREE;
+ }
+
+ return binfo;
}
-/* Return the list of virtual functions which are abstract in type TYPE.
- This information is cached, and so must be built on a
- non-temporary obstack. */
+/* A queue function to use with dfs_walk that prevents travel into any
+ nonprimary virtual base, or its baseclasses. DATA should be the
+ type of the complete object, or a TREE_LIST whose TREE_PURPOSE is
+ the type of the complete object. By using this function as a queue
+ function, you will walk over exactly those BINFOs that actually
+ exist in the complete object, including those for virtual base
+ classes. If you SET_BINFO_MARKED for each binfo you process, you
+ are further guaranteed that you will walk into each virtual base
+ class exactly once. */
tree
-get_abstract_virtuals (type)
- tree type;
+dfs_unmarked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
{
- tree vbases;
- tree abstract_virtuals = NULL;
+ tree type = (tree) data;
- /* First get all from non-virtual bases. */
- abstract_virtuals
- = get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals);
-
- for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases))
+ if (TREE_CODE (type) == TREE_LIST)
+ type = TREE_PURPOSE (type);
+ binfo = get_shared_vbase_if_not_primary (binfo, type);
+ return binfo ? unmarkedp (binfo, NULL) : NULL_TREE;
+}
+
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+ that are marked, rather than unmarked. */
+
+tree
+dfs_marked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ tree type = (tree) data;
+
+ if (TREE_CODE (type) == TREE_LIST)
+ type = TREE_PURPOSE (type);
+ binfo = get_shared_vbase_if_not_primary (binfo, type);
+ return binfo ? markedp (binfo, NULL) : NULL_TREE;
+}
+
+/* Called via dfs_walk from dfs_get_pure_virtuals. */
+
+static tree
+dfs_get_pure_virtuals (binfo, data)
+ tree binfo;
+ void *data;
+{
+ tree type = (tree) data;
+
+ /* We're not interested in primary base classes; the derived class
+ of which they are a primary base will contain the information we
+ need. */
+ if (!BINFO_PRIMARY_MARKED_P (binfo))
{
- tree virtuals = BINFO_VIRTUALS (vbases);
+ tree virtuals;
+
+ for (virtuals = skip_rtti_stuff (binfo,
+ BINFO_TYPE (binfo),
+ NULL);
+ virtuals;
+ virtuals = TREE_CHAIN (virtuals))
+ if (DECL_PURE_VIRTUAL_P (TREE_VALUE (virtuals)))
+ CLASSTYPE_PURE_VIRTUALS (type)
+ = tree_cons (NULL_TREE, TREE_VALUE (virtuals),
+ CLASSTYPE_PURE_VIRTUALS (type));
+ }
+
+ SET_BINFO_MARKED (binfo);
- skip_rtti_stuff (&virtuals, BINFO_TYPE (vbases));
+ return NULL_TREE;
+}
- while (virtuals)
+/* Set CLASSTYPE_PURE_VIRTUALS for TYPE. */
+
+void
+get_pure_virtuals (type)
+ tree type;
+{
+ tree vbases;
+
+ /* Clear the CLASSTYPE_PURE_VIRTUALS list; whatever is already there
+ is going to be overridden. */
+ CLASSTYPE_PURE_VIRTUALS (type) = NULL_TREE;
+ /* Now, run through all the bases which are not primary bases, and
+ collect the pure virtual functions. We look at the vtable in
+ each class to determine what pure virtual functions are present.
+ (A primary base is not interesting because the derived class of
+ which it is a primary base will contain vtable entries for the
+ pure virtuals in the base class. */
+ dfs_walk (TYPE_BINFO (type), dfs_get_pure_virtuals,
+ dfs_unmarked_real_bases_queue_p, type);
+ dfs_walk (TYPE_BINFO (type), dfs_unmark,
+ dfs_marked_real_bases_queue_p, type);
+
+ /* Put the pure virtuals in dfs order. */
+ CLASSTYPE_PURE_VIRTUALS (type) = nreverse (CLASSTYPE_PURE_VIRTUALS (type));
+
+ for (vbases = CLASSTYPE_VBASECLASSES (type);
+ vbases;
+ vbases = TREE_CHAIN (vbases))
+ {
+ tree virtuals;
+
+ for (virtuals = skip_rtti_stuff (vbases, BINFO_TYPE (vbases), NULL);
+ virtuals;
+ virtuals = TREE_CHAIN (virtuals))
{
tree base_fndecl = TREE_VALUE (virtuals);
if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
cp_error ("`%#D' needs a final overrider", base_fndecl);
- else if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
- abstract_virtuals = tree_cons (NULL_TREE, base_fndecl,
- abstract_virtuals);
- virtuals = TREE_CHAIN (virtuals);
}
}
- return nreverse (abstract_virtuals);
}
static tree
return NULL_TREE;
}
-tree markedp (binfo, data)
+tree
+markedp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
return BINFO_MARKED (binfo) ? binfo : NULL_TREE;
}
-static tree
+tree
unmarkedp (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
#if 0
static int dfs_search_slot_nonempty_p (binfo) tree binfo;
{ return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) != 0; }
-#endif
static tree
dfs_debug_unmarkedp (binfo, data)
return (!CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo))
? binfo : NULL_TREE);
}
+#endif
/* The worker functions for `dfs_walk'. These do not need to
test anything (vis a vis marking) if they are paired with
return NULL_TREE;
}
+/* Clear both BINFO_MARKED and BINFO_VBASE_MARKED. */
+
+tree
+dfs_vbase_unmark (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ CLEAR_BINFO_VBASE_MARKED (binfo);
+ return dfs_unmark (binfo, data);
+}
+
#if 0
static void
dfs_mark_vtable_path (binfo) tree binfo;
static void
dfs_clear_search_slot (binfo) tree binfo;
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
-#endif
+/* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". Currently, we only suppress debug
+ info if we can emit it with the vtable. jason 1999-11-11) */
static tree
dfs_debug_mark (binfo, data)
tree binfo;
{
tree t = BINFO_TYPE (binfo);
- /* Use heuristic that if there are virtual functions,
- ignore until we see a non-inline virtual function. */
- tree methods = CLASSTYPE_METHOD_VEC (t);
-
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
- if (methods == 0)
- return NULL_TREE;
-
/* If interface info is known, either we've already emitted the debug
info or we don't need to. */
if (CLASSTYPE_INTERFACE_KNOWN (t))
return NULL_TREE;
- /* If debug info is requested from this context for this type, supply it.
- If debug info is requested from another context for this type,
- see if some third context can supply it. */
- if (current_function_decl == NULL_TREE
- || DECL_CLASS_CONTEXT (current_function_decl) != t)
- {
- if (TREE_VEC_ELT (methods, 1))
- methods = TREE_VEC_ELT (methods, 1);
- else if (TREE_VEC_ELT (methods, 0))
- methods = TREE_VEC_ELT (methods, 0);
- else
- methods = TREE_VEC_ELT (methods, 2);
- methods = OVL_CURRENT (methods);
- while (methods)
- {
- if (DECL_VINDEX (methods)
- && DECL_THIS_INLINE (methods) == 0
- && DECL_ABSTRACT_VIRTUAL_P (methods) == 0)
- {
- /* Somebody, somewhere is going to have to define this
- virtual function. When they do, they will provide
- the debugging info. */
- return NULL_TREE;
- }
- methods = TREE_CHAIN (methods);
- }
- }
+ /* If the class has virtual functions, we'll emit the debug info
+ with the vtable. */
+ if (TYPE_POLYMORPHIC_P (t))
+ return NULL_TREE;
+
/* We cannot rely on some alien method to solve our problems,
so we must write out the debug info ourselves. */
TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
return NULL_TREE;
}
+#endif
\f
struct vbase_info
{
{
struct vbase_info *vi = (struct vbase_info *) data;
tree type = BINFO_TYPE (binfo);
- tree fields = TYPE_FIELDS (type);
+ tree fields;
tree this_vbase_ptr;
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
-#if 0
- /* See finish_struct_1 for when we can enable this. */
- /* If we have a vtable pointer first, skip it. */
- if (VFIELD_NAME_P (DECL_NAME (fields)))
- fields = TREE_CHAIN (fields);
-#endif
-
if (BINFO_INHERITANCE_CHAIN (binfo))
{
this_vbase_ptr = TREE_CHAIN (BINFO_INHERITANCE_CHAIN (binfo));
else
this_vbase_ptr = TREE_CHAIN (binfo);
+ /* We're going to iterate through all the pointers to virtual
+ base-classes. They come at the beginning of the class. */
+ fields = TYPE_FIELDS (type);
+ if (fields == TYPE_VFIELD (type))
+ /* If the first field is the vtbl pointer (as happens in the new
+ ABI), skip it. */
+ fields = TREE_CHAIN (fields);
+
if (fields == NULL_TREE
|| DECL_NAME (fields) == NULL_TREE
|| ! VBASE_NAME_P (DECL_NAME (fields)))
/* Not sure if checking path == vbase is necessary here, but just in
case it is. */
if (TREE_VIA_VIRTUAL (path) || path == vbase)
- return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t));
+ return BINFO_FOR_VBASE (BINFO_TYPE (path), t);
path = BINFO_INHERITANCE_CHAIN (path);
}
}
vbase_offsets)
tree binfo, addr, orig_addr, vbase, vbase_addr, t, *vbase_offsets;
{
- tree virtuals = BINFO_VIRTUALS (binfo);
+ tree virtuals;
tree vc;
tree delta;
unsigned HOST_WIDE_INT n;
*vbase_offsets = delta;
}
- n = skip_rtti_stuff (&virtuals, BINFO_TYPE (binfo));
+ virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
while (virtuals)
{
DECL_ARTIFICIAL (nvtbl) = 1;
nvtbl = pushdecl (nvtbl);
init = NULL_TREE;
- cp_finish_decl (nvtbl, init, NULL_TREE, 0,
+ cp_finish_decl (nvtbl, init, NULL_TREE,
LOOKUP_ONLYCONVERTING);
/* We don't set DECL_VIRTUAL_P and DECL_CONTEXT on nvtbl
init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
nvtbl, vtbl);
- TREE_SIDE_EFFECTS (init) = 1;
- expand_expr_stmt (init);
+ finish_expr_stmt (init);
/* Update the vtable pointers as necessary. */
ref = build_vfield_ref
(build_indirect_ref (addr, NULL_PTR),
- DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
- expand_expr_stmt
+ DECL_CONTEXT (TYPE_VFIELD (BINFO_TYPE (binfo))));
+ finish_expr_stmt
(build_modify_expr (ref, NOP_EXPR, nvtbl));
}
assemble_external (vtbl);
cp_build_qualified_type (TREE_TYPE (new_delta),
CP_TYPE_QUALS (TREE_TYPE (new_delta))
& ~TYPE_QUAL_CONST);
- expand_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
+ finish_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
old_delta));
}
++n;
}
}
-/* 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.
+/* Fixup all the virtual upcast offsets for TYPE. DECL_PTR is the
+ address of the sub-object being initialized. */
- 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. */
+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)
+expand_indirect_vtbls_init (binfo, decl_ptr)
tree binfo;
- tree true_exp, decl_ptr;
+ tree decl_ptr;
{
tree type = BINFO_TYPE (binfo);
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)
- : decl_ptr);
+ vi.decl_ptr = 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;
-
- addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vi.decl_ptr);
-
- /* Do all vtables from this virtual base. */
- /* This assumes that virtual bases can never serve as parent
- 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 = lookup_name (in_charge_identifier, 0);
- 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 ();
- }
-
+ fixup_all_virtual_upcast_offsets (type, vi.decl_ptr);
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
}
}
tree binfo;
void *data;
{
- tree *vbase_types = (tree *) data;
+ tree type = (tree) data;
if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
{
- tree new_vbase = make_binfo (integer_zero_node, binfo,
+ tree new_vbase = make_binfo (integer_zero_node,
+ BINFO_TYPE (binfo),
BINFO_VTABLE (binfo),
BINFO_VIRTUALS (binfo));
- TREE_CHAIN (new_vbase) = *vbase_types;
+ unshare_base_binfos (new_vbase);
TREE_VIA_VIRTUAL (new_vbase) = 1;
- *vbase_types = new_vbase;
+ BINFO_INHERITANCE_CHAIN (new_vbase) = TYPE_BINFO (type);
+ TREE_CHAIN (new_vbase) = CLASSTYPE_VBASECLASSES (type);
+ CLASSTYPE_VBASECLASSES (type) = new_vbase;
SET_BINFO_VBASE_MARKED (binfo);
}
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
-/* Return a list of binfos for the virtual base classes for TYPE, in
- depth-first search order. The list is freshly allocated, so
- no modification is made to the current binfo hierarchy. */
+/* Set CLASSTYPE_VBASECLASSES for TYPE. */
-tree
+void
get_vbase_types (type)
tree type;
{
- tree vbase_types;
- tree vbases;
- tree binfo;
-
- binfo = TYPE_BINFO (type);
- vbase_types = NULL_TREE;
- dfs_walk (binfo, dfs_get_vbase_types, unmarkedp, &vbase_types);
- dfs_walk (binfo, dfs_unmark, markedp, 0);
+ CLASSTYPE_VBASECLASSES (type) = NULL_TREE;
+ dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp, type);
/* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now
reverse it so that we get normal dfs ordering. */
- vbase_types = nreverse (vbase_types);
+ CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
+ dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0);
+}
+\f
+/* Debug info for C++ classes can get very large; try to avoid
+ emitting it everywhere.
- /* unmark marked vbases */
- for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
- CLEAR_BINFO_VBASE_MARKED (vbases);
+ Note that this optimization wins even when the target supports
+ BINCL (if only slightly), and reduces the amount of work for the
+ linker. */
- return vbase_types;
+void
+maybe_suppress_debug_info (t)
+ tree t;
+{
+ /* We can't do the usual TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
+ does not support name references between translation units. It supports
+ symbolic references between translation units, but only within a single
+ executable or shared library.
+
+ For DWARF 2, we handle TYPE_DECL_SUPPRESS_DEBUG by pretending
+ that the type was never defined, so we only get the members we
+ actually define. */
+ if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
+ return;
+
+ /* We might have set this earlier in cp_finish_decl. */
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 0;
+
+ /* If we already know how we're handling this class, handle debug info
+ the same way. */
+ if (CLASSTYPE_INTERFACE_ONLY (t))
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+ else if (CLASSTYPE_INTERFACE_KNOWN (t))
+ /* Don't set it. */;
+ /* If the class has virtual functions, write out the debug info
+ along with the vtable. */
+ else if (TYPE_POLYMORPHIC_P (t))
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+
+ /* Otherwise, just emit the debug info normally. */
}
-\f
+
+#if 0
+/* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". Currently, we only suppress debug
+ info if we can emit it with the vtable. jason 1999-11-11) */
+
/* If we want debug info for a type TYPE, make sure all its base types
are also marked as being potentially interesting. This avoids
the problem of not writing any debug info for intermediate basetypes
/* We can't go looking for the base types and fields just yet. */
return;
- /* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
- does not support name references between translation units. Well, we
- could, but that would mean putting global labels in the debug output
- before each exported type and each of its functions and static data
- members. */
- if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG
- || write_symbols == NO_DEBUG)
+ /* See the comment in maybe_suppress_debug_info. */
+ if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
return;
dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp, 0);
note_debug_info_needed (ttype);
}
}
+#endif
\f
/* Subroutines of push_class_decls (). */
push_class_decls (type)
tree type;
{
- struct obstack *ambient_obstack = current_obstack;
search_stack = push_search_level (search_stack, &search_obstack);
- /* Build up all the relevant bindings and such on the cache
- obstack. That way no memory is wasted when we throw away the
- cache later. */
- push_cache_obstack ();
-
/* Enter type declarations and mark. */
dfs_walk (TYPE_BINFO (type), dfs_push_type_decls, unmarked_pushdecls_p, 0);
/* Enter non-type declarations and unmark. */
dfs_walk (TYPE_BINFO (type), dfs_push_decls, marked_pushdecls_p, 0);
-
- /* Undo the call to push_cache_obstack above. */
- pop_obstacks ();
-
- current_obstack = ambient_obstack;
}
/* Here's a subroutine we need because C lacks lambdas. */
#endif /* GATHER_STATISTICS */
}
-#define scratch_tree_cons expr_tree_cons
-
static tree
add_conversions (binfo, data)
tree binfo;
/* Make sure we don't already have this conversion. */
if (! IDENTIFIER_MARKED (name))
{
- *conversions = scratch_tree_cons (binfo, tmp, *conversions);
+ *conversions = tree_cons (binfo, tmp, *conversions);
IDENTIFIER_MARKED (name) = 1;
}
}
return oi.found_overlap;
}
-struct bfv_info {
- tree vbases;
- tree var;
-};
-
-static tree
-dfs_bfv_queue_p (binfo, data)
- tree binfo;
- void *data;
-{
- struct bfv_info *bfvi = (struct bfv_info *) data;
-
- /* Use the real virtual base class objects, not the placeholders in
- the usual hierarchy. */
- if (TREE_VIA_VIRTUAL (binfo))
- return binfo_member (BINFO_TYPE (binfo), bfvi->vbases);
-
- return binfo;
-}
-
-/* Passed to dfs_walk_real by binfo_for_vtable; determine if bvtable
- comes from BINFO. */
+/* Given a vtable VAR, determine which binfo it comes from.
-static tree
-dfs_bfv_helper (binfo, data)
- tree binfo;
- void *data;
-{
- struct bfv_info *bfvi = (struct bfv_info *) data;
-
- if (BINFO_VTABLE (binfo) == bfvi->var)
- return binfo;
- return NULL_TREE;
-}
-
-/* Given a vtable VAR, determine which binfo it comes from. */
+ FIXME What about secondary vtables? */
tree
binfo_for_vtable (var)
tree var;
{
- tree type;
- struct bfv_info bfvi;
+ tree binfo = TYPE_BINFO (DECL_CONTEXT (var));
+ tree binfos;
+ int i;
- type = DECL_CONTEXT (var);
- bfvi.vbases = CLASSTYPE_VBASECLASSES (type);
- bfvi.var = var;
- return dfs_walk_real (TYPE_BINFO (type),
- 0, dfs_bfv_helper, dfs_bfv_queue_p, &bfvi);
+ while (1)
+ {
+ binfos = BINFO_BASETYPES (binfo);
+ if (binfos == NULL_TREE)
+ break;
+
+ i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ if (i == -1)
+ break;
+
+ binfo = TREE_VEC_ELT (binfos, i);
+ }
+
+ return binfo;
}
/* Returns 1 iff BINFO is from a direct or indirect virtual base. */